Skip to content

Commit d040800

Browse files
authored
Merge pull request #308 from opsmill/infrahub-develop
Release 1.8.0
2 parents cd7e689 + 15fe07d commit d040800

39 files changed

+2319
-331
lines changed

.github/workflows/ci.yml

Lines changed: 68 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ jobs:
7676
- name: "Check out repository code"
7777
uses: "actions/checkout@v4"
7878
- name: "Setup environment"
79-
run: "pip install ruff==0.8.6"
79+
run: "pip install ruff==0.11.0"
8080
- name: "Linting: ruff check"
8181
run: "ruff check ."
8282
- name: "Linting: ruff format"
@@ -212,6 +212,7 @@ jobs:
212212
- "3.10"
213213
- "3.11"
214214
- "3.12"
215+
- "3.13"
215216
if: |
216217
always() && !cancelled() &&
217218
!contains(needs.*.result, 'failure') &&
@@ -299,77 +300,79 @@ jobs:
299300
env:
300301
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
301302

302-
integration-tests-local-infrahub:
303-
if: |
304-
always() && !cancelled() &&
305-
!contains(needs.*.result, 'failure') &&
306-
!contains(needs.*.result, 'cancelled') &&
307-
needs.files-changed.outputs.python == 'true' &&
308-
(github.base_ref == 'stable' || github.base_ref == 'develop')
309-
needs: ["files-changed", "yaml-lint", "python-lint"]
310-
runs-on:
311-
group: "huge-runners"
312-
timeout-minutes: 30
313-
steps:
314-
- name: "Check out repository code"
315-
uses: "actions/checkout@v4"
303+
# NOTE: Disabling this test for now because it's expected that we can't start the latest version of infrahub
304+
# with the current shipping version of infrahub-testcontainers
305+
# integration-tests-local-infrahub:
306+
# if: |
307+
# always() && !cancelled() &&
308+
# !contains(needs.*.result, 'failure') &&
309+
# !contains(needs.*.result, 'cancelled') &&
310+
# needs.files-changed.outputs.python == 'true' &&
311+
# (github.base_ref == 'stable' || github.base_ref == 'develop')
312+
# needs: ["files-changed", "yaml-lint", "python-lint"]
313+
# runs-on:
314+
# group: "huge-runners"
315+
# timeout-minutes: 30
316+
# steps:
317+
# - name: "Check out repository code"
318+
# uses: "actions/checkout@v4"
316319

317-
- name: "Extract target branch name"
318-
id: extract_branch
319-
run: echo "TARGET_BRANCH=${{ github.base_ref }}" >> $GITHUB_ENV
320+
# - name: "Extract target branch name"
321+
# id: extract_branch
322+
# run: echo "TARGET_BRANCH=${{ github.base_ref }}" >> $GITHUB_ENV
320323

321-
- name: "Checkout infrahub repository"
322-
uses: "actions/checkout@v4"
323-
with:
324-
repository: "opsmill/infrahub"
325-
path: "infrahub-server"
326-
ref: ${{ github.base_ref }}
327-
submodules: true
324+
# - name: "Checkout infrahub repository"
325+
# uses: "actions/checkout@v4"
326+
# with:
327+
# repository: "opsmill/infrahub"
328+
# path: "infrahub-server"
329+
# ref: ${{ github.base_ref }}
330+
# submodules: true
328331

329-
- name: Set up Python
330-
uses: actions/setup-python@v5
331-
with:
332-
python-version: "3.12"
332+
# - name: Set up Python
333+
# uses: actions/setup-python@v5
334+
# with:
335+
# python-version: "3.12"
333336

334-
- name: "Setup git credentials prior dev.build"
335-
run: |
336-
cd infrahub-server
337-
git config --global user.name 'Infrahub'
338-
git config --global user.email '[email protected]'
339-
git config --global --add safe.directory '*'
340-
git config --global credential.usehttppath true
341-
git config --global credential.helper /usr/local/bin/infrahub-git-credential
337+
# - name: "Setup git credentials prior dev.build"
338+
# run: |
339+
# cd infrahub-server
340+
# git config --global user.name 'Infrahub'
341+
# git config --global user.email '[email protected]'
342+
# git config --global --add safe.directory '*'
343+
# git config --global credential.usehttppath true
344+
# git config --global credential.helper /usr/local/bin/infrahub-git-credential
342345

