Skip to content

Commit 4f8997e

Browse files
committed
merge stable and refresh
2 parents 174e8ec + b904ad5 commit 4f8997e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+2880
-1169
lines changed

.github/workflows/ci.yml

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ env:
2929
METRICS_ENDPOINT: ${{ secrets.METRICS_ENDPOINT }}
3030

3131
jobs:
32-
# ------------------------------------------ Check Files Changes ------------------------------------------
32+
prepare-environment:
33+
uses: ./.github/workflows/define-versions.yml
34+
# ------------------------------------------ Check Files Changes ------------------------------------------
3335
files-changed:
3436
name: Detect which file has changed
3537
runs-on: ubuntu-latest
@@ -84,15 +86,17 @@ jobs:
8486

8587

8688
markdown-lint:
87-
if: needs.files-changed.outputs.documentation == 'true'
89+
if: |
90+
needs.files-changed.outputs.documentation == 'true' ||
91+
needs.files-changed.outputs.github_workflows == 'true'
8892
needs: ["files-changed"]
8993
runs-on: "ubuntu-latest"
9094
timeout-minutes: 5
9195
steps:
9296
- name: "Check out repository code"
9397
uses: "actions/checkout@v4"
9498
- name: "Linting: markdownlint"
95-
uses: DavidAnson/markdownlint-cli2-action@v19
99+
uses: DavidAnson/markdownlint-cli2-action@v20
96100
with:
97101
config: .markdownlint.yaml
98102
globs: |
@@ -152,7 +156,7 @@ jobs:
152156
!contains(needs.*.result, 'failure') &&
153157
!contains(needs.*.result, 'cancelled') &&
154158
(needs.files-changed.outputs.python == 'true') || (needs.files-changed.outputs.documentation_generated == 'true')
155-
needs: ["files-changed", "yaml-lint", "python-lint"]
159+
needs: ["prepare-environment", "files-changed", "yaml-lint", "python-lint"]
156160
runs-on: "ubuntu-22.04"
157161
timeout-minutes: 5
158162
steps:
@@ -166,7 +170,7 @@ jobs:
166170
python-version: "3.12"
167171
- name: "Setup Python environment"
168172
run: |
169-
pipx install poetry==2.1
173+
pipx install poetry==${{ needs.prepare-environment.outputs.POETRY_VERSION }}
170174
poetry config virtualenvs.create true --local
171175
poetry env use 3.12
172176
- name: "Install dependencies"
@@ -218,7 +222,7 @@ jobs:
218222
!contains(needs.*.result, 'failure') &&
219223
!contains(needs.*.result, 'cancelled') &&
220224
needs.files-changed.outputs.python == 'true'
221-
needs: ["files-changed", "yaml-lint", "python-lint"]
225+
needs: ["prepare-environment", "files-changed", "yaml-lint", "python-lint"]
222226
runs-on: ubuntu-latest
223227
timeout-minutes: 30
224228
steps:
@@ -230,7 +234,7 @@ jobs:
230234
python-version: ${{ matrix.python-version }}
231235
- name: "Setup environment"
232236
run: |
233-
pipx install poetry==2.1 --python python${{ matrix.python-version }}
237+
pipx install poetry==${{ needs.prepare-environment.outputs.POETRY_VERSION }} --python python${{ matrix.python-version }}
234238
poetry config virtualenvs.create true --local
235239
pip install invoke toml codecov
236240
- name: "Install Package"
@@ -266,7 +270,7 @@ jobs:
266270
!contains(needs.*.result, 'failure') &&
267271
!contains(needs.*.result, 'cancelled') &&
268272
needs.files-changed.outputs.python == 'true'
269-
needs: ["files-changed", "yaml-lint", "python-lint"]
273+
needs: ["prepare-environment", "files-changed", "yaml-lint", "python-lint"]
270274
runs-on:
271275
group: "huge-runners"
272276
timeout-minutes: 30
@@ -283,7 +287,7 @@ jobs:
283287
echo "PYTEST_DEBUG_TEMPROOT=/var/lib/github/${RUNNER_NAME}/_temp" >> $GITHUB_ENV
284288
- name: "Setup environment"
285289
run: |
286-
pipx install poetry==2.1
290+
pipx install poetry==${{ needs.prepare-environment.outputs.POETRY_VERSION }}
287291
poetry config virtualenvs.create true --local
288292
pip install invoke toml codecov
289293
- name: "Install Package"
@@ -306,7 +310,7 @@ jobs:
306310
# !contains(needs.*.result, 'cancelled') &&
307311
# needs.files-changed.outputs.python == 'true' &&
308312
# (github.base_ref == 'stable' || github.base_ref == 'develop')
309-
# needs: ["files-changed", "yaml-lint", "python-lint"]
313+
# needs: ["prepare-environment", "files-changed", "yaml-lint", "python-lint"]
310314
# runs-on:
311315
# group: "huge-runners"
312316
# timeout-minutes: 30
@@ -356,7 +360,7 @@ jobs:
356360