343-
- name: "Set environment variables prior dev.build"
344-
run: |
345-
echo "INFRAHUB_BUILD_NAME=infrahub-${{ runner.name }}" >> $GITHUB_ENV
346-
RUNNER_NAME=$(echo "${{ runner.name }}" | grep -o 'ghrunner[0-9]\+' | sed 's/ghrunner\([0-9]\+\)/ghrunner_\1/')
347-
echo "PYTEST_DEBUG_TEMPROOT=/var/lib/github/${RUNNER_NAME}/_temp" >> $GITHUB_ENV
348-
echo "INFRAHUB_IMAGE_VER=local-${{ runner.name }}-${{ github.sha }}" >> $GITHUB_ENV
349-
echo "INFRAHUB_TESTING_IMAGE_VER=local-${{ runner.name }}-${{ github.sha }}" >> $GITHUB_ENV
350-
echo "INFRAHUB_TESTING_DOCKER_IMAGE=opsmill/infrahub" >> $GITHUB_ENV
346+
# - name: "Set environment variables prior dev.build"
347+
# run: |
348+
# echo "INFRAHUB_BUILD_NAME=infrahub-${{ runner.name }}" >> $GITHUB_ENV
349+
# RUNNER_NAME=$(echo "${{ runner.name }}" | grep -o 'ghrunner[0-9]\+' | sed 's/ghrunner\([0-9]\+\)/ghrunner_\1/')
350+
# echo "PYTEST_DEBUG_TEMPROOT=/var/lib/github/${RUNNER_NAME}/_temp" >> $GITHUB_ENV
351+
# echo "INFRAHUB_IMAGE_VER=local-${{ runner.name }}-${{ github.sha }}" >> $GITHUB_ENV
352+
# echo "INFRAHUB_TESTING_IMAGE_VER=local-${{ runner.name }}-${{ github.sha }}" >> $GITHUB_ENV
353+
# echo "INFRAHUB_TESTING_DOCKER_IMAGE=opsmill/infrahub" >> $GITHUB_ENV
351354

352-
- name: "Build container"
353-
run: |
354-
cd infrahub-server
355-
inv dev.build
355+
# - name: "Build container"
356+
# run: |
357+
# cd infrahub-server
358+
# inv dev.build
356359

357-
- name: "Setup environment"
358-
run: |
359-
pipx install poetry==1.8.5
360-
poetry config virtualenvs.create true --local
361-
pip install invoke toml codecov
360+
# - name: "Setup environment"
361+
# run: |
362+
# pipx install poetry==1.8.5
363+
# poetry config virtualenvs.create true --local
364+
# pip install invoke toml codecov
362365

363-
- name: "Install Package"
364-
run: "poetry install --all-extras"
366+
# - name: "Install Package"
367+
# run: "poetry install --all-extras"
365368

366-
- name: "Integration Tests"
367-
run: |
368-
echo "Running tests for version: $INFRAHUB_TESTING_IMAGE_VER"
369-
poetry run pytest --cov infrahub_sdk tests/integration/
369+
# - name: "Integration Tests"
370+
# run: |
371+
# echo "Running tests for version: $INFRAHUB_TESTING_IMAGE_VER"
372+
# poetry run pytest --cov infrahub_sdk tests/integration/
370373

371-
- name: "Upload coverage to Codecov"
372-
run: |
373-
codecov --flags integration-tests
374-
env:
375-
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
374+
# - name: "Upload coverage to Codecov"
375+
# run: |
376+
# codecov --flags integration-tests
377+
# env:
378+
# CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,21 @@ This project uses [*towncrier*](https://towncrier.readthedocs.io/) and the chang
1111

1212
<!-- towncrier release notes start -->
1313

14+
## [1.8.0](https://github.com/opsmill/infrahub-sdk-python/tree/v1.8.0) - 2025-03-19
15+
16+
### Deprecated
17+
18+
- Timestamp: Direct access to `obj` and `add_delta` have been deprecated and will be removed in a future version. ([#255](https://github.com/opsmill/infrahub-sdk-python/issues/255))
19+
20+
### Added
21+
22+
- Added support for Enum in GraphQL query and mutation. ([#18](https://github.com/opsmill/infrahub-sdk-python/issues/18))
23+
24+
### Fixed
25+
26+
- Refactored Timestamp to use `whenever` instead of `pendulum` and extend Timestamp with `add()`, `subtract()`, and `to_datetime()`. ([#255](https://github.com/opsmill/infrahub-sdk-python/issues/255))
27+
- Fixed support for Python 3.13 as it's no longer required to have Rust installed on the system.
28+
1429
## [1.7.2](https://github.com/opsmill/infrahub-sdk-python/tree/v1.7.2) - 2025-03-07
1530

1631
### Added
@@ -26,6 +41,14 @@ This project uses [*towncrier*](https://towncrier.readthedocs.io/) and the chang
2641
### Fixed
2742

2843
- `protocols` CTL command properly gets default branch setting from environment variable. ([#104](https://github.com/opsmill/infrahub-sdk-python/issues/104))
44+
- Fix typing for Python 3.9 ([#251](https://github.com/opsmill/infrahub-sdk-python/issues/251))
45+
- Refactor Timestamp to use `whenever` instead of `pendulum` and extend Timestamp with add(), subtract(), and to_datetime(). ([#255](https://github.com/opsmill/infrahub-sdk-python/issues/255))
46+
- Remove default value "main" for branch parameter from all Infrahub CTL commands. ([#264](https://github.com/opsmill/infrahub-sdk-python/issues/264))
47+
- Fixed support for Python 3.13, it's no longer required to have Rust installed on the system.
48+
49+
### Housekeeping
50+
51+
- Move the function `read_file` from the ctl module to the SDK.
2952
- Fixed typing for Python 3.9 and removed support for Python 3.13. ([#251](https://github.com/opsmill/infrahub-sdk-python/issues/251))
3053
- Removed default value "main" for branch parameter from all Infrahub CTL commands. ([#264](https://github.com/opsmill/infrahub-sdk-python/issues/264))
3154

infrahub_sdk/client.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,16 @@
5252
from .query_groups import InfrahubGroupContext, InfrahubGroupContextSync
5353
from .schema import InfrahubSchema, InfrahubSchemaSync, NodeSchemaAPI
5454
from .store import NodeStore, NodeStoreSync
55+
from .task.manager import InfrahubTaskManager, InfrahubTaskManagerSync
5556
from .timestamp import Timestamp
5657
from .types import AsyncRequester, HTTPMethod, Order, SyncRequester
5758
from .utils import decode_json, get_user_permissions, is_valid_uuid
5859

5960
if TYPE_CHECKING:
6061
from types import TracebackType
6162

63+
from .context import RequestContext
64+
6265

6366
SchemaType = TypeVar("SchemaType", bound=CoreNode)
6467
SchemaTypeSync = TypeVar("SchemaTypeSync", bound=CoreNodeSync)
@@ -140,6 +143,7 @@ def __init__(
140143
self.identifier = self.config.identifier
141144
self.group_context: InfrahubGroupContext | InfrahubGroupContextSync
142145
self._initialize()
146+
self._request_context: RequestContext | None = None
143147

144148
def _initialize(self) -> None:
145149
"""Sets the properties for each version of the client"""
@@ -154,6 +158,14 @@ def _echo(self, url: str, query: str, variables: dict | None = None) -> None:
154158
if variables:
155159
print(f"VARIABLES:\n{ujson.dumps(variables, indent=4)}\n")
156160

161+
@property
162+
def request_context(self) -> RequestContext | None:
163+
return self._request_context
164+
165+
@request_context.setter
166+
def request_context(self, request_context: RequestContext) -> None:
167+
self._request_context = request_context
168+
157169
def start_tracking(
158170
self,
159171
identifier: str | None = None,
@@ -270,6 +282,7 @@ def _initialize(self) -> None:
270282
self.branch = InfrahubBranchManager(self)
271283
self.object_store = ObjectStore(self)
272284
self.store = NodeStore()
285+
self.task = InfrahubTaskManager(self)
273286
self.concurrent_execution_limit = asyncio.Semaphore(self.max_concurrent_execution)
274287
self._request_method: AsyncRequester = self.config.requester or self._default_request_method
275288
self.group_context = InfrahubGroupContext(self)
@@ -1505,13 +1518,19 @@ async def __aexit__(
15051518

15061519

15071520
class InfrahubClientSync(BaseClient):
1521+
schema: InfrahubSchemaSync
1522+
branch: InfrahubBranchManagerSync
1523+
object_store: ObjectStoreSync
1524+
store: NodeStoreSync
1525+
task: InfrahubTaskManagerSync
15081526
group_context: InfrahubGroupContextSync
15091527

15101528
def _initialize(self) -> None:
15111529
self.schema = InfrahubSchemaSync(self)
15121530
self.branch = InfrahubBranchManagerSync(self)
15131531
self.object_store = ObjectStoreSync(self)
15141532
self.store = NodeStoreSync()
1533+
self.task = InfrahubTaskManagerSync(self)
15151534
self._request_method: SyncRequester = self.config.sync_requester or self._default_request_method
15161535
self.group_context = InfrahubGroupContextSync(self)
15171536

infrahub_sdk/context.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from __future__ import annotations
2+
3+
from pydantic import BaseModel, Field
4+
5+
6+
class ContextAccount(BaseModel):
7+
id: str = Field(..., description="The ID of the account")
8+
9+
10+
class RequestContext(BaseModel):
11+
"""The context can be used to override settings such as the account within mutations."""
12+
13+
account: ContextAccount | None = Field(default=None, description="Account tied to the context")

infrahub_sdk/ctl/branch.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
from rich.table import Table
66

77
from ..async_typer import AsyncTyper
8-
from ..ctl.client import initialize_client
9-
from ..ctl.utils import calculate_time_diff, catch_exception
8+
from ..utils import calculate_time_diff
9+
from .client import initialize_client
1010
from .parameters import CONFIG_PARAM
11+
from .utils import catch_exception
1112

1213
app = AsyncTyper()
1314
console = Console()

infrahub_sdk/ctl/utils.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,9 @@
88
from pathlib import Path
99
from typing import TYPE_CHECKING, Any, Callable, NoReturn, Optional, TypeVar
1010

11-
import pendulum
1211
import typer
1312
from click.exceptions import Exit
1413
from httpx import HTTPError
15-
from pendulum.datetime import DateTime
1614
from rich.console import Console
1715
from rich.logging import RichHandler
1816
from rich.markup import escape
@@ -152,20 +150,6 @@ def parse_cli_vars(variables: Optional[list[str]]) -> dict[str, str]:
152150
return {var.split("=")[0]: var.split("=")[1] for var in variables if "=" in var}
153151

154152

155-
def calculate_time_diff(value: str) -> str | None:
156-
"""Calculate the time in human format between a timedate in string format and now."""
157-
try:
158-
time_value = pendulum.parse(value)
159-
except pendulum.parsing.exceptions.ParserError:
160-
return None
161-
162-
if not isinstance(time_value, DateTime):
163-
return None
164-
165-
pendulum.set_locale("en")
166-
return time_value.diff_for_humans(other=pendulum.now(), absolute=True)
167-
168-
169153
def find_graphql_query(name: str, directory: str | Path = ".") -> str:
170154
if isinstance(directory, str):
171155
directory = Path(directory)

infrahub_sdk/exceptions.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,9 @@ class FileNotValidError(Error):
143143
def __init__(self, name: str, message: str = ""):
144144
self.message = message or f"Cannot parse '{name}' content."
145145
super().__init__(self.message)
146+
147+
148+
class TimestampFormatError(Error):
149+
def __init__(self, message: str | None = None):
150+
self.message = message or "Invalid timestamp format"
151+
super().__init__(self.message)

infrahub_sdk/generator.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
if TYPE_CHECKING:
1313
from .client import InfrahubClient
14+
from .context import RequestContext
1415
from .node import InfrahubNode
1516
from .store import NodeStore
1617

@@ -29,6 +30,7 @@ def __init__(
2930
params: dict | None = None,
3031
convert_query_response: bool = False,
3132
logger: logging.Logger | None = None,
33+
request_context: RequestContext | None = None,
3234
) -> None:
3335
self.query = query
3436
self.branch = branch
@@ -44,6 +46,7 @@ def __init__(
4446
self.infrahub_node = infrahub_node
4547
self.convert_query_response = convert_query_response
4648
self.logger = logger if logger else logging.getLogger("infrahub.tasks")
49+
self.request_context = request_context
4750

4851
@property
4952
def store(self) -> NodeStore:

0 commit comments

Comments
 (0)