357361
# - name: "Setup environment"
358362
# run: |
359-
# pipx install poetry==2.1
363+
# pipx install poetry==${{ needs.prepare-environment.outputs.POETRY_VERSION }}
360364
# poetry config virtualenvs.create true --local
361365
# pip install invoke toml codecov
362366

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
# yamllint disable rule:truthy rule:truthy rule:line-length
3+
name: "Define versions"
4+
on:
5+
workflow_call:
6+
outputs:
7+
POETRY_VERSION:
8+
value: "2.1.3"
9+
10+
jobs:
11+
prepare:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- run: "true"

.github/workflows/publish-pypi.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,12 @@ on:
2929
default: false
3030

3131
jobs:
32+
prepare-environment:
33+
uses: ./.github/workflows/define-versions.yml
3234
publish_to_pypi:
3335
name: "Publish Infrahub SDK to PyPI"
3436
runs-on: "ubuntu-22.04"
37+
needs: prepare-environment
3538
steps:
3639
- name: "Set up Python"
3740
uses: "actions/setup-python@v5"
@@ -41,7 +44,7 @@ jobs:
4144
- name: "Install Poetry"
4245
uses: "snok/install-poetry@v1"
4346
with:
44-
version: 1.8.5
47+
version: ${{ needs.prepare-environment.outputs.POETRY_VERSION }}
4548
virtualenvs-create: true
4649
virtualenvs-in-project: true
4750
installer-parallel: true

.github/workflows/release.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ on:
88
- published
99

1010
jobs:
11+
prepare-environment:
12+
uses: ./.github/workflows/define-versions.yml
1113
check_release:
1214
runs-on: ubuntu-22.04
15+
needs: prepare-environment
1316
outputs:
1417
is_prerelease: ${{ steps.release.outputs.is_prerelease }}
1518
is_devrelease: ${{ steps.release.outputs.is_devrelease }}
@@ -30,7 +33,7 @@ jobs:
3033
- name: "Install Poetry"
3134
uses: "snok/install-poetry@v1"
3235
with:
33-
version: 1.8.5
36+
version: ${{ needs.prepare-environment.outputs.POETRY_VERSION }}
3437
virtualenvs-create: true
3538
virtualenvs-in-project: true
3639
installer-parallel: true

.markdownlint.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ MD034: false # no-bare-urls
1111
MD041: false # allow 1st line to not be a top-level heading (required for Towncrier)
1212
MD045: false # no alt text around images
1313
MD047: false # single trailing newline
14+
MD059: # Link descriptions that are prohibited
15+
prohibited_texts: []

CHANGELOG.md

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

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

14+
## [1.13.2](https://github.com/opsmill/infrahub-sdk-python/tree/v1.13.2) - 2025-06-27
15+
16+
### Fixed
17+
18+
- Re-enable specifying a cardinality-one relationship using a RelatedNode when creating an InfrahubNode ([#452](https://github.com/opsmill/infrahub-sdk-python/issues/452))
19+
20+
## [1.13.1](https://github.com/opsmill/infrahub-sdk-python/tree/v1.13.1) - 2025-06-19
21+
22+
### Fixed
23+
24+
- Fix the import path of the Attribute class [#448](https://github.com/opsmill/infrahub-sdk-python/pull/448)
25+
26+
## [1.13.0](https://github.com/opsmill/infrahub-sdk-python/tree/v1.13.0) - 2025-06-11
27+
28+
This release adds support for the new NumberPool attribute and loading object and menu files from external repositories in Infrahub 1.3.
29+
30+
### Added
31+
32+
- Added NumberPool as a new attribute kind, for support in Infrahub 1.3
33+
- Added support for object and menu files in the `.infrahub` repository configuration file
34+
- Defined ordering in which object files are loaded
35+
36+
### Housekeeping
37+
38+
- Refactor InfrahubNode to avoid the creation of a dynamic Python class for each object defined
39+
40+
## [1.12.3](https://github.com/opsmill/infrahub-sdk-python/tree/v1.12.3) - 2025-06-10
41+
42+
## Fixed
43+
44+
- fix Python transforms tests in the resource testing framework by @ogenstad in https://github.com/opsmill/infrahub-sdk-python/pull/433
45+
- add unit test for Python transforms test for the resource testing framework @wvandeun in https://github.com/opsmill/infrahub-sdk-python/pull/435
46+
47+
### Changed
48+
49+
- loosen requirement for the optional Rich dependency from v12.0.0 up to but not including v14.0.0 by @wvandeun in https://github.com/opsmill/infrahub-sdk-python/pull/434
50+
51+
## [1.12.2](https://github.com/opsmill/infrahub-sdk-python/tree/v1.12.2) - 2025-06-05
52+
53+
### Fixed
54+
55+
- fix bug in Timestamp.add by @ajtmccarty in [#403](https://github.com/opsmill/infrahub-sdk-python/pull/403)
56+
- utils.py: improve file not found exception message by @granoe668 in [#425](https://github.com/opsmill/infrahub-sdk-python/pull/425)
57+
58+
### Changed
59+
60+
- Add partial_match to the client.count() by @BeArchiTek in [#411](https://github.com/opsmill/infrahub-sdk-python/pull/411)
61+
62+
### Housekeeping
63+
64+
- Loosen pinned requirement for `whenever` to allow versions from 0.7.2 up to but not including 0.8.0.
65+
- Bump http-proxy-middleware from 2.0.7 to 2.0.9 in /docs by @dependabot in [#418](https://github.com/opsmill/infrahub-sdk-python/pull/418)
66+
1467
## [1.12.1](https://github.com/opsmill/infrahub-sdk-python/tree/v1.12.1) - 2025-05-12
1568

1669
### Changed

docs/docs/python-sdk/introduction.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ The Infrahub Python SDK greatly simplifies how you can interact with Infrahub pr
77
## Blog posts
88

99
- [Querying Data in Infrahub via the Python SDK](https://www.opsmill.com/querying-data-in-infrahub-via-the-python-sdk/)
10+
- [Creating, Modifying, and Deleting Data in Infrahub Using the Python SDK](https://www.opsmill.com/infrahub-python-sdk-create-modify-delete/)
1011

1112
## Guides
1213

docs/docs/python-sdk/topics/object_file.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ Multiple object files can be loaded at once by specifying the path to multiple f
3838
The `object load` command will create/update the objects using an `Upsert` operation. All objects previously loaded will NOT be deleted in the Infrahub instance.
3939
Also, if some objects present in different files are identical and dependent on each other, the `object load` command will NOT calculate the dependencies between the objects and as such it's the responsibility of the users to execute the command in the right order.
4040

41+
> Object files can also be loaded into Infrahub when using external Git repositories. To see how to do this, please refer to the [.infrahub.yml](https://docs.infrahub.app/topics/infrahub-yml#objects) documentation.
42+
4143
### Validate the format of object files
4244

4345
The object file can be validated using the `infrahubctl object validate` command.

docs/package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

infrahub_sdk/client.py

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -172,11 +172,18 @@ def start_tracking(
172172
params: dict[str, Any] | None = None,
173173
delete_unused_nodes: bool = False,
174174
group_type: str | None = None,
175+
group_params: dict[str, Any] | None = None,
176+
branch: str | None = None,
175177
) -> Self:
176178
self.mode = InfrahubClientMode.TRACKING
177179
identifier = identifier or self.identifier or "python-sdk"
178180
self.set_context_properties(
179-
identifier=identifier, params=params, delete_unused_nodes=delete_unused_nodes, group_type=group_type
181+
identifier=identifier,
182+
params=params,
183+
delete_unused_nodes=delete_unused_nodes,
184+
group_type=group_type,
185+
group_params=group_params,
186+
branch=branch,
180187
)
181188
return self
182189

@@ -187,14 +194,22 @@ def set_context_properties(
187194
delete_unused_nodes: bool = True,
188195
reset: bool = True,
189196
group_type: str | None = None,
197+
group_params: dict[str, Any] | None = None,
198+
branch: str | None = None,
190199
) -> None:
191200
if reset:
192201
if isinstance(self, InfrahubClient):
193202
self.group_context = InfrahubGroupContext(self)
194203
elif isinstance(self, InfrahubClientSync):
195204
self.group_context = InfrahubGroupContextSync(self)
205+
196206
self.group_context.set_properties(
197-
identifier=identifier, params=params, delete_unused_nodes=delete_unused_nodes, group_type=group_type
207+
identifier=identifier,
208+
params=params,
209+
delete_unused_nodes=delete_unused_nodes,
210+
group_type=group_type,
211+
group_params=group_params,
212+
branch=branch,
198213
)
199214

200215
def _graphql_url(
@@ -562,18 +577,27 @@ async def count(
562577
at: Timestamp | None = None,
563578
branch: str | None = None,
564579
timeout: int | None = None,
580+
partial_match: bool = False,
565581
**kwargs: Any,
566582
) -> int:
567583
"""Return the number of nodes of a given kind."""
568-
filters = kwargs
569-
schema = await self.schema.get(kind=kind, branch=branch)
584+
filters: dict[str, Any] = dict(kwargs)
570585

586+
if partial_match:
587+
filters["partial_match"] = True
588+
589+
schema = await self.schema.get(kind=kind, branch=branch)
571590
branch = branch or self.default_branch
572591
if at:
573592
at = Timestamp(at)
574593

594+
data: dict[str, Any] = {
595+
"count": None,
596+
"@filters": filters,
597+
}
598+
575599
response = await self.execute_graphql(
576-
query=Query(query={schema.kind: {"count": None, "@filters": filters}}).render(),
600+
query=Query(query={schema.kind: data}).render(),
577601
branch_name=branch,
578602
at=at,
579603
timeout=timeout,
@@ -801,7 +825,7 @@ async def process_batch() -> tuple[list[InfrahubNode], list[InfrahubNode]]:
801825
nodes = []
802826
related_nodes = []
803827
batch_process = await self.create_batch()
804-
count = await self.count(kind=schema.kind, **filters)
828+
count = await self.count(kind=schema.kind, partial_match=partial_match, **filters)
805829
total_pages = (count + pagination_size - 1) // pagination_size
806830

807831
for page_number in range(1, total_pages + 1):
@@ -1683,18 +1707,27 @@ def count(
16831707
at: Timestamp | None = None,
16841708
branch: str | None = None,
16851709
timeout: int | None = None,
1710+
partial_match: bool = False,
16861711
**kwargs: Any,
16871712
) -> int:
16881713
"""Return the number of nodes of a given kind."""
1689-
filters = kwargs
1690-
schema = self.schema.get(kind=kind, branch=branch)
1714+
filters: dict[str, Any] = dict(kwargs)
1715+
1716+
if partial_match:
1717+
filters["partial_match"] = True
16911718

1719+
schema = self.schema.get(kind=kind, branch=branch)
16921720
branch = branch or self.default_branch
16931721
if at:
16941722
at = Timestamp(at)
16951723

1724+
data: dict[str, Any] = {
1725+
"count": None,
1726+
"@filters": filters,
1727+
}
1728+
16961729
response = self.execute_graphql(
1697-
query=Query(query={schema.kind: {"count": None, "@filters": filters}}).render(),
1730+
query=Query(query={schema.kind: data}).render(),
16981731
branch_name=branch,
16991732
at=at,
17001733
timeout=timeout,
@@ -1957,7 +1990,7 @@ def process_batch() -> tuple[list[InfrahubNodeSync], list[InfrahubNodeSync]]:
19571990
related_nodes = []
19581991
batch_process = self.create_batch()
19591992

1960-
count = self.count(kind=schema.kind, **filters)
1993+
count = self.count(kind=schema.kind, partial_match=partial_match, **filters)
19611994
total_pages = (count + pagination_size - 1) // pagination_size
19621995

19631996
for page_number in range(1, total_pages + 1):

0 commit comments

Comments
 (0)