infrahub-server 1.2.0b1__py3-none-any.whl → 1.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (297) hide show
  1. infrahub/api/dependencies.py +6 -6
  2. infrahub/api/diff/validation_models.py +7 -7
  3. infrahub/api/schema.py +1 -1
  4. infrahub/artifacts/models.py +1 -3
  5. infrahub/artifacts/tasks.py +1 -3
  6. infrahub/cli/__init__.py +13 -9
  7. infrahub/cli/constants.py +3 -0
  8. infrahub/cli/db.py +165 -183
  9. infrahub/cli/upgrade.py +146 -0
  10. infrahub/computed_attribute/gather.py +185 -0
  11. infrahub/computed_attribute/models.py +239 -11
  12. infrahub/computed_attribute/tasks.py +77 -442
  13. infrahub/computed_attribute/triggers.py +11 -45
  14. infrahub/config.py +43 -32
  15. infrahub/context.py +14 -0
  16. infrahub/core/account.py +4 -4
  17. infrahub/core/attribute.py +57 -57
  18. infrahub/core/branch/tasks.py +12 -9
  19. infrahub/core/changelog/diff.py +16 -8
  20. infrahub/core/changelog/models.py +189 -26
  21. infrahub/core/constants/__init__.py +5 -1
  22. infrahub/core/constants/infrahubkind.py +2 -0
  23. infrahub/core/constraint/node/runner.py +9 -8
  24. infrahub/core/diff/branch_differ.py +10 -10
  25. infrahub/core/diff/ipam_diff_parser.py +4 -5
  26. infrahub/core/diff/model/diff.py +27 -27
  27. infrahub/core/diff/model/path.py +3 -3
  28. infrahub/core/diff/query/merge.py +20 -17
  29. infrahub/core/diff/query_parser.py +4 -4
  30. infrahub/core/graph/__init__.py +1 -1
  31. infrahub/core/initialization.py +1 -10
  32. infrahub/core/ipam/constants.py +3 -4
  33. infrahub/core/ipam/reconciler.py +12 -12
  34. infrahub/core/ipam/utilization.py +10 -13
  35. infrahub/core/manager.py +34 -34
  36. infrahub/core/merge.py +7 -7
  37. infrahub/core/migrations/__init__.py +2 -3
  38. infrahub/core/migrations/graph/__init__.py +9 -4
  39. infrahub/core/migrations/graph/m017_add_core_profile.py +1 -5
  40. infrahub/core/migrations/graph/m018_uniqueness_nulls.py +4 -4
  41. infrahub/core/migrations/graph/m020_duplicate_edges.py +160 -0
  42. infrahub/core/migrations/graph/m021_missing_hierarchy_merge.py +51 -0
  43. infrahub/core/migrations/graph/{m020_add_generate_template_attr.py → m022_add_generate_template_attr.py} +3 -3
  44. infrahub/core/migrations/graph/m023_deduplicate_cardinality_one_relationships.py +96 -0
  45. infrahub/core/migrations/query/attribute_add.py +2 -2
  46. infrahub/core/migrations/query/node_duplicate.py +18 -21
  47. infrahub/core/migrations/query/schema_attribute_update.py +2 -2
  48. infrahub/core/migrations/schema/models.py +19 -4
  49. infrahub/core/migrations/schema/tasks.py +2 -2
  50. infrahub/core/migrations/shared.py +16 -16
  51. infrahub/core/models.py +15 -6
  52. infrahub/core/node/__init__.py +29 -28
  53. infrahub/core/node/base.py +2 -4
  54. infrahub/core/node/constraints/attribute_uniqueness.py +2 -2
  55. infrahub/core/node/constraints/grouped_uniqueness.py +99 -47
  56. infrahub/core/node/constraints/interface.py +1 -2
  57. infrahub/core/node/delete_validator.py +3 -5
  58. infrahub/core/node/ipam.py +4 -4
  59. infrahub/core/node/permissions.py +7 -7
  60. infrahub/core/node/resource_manager/ip_address_pool.py +6 -6
  61. infrahub/core/node/resource_manager/ip_prefix_pool.py +6 -6
  62. infrahub/core/node/resource_manager/number_pool.py +3 -3
  63. infrahub/core/path.py +12 -12
  64. infrahub/core/property.py +11 -11
  65. infrahub/core/protocols.py +5 -0
  66. infrahub/core/protocols_base.py +21 -21
  67. infrahub/core/query/__init__.py +33 -33
  68. infrahub/core/query/attribute.py +6 -4
  69. infrahub/core/query/diff.py +3 -3
  70. infrahub/core/query/node.py +82 -32
  71. infrahub/core/query/relationship.py +24 -24
  72. infrahub/core/query/resource_manager.py +2 -0
  73. infrahub/core/query/standard_node.py +3 -3
  74. infrahub/core/query/subquery.py +9 -9
  75. infrahub/core/registry.py +13 -15
  76. infrahub/core/relationship/constraints/count.py +3 -4
  77. infrahub/core/relationship/constraints/peer_kind.py +3 -4
  78. infrahub/core/relationship/constraints/profiles_kind.py +2 -2
  79. infrahub/core/relationship/model.py +40 -46
  80. infrahub/core/schema/attribute_schema.py +9 -9
  81. infrahub/core/schema/basenode_schema.py +93 -44
  82. infrahub/core/schema/computed_attribute.py +3 -3
  83. infrahub/core/schema/definitions/core/__init__.py +13 -19
  84. infrahub/core/schema/definitions/core/account.py +151 -148
  85. infrahub/core/schema/definitions/core/artifact.py +122 -113
  86. infrahub/core/schema/definitions/core/builtin.py +19 -16
  87. infrahub/core/schema/definitions/core/check.py +61 -53
  88. infrahub/core/schema/definitions/core/core.py +17 -0
  89. infrahub/core/schema/definitions/core/generator.py +89 -85
  90. infrahub/core/schema/definitions/core/graphql_query.py +72 -70
  91. infrahub/core/schema/definitions/core/group.py +96 -93
  92. infrahub/core/schema/definitions/core/ipam.py +176 -235
  93. infrahub/core/schema/definitions/core/lineage.py +18 -16
  94. infrahub/core/schema/definitions/core/menu.py +42 -40
  95. infrahub/core/schema/definitions/core/permission.py +144 -142
  96. infrahub/core/schema/definitions/core/profile.py +16 -27
  97. infrahub/core/schema/definitions/core/propose_change.py +88 -79
  98. infrahub/core/schema/definitions/core/propose_change_comment.py +170 -165
  99. infrahub/core/schema/definitions/core/propose_change_validator.py +290 -288
  100. infrahub/core/schema/definitions/core/repository.py +231 -225
  101. infrahub/core/schema/definitions/core/resource_pool.py +156 -166
  102. infrahub/core/schema/definitions/core/template.py +27 -12
  103. infrahub/core/schema/definitions/core/transform.py +85 -76
  104. infrahub/core/schema/definitions/core/webhook.py +127 -101
  105. infrahub/core/schema/definitions/internal.py +16 -16
  106. infrahub/core/schema/dropdown.py +3 -4
  107. infrahub/core/schema/generated/attribute_schema.py +15 -18
  108. infrahub/core/schema/generated/base_node_schema.py +12 -14
  109. infrahub/core/schema/generated/node_schema.py +3 -5
  110. infrahub/core/schema/generated/relationship_schema.py +9 -11
  111. infrahub/core/schema/generic_schema.py +2 -2
  112. infrahub/core/schema/manager.py +20 -9
  113. infrahub/core/schema/node_schema.py +4 -2
  114. infrahub/core/schema/relationship_schema.py +7 -7
  115. infrahub/core/schema/schema_branch.py +276 -138
  116. infrahub/core/schema/schema_branch_computed.py +41 -4
  117. infrahub/core/task/task.py +3 -3
  118. infrahub/core/task/user_task.py +15 -15
  119. infrahub/core/utils.py +20 -18
  120. infrahub/core/validators/__init__.py +1 -3
  121. infrahub/core/validators/aggregated_checker.py +2 -2
  122. infrahub/core/validators/attribute/choices.py +2 -2
  123. infrahub/core/validators/attribute/enum.py +2 -2
  124. infrahub/core/validators/attribute/kind.py +2 -2
  125. infrahub/core/validators/attribute/length.py +2 -2
  126. infrahub/core/validators/attribute/optional.py +2 -2
  127. infrahub/core/validators/attribute/regex.py +2 -2
  128. infrahub/core/validators/attribute/unique.py +2 -2
  129. infrahub/core/validators/checks_runner.py +25 -2
  130. infrahub/core/validators/determiner.py +1 -3
  131. infrahub/core/validators/interface.py +6 -2
  132. infrahub/core/validators/model.py +22 -3
  133. infrahub/core/validators/models/validate_migration.py +17 -4
  134. infrahub/core/validators/node/attribute.py +2 -2
  135. infrahub/core/validators/node/generate_profile.py +2 -2
  136. infrahub/core/validators/node/hierarchy.py +3 -5
  137. infrahub/core/validators/node/inherit_from.py +27 -5
  138. infrahub/core/validators/node/relationship.py +2 -2
  139. infrahub/core/validators/relationship/count.py +4 -4
  140. infrahub/core/validators/relationship/optional.py +2 -2
  141. infrahub/core/validators/relationship/peer.py +2 -2
  142. infrahub/core/validators/shared.py +2 -2
  143. infrahub/core/validators/tasks.py +8 -0
  144. infrahub/core/validators/uniqueness/checker.py +22 -21
  145. infrahub/core/validators/uniqueness/index.py +2 -2
  146. infrahub/core/validators/uniqueness/model.py +11 -11
  147. infrahub/database/__init__.py +26 -22
  148. infrahub/database/metrics.py +7 -1
  149. infrahub/dependencies/builder/constraint/grouped/node_runner.py +1 -3
  150. infrahub/dependencies/component/registry.py +2 -2
  151. infrahub/events/__init__.py +25 -2
  152. infrahub/events/artifact_action.py +13 -25
  153. infrahub/events/branch_action.py +26 -18
  154. infrahub/events/generator.py +71 -0
  155. infrahub/events/group_action.py +10 -24
  156. infrahub/events/models.py +10 -16
  157. infrahub/events/node_action.py +87 -32
  158. infrahub/events/repository_action.py +5 -18
  159. infrahub/events/schema_action.py +4 -9
  160. infrahub/events/utils.py +16 -0
  161. infrahub/events/validator_action.py +55 -0
  162. infrahub/exceptions.py +23 -24
  163. infrahub/generators/models.py +1 -3
  164. infrahub/git/base.py +7 -7
  165. infrahub/git/integrator.py +26 -25
  166. infrahub/git/models.py +22 -9
  167. infrahub/git/repository.py +3 -3
  168. infrahub/git/tasks.py +67 -49
  169. infrahub/git/utils.py +48 -0
  170. infrahub/git/worktree.py +1 -2
  171. infrahub/git_credential/askpass.py +1 -2
  172. infrahub/graphql/analyzer.py +12 -0
  173. infrahub/graphql/app.py +13 -15
  174. infrahub/graphql/context.py +6 -0
  175. infrahub/graphql/initialization.py +3 -0
  176. infrahub/graphql/loaders/node.py +2 -12
  177. infrahub/graphql/loaders/peers.py +77 -0
  178. infrahub/graphql/loaders/shared.py +13 -0
  179. infrahub/graphql/manager.py +13 -10
  180. infrahub/graphql/mutations/artifact_definition.py +5 -5
  181. infrahub/graphql/mutations/computed_attribute.py +4 -5
  182. infrahub/graphql/mutations/graphql_query.py +5 -5
  183. infrahub/graphql/mutations/ipam.py +50 -70
  184. infrahub/graphql/mutations/main.py +164 -141
  185. infrahub/graphql/mutations/menu.py +5 -5
  186. infrahub/graphql/mutations/models.py +2 -4
  187. infrahub/graphql/mutations/node_getter/by_default_filter.py +10 -10
  188. infrahub/graphql/mutations/node_getter/by_hfid.py +1 -3
  189. infrahub/graphql/mutations/node_getter/by_id.py +1 -3
  190. infrahub/graphql/mutations/node_getter/interface.py +1 -2
  191. infrahub/graphql/mutations/proposed_change.py +7 -7
  192. infrahub/graphql/mutations/relationship.py +67 -35
  193. infrahub/graphql/mutations/repository.py +8 -8
  194. infrahub/graphql/mutations/resource_manager.py +3 -3
  195. infrahub/graphql/mutations/schema.py +4 -4
  196. infrahub/graphql/mutations/webhook.py +137 -0
  197. infrahub/graphql/parser.py +4 -4
  198. infrahub/graphql/queries/diff/tree.py +4 -4
  199. infrahub/graphql/queries/ipam.py +2 -2
  200. infrahub/graphql/queries/relationship.py +2 -2
  201. infrahub/graphql/queries/search.py +2 -2
  202. infrahub/graphql/resolvers/many_relationship.py +264 -0
  203. infrahub/graphql/resolvers/resolver.py +13 -110
  204. infrahub/graphql/subscription/graphql_query.py +2 -0
  205. infrahub/graphql/types/event.py +20 -11
  206. infrahub/graphql/types/node.py +2 -2
  207. infrahub/graphql/utils.py +2 -2
  208. infrahub/groups/ancestors.py +29 -0
  209. infrahub/groups/parsers.py +107 -0
  210. infrahub/menu/generator.py +7 -7
  211. infrahub/menu/menu.py +0 -10
  212. infrahub/menu/models.py +117 -16
  213. infrahub/menu/repository.py +111 -0
  214. infrahub/menu/utils.py +5 -8
  215. infrahub/message_bus/messages/__init__.py +1 -11
  216. infrahub/message_bus/messages/check_generator_run.py +2 -0
  217. infrahub/message_bus/messages/finalize_validator_execution.py +3 -0
  218. infrahub/message_bus/messages/request_generatordefinition_check.py +2 -0
  219. infrahub/message_bus/operations/__init__.py +0 -2
  220. infrahub/message_bus/operations/check/generator.py +1 -0
  221. infrahub/message_bus/operations/event/__init__.py +2 -2
  222. infrahub/message_bus/operations/finalize/validator.py +51 -1
  223. infrahub/message_bus/operations/requests/generator_definition.py +19 -19
  224. infrahub/message_bus/operations/requests/proposed_change.py +3 -1
  225. infrahub/pools/number.py +2 -4
  226. infrahub/proposed_change/tasks.py +37 -28
  227. infrahub/pytest_plugin.py +13 -10
  228. infrahub/server.py +1 -2
  229. infrahub/services/adapters/event/__init__.py +1 -1
  230. infrahub/task_manager/event.py +23 -9
  231. infrahub/tasks/artifact.py +2 -4
  232. infrahub/telemetry/__init__.py +0 -0
  233. infrahub/telemetry/constants.py +9 -0
  234. infrahub/telemetry/database.py +86 -0
  235. infrahub/telemetry/models.py +65 -0
  236. infrahub/telemetry/task_manager.py +77 -0
  237. infrahub/{tasks/telemetry.py → telemetry/tasks.py} +49 -56
  238. infrahub/telemetry/utils.py +11 -0
  239. infrahub/trace.py +4 -4
  240. infrahub/transformations/tasks.py +2 -2
  241. infrahub/trigger/catalogue.py +2 -5
  242. infrahub/trigger/constants.py +0 -8
  243. infrahub/trigger/models.py +14 -1
  244. infrahub/trigger/setup.py +90 -0
  245. infrahub/trigger/tasks.py +35 -90
  246. infrahub/utils.py +11 -1
  247. infrahub/validators/__init__.py +0 -0
  248. infrahub/validators/events.py +42 -0
  249. infrahub/validators/tasks.py +41 -0
  250. infrahub/webhook/gather.py +17 -0
  251. infrahub/webhook/models.py +22 -5
  252. infrahub/webhook/tasks.py +44 -19
  253. infrahub/webhook/triggers.py +22 -5
  254. infrahub/workers/infrahub_async.py +2 -2
  255. infrahub/workers/utils.py +2 -2
  256. infrahub/workflows/catalogue.py +28 -20
  257. infrahub/workflows/initialization.py +1 -3
  258. infrahub/workflows/models.py +1 -1
  259. infrahub/workflows/utils.py +10 -1
  260. infrahub_sdk/client.py +27 -8
  261. infrahub_sdk/config.py +3 -0
  262. infrahub_sdk/context.py +13 -0
  263. infrahub_sdk/exceptions.py +6 -0
  264. infrahub_sdk/generator.py +4 -1
  265. infrahub_sdk/graphql.py +45 -13
  266. infrahub_sdk/node.py +69 -20
  267. infrahub_sdk/protocols_base.py +32 -11
  268. infrahub_sdk/query_groups.py +6 -35
  269. infrahub_sdk/schema/__init__.py +55 -26
  270. infrahub_sdk/schema/main.py +8 -0
  271. infrahub_sdk/task/__init__.py +10 -0
  272. infrahub_sdk/task/manager.py +12 -6
  273. infrahub_sdk/testing/schemas/animal.py +9 -0
  274. infrahub_sdk/timestamp.py +12 -4
  275. {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/METADATA +3 -2
  276. {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/RECORD +289 -260
  277. {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/entry_points.txt +1 -0
  278. infrahub_testcontainers/constants.py +2 -0
  279. infrahub_testcontainers/container.py +157 -12
  280. infrahub_testcontainers/docker-compose.test.yml +31 -6
  281. infrahub_testcontainers/helpers.py +18 -73
  282. infrahub_testcontainers/host.py +41 -0
  283. infrahub_testcontainers/measurements.py +93 -0
  284. infrahub_testcontainers/models.py +38 -0
  285. infrahub_testcontainers/performance_test.py +166 -0
  286. infrahub_testcontainers/plugin.py +136 -0
  287. infrahub_testcontainers/prometheus.yml +30 -0
  288. infrahub/message_bus/messages/event_branch_create.py +0 -11
  289. infrahub/message_bus/messages/event_branch_delete.py +0 -11
  290. infrahub/message_bus/messages/event_branch_rebased.py +0 -9
  291. infrahub/message_bus/messages/event_node_mutated.py +0 -15
  292. infrahub/message_bus/messages/event_schema_update.py +0 -9
  293. infrahub/message_bus/operations/event/node.py +0 -20
  294. infrahub/message_bus/operations/event/schema.py +0 -17
  295. infrahub/webhook/constants.py +0 -1
  296. {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/LICENSE.txt +0 -0
  297. {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/WHEEL +0 -0
@@ -0,0 +1,55 @@
1
+ from typing import ClassVar
2
+
3
+ from pydantic import Field
4
+
5
+ from .constants import EVENT_NAMESPACE
6
+ from .models import InfrahubEvent
7
+
8
+
9
+ class ValidatorEvent(InfrahubEvent):
10
+ """Event generated when an validator within a pipeline has started."""
11
+
12
+ node_id: str = Field(..., description="The ID of the validator")
13
+ kind: str = Field(..., description="The kind of the validator")
14
+ proposed_change_id: str = Field(..., description="The ID of the proposed change")
15
+
16
+ def get_resource(self) -> dict[str, str]:
17
+ return {
18
+ "prefect.resource.id": self.node_id,
19
+ "infrahub.node.kind": self.kind,
20
+ "infrahub.node.id": self.node_id,
21
+ "infrahub.branch.name": self.meta.context.branch.name,
22
+ }
23
+
24
+ def get_related(self) -> list[dict[str, str]]:
25
+ related = super().get_related()
26
+ related.append(
27
+ {
28
+ "prefect.resource.id": self.proposed_change_id,
29
+ "prefect.resource.role": "infrahub.related.node",
30
+ "infrahub.node.kind": "CoreProposedChange",
31
+ }
32
+ )
33
+
34
+ return related
35
+
36
+
37
+ class ValidatorStartedEvent(ValidatorEvent):
38
+ """Event generated when an validator within a pipeline has started."""
39
+
40
+ event_name: ClassVar[str] = f"{EVENT_NAMESPACE}.validator.started"
41
+ infrahub_node_kind_event: ClassVar[bool] = True
42
+
43
+
44
+ class ValidatorPassedEvent(ValidatorEvent):
45
+ """Event generated when an validator within a pipeline has completed successfully."""
46
+
47
+ event_name: ClassVar[str] = f"{EVENT_NAMESPACE}.validator.passed"
48
+ infrahub_node_kind_event: ClassVar[bool] = True
49
+
50
+
51
+ class ValidatorFailedEvent(ValidatorEvent):
52
+ """Event generated when an validator within a pipeline has completed successfully."""
53
+
54
+ event_name: ClassVar[str] = f"{EVENT_NAMESPACE}.validator.failed"
55
+ infrahub_node_kind_event: ClassVar[bool] = True
infrahub/exceptions.py CHANGED
@@ -1,12 +1,12 @@
1
1
  from pathlib import Path
2
- from typing import Any, Optional, Union
2
+ from typing import Any
3
3
 
4
4
 
5
5
  class Error(Exception):
6
6
  HTTP_CODE: int = 500
7
7
  DESCRIPTION: str = "Unknown Error"
8
8
  message: str = ""
9
- errors: Optional[list] = None
9
+ errors: list | None = None
10
10
 
11
11
  def api_response(self) -> dict[str, Any]:
12
12
  """Return error response."""
@@ -291,35 +291,26 @@ class MigrationError(Error):
291
291
  class ValidationError(Error):
292
292
  HTTP_CODE = 422
293
293
 
294
- def __init__(self, input_value: Union[str, dict, list]) -> None:
294
+ def __init__(self, input_value: str | dict | list) -> None:
295
295
  self.message = ""
296
- self.location = None
297
- self.messages = {}
298
296
 
299
297
  if isinstance(input_value, str):
300
298
  self.message = input_value
301
- elif isinstance(input_value, dict) and len(input_value) == 1:
302
- self.message = list(input_value.values())[0]
303
- self.location = list(input_value.keys())[0]
304
- elif isinstance(input_value, dict) and len(input_value) > 1:
305
- for key, value in input_value.items():
306
- self.messages[key] = value
307
-
299
+ elif isinstance(input_value, dict):
300
+ self.message = ", ".join([f"{message} at {location}" for location, message in input_value.items()])
308
301
  elif isinstance(input_value, list):
309
- for item in input_value:
310
- if isinstance(item, self.__class__):
311
- self.messages[item.location] = item.message
312
- elif isinstance(item, dict):
313
- for key, value in item.items():
314
- self.messages[key] = value
315
-
316
- super().__init__(self.message)
302
+ if all(isinstance(item, ValidationError) for item in input_value):
303
+ self.message = ", ".join([validation_error.message for validation_error in input_value])
304
+ if all(isinstance(item, dict) for item in input_value):
305
+ messages = []
306
+ for item in input_value:
307
+ messages.append(", ".join([f"{message} at {location}" for location, message in item.items()]))
308
+ self.message = ", ".join(messages)
317
309
 
318
- def __str__(self) -> str:
319
- if self.messages:
320
- return ", ".join([f"{message} at {location}" for location, message in self.messages.items()])
310
+ if not self.message:
311
+ raise ValueError("Could not build validation error message")
321
312
 
322
- return f"{self.message} at {self.location or '<Undefined>'}"
313
+ super().__init__(self.message)
323
314
 
324
315
 
325
316
  class DiffError(Error):
@@ -329,6 +320,14 @@ class DiffError(Error):
329
320
  self.message = message
330
321
 
331
322
 
323
+ class HFIDViolatedError(ValidationError):
324
+ matching_nodes_ids: set[str]
325
+
326
+ def __init__(self, input_value: str | dict | list, matching_nodes_ids: set[str]) -> None:
327
+ self.matching_nodes_ids = matching_nodes_ids
328
+ super().__init__(input_value)
329
+
330
+
332
331
  class DiffRangeValidationError(DiffError): ...
333
332
 
334
333
 
@@ -1,7 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Optional
4
-
5
3
  from pydantic import BaseModel, ConfigDict, Field
6
4
 
7
5
 
@@ -9,7 +7,7 @@ class RequestGeneratorRun(BaseModel):
9
7
  """Runs a generator."""
10
8
 
11
9
  generator_definition: ProposedChangeGeneratorDefinition = Field(..., description="The Generator definition")
12
- generator_instance: Optional[str] = Field(
10
+ generator_instance: str | None = Field(
13
11
  default=None, description="The id of the generator instance if it previously existed"
14
12
  )
15
13
  commit: str = Field(..., description="The commit to target")
infrahub/git/base.py CHANGED
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import shutil
4
4
  from abc import ABC, abstractmethod
5
5
  from pathlib import Path
6
- from typing import TYPE_CHECKING, NoReturn, Optional, Union
6
+ from typing import TYPE_CHECKING, NoReturn
7
7
  from uuid import UUID # noqa: TC003
8
8
 
9
9
  import git
@@ -144,12 +144,12 @@ class InfrahubRepositoryBase(BaseModel, ABC):
144
144
  False, description="Flag to indicate if a remote repository (named origin) is present in the config."
145
145
  )
146
146
 
147
- client: Optional[InfrahubClient] = Field(
147
+ client: InfrahubClient | None = Field(
148
148
  default=None,
149
149
  description="Infrahub Client, used to query the Repository and Branch information in the graph and to update the commit.",
150
150
  )
151
151
 
152
- cache_repo: Optional[Repo] = Field(None, description="Internal cache of the GitPython Repo object")
152
+ cache_repo: Repo | None = Field(None, description="Internal cache of the GitPython Repo object")
153
153
  service: InfrahubServices = Field(
154
154
  ..., description="Service object with access to the message queue, the database etc.."
155
155
  )
@@ -584,7 +584,7 @@ class InfrahubRepositoryBase(BaseModel, ABC):
584
584
 
585
585
  return True
586
586
 
587
- def create_commit_worktree(self, commit: str) -> Union[bool, Worktree]:
587
+ def create_commit_worktree(self, commit: str) -> bool | Worktree:
588
588
  """Create a new worktree for a given commit."""
589
589
 
590
590
  # Check of the worktree already exist
@@ -744,7 +744,7 @@ class InfrahubRepositoryBase(BaseModel, ABC):
744
744
  branch_id: str | None = None,
745
745
  create_if_missing: bool = False,
746
746
  update_commit_value: bool = True,
747
- ) -> Union[bool, str]:
747
+ ) -> bool | str:
748
748
  """Pull the latest update from the remote repository on a given branch."""
749
749
 
750
750
  if not self.has_origin:
@@ -812,10 +812,10 @@ class InfrahubRepositoryBase(BaseModel, ABC):
812
812
 
813
813
  async def find_files(
814
814
  self,
815
- extension: Union[str, list[str]],
815
+ extension: str | list[str],
816
816
  branch_name: str | None = None,
817
817
  commit: str | None = None,
818
- directory: Optional[Path] = None,
818
+ directory: Path | None = None,
819
819
  ) -> list[Path]:
820
820
  """Return the path of all files matching a specific extension in a given Branch or Commit."""
821
821
  if not branch_name and not commit:
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import hashlib
4
4
  import importlib
5
5
  import sys
6
- from typing import TYPE_CHECKING, Any, Optional, Union
6
+ from typing import TYPE_CHECKING, Any
7
7
 
8
8
  import jinja2
9
9
  import ujson
@@ -39,7 +39,7 @@ from typing_extensions import Self
39
39
 
40
40
  from infrahub.core.constants import ArtifactStatus, ContentType, InfrahubKind, RepositorySyncStatus
41
41
  from infrahub.core.registry import registry
42
- from infrahub.events.artifact_action import ArtifactEvent
42
+ from infrahub.events.artifact_action import ArtifactCreatedEvent, ArtifactUpdatedEvent
43
43
  from infrahub.events.models import EventMeta
44
44
  from infrahub.events.repository_action import CommitUpdatedEvent
45
45
  from infrahub.exceptions import CheckError, RepositoryInvalidFileSystemError, TransformError
@@ -93,10 +93,10 @@ class CheckDefinitionInformation(BaseModel):
93
93
  timeout: int
94
94
  """Timeout for the Check."""
95
95
 
96
- parameters: Optional[dict] = None
96
+ parameters: dict | None = None
97
97
  """Additional Parameters to extract from each target (if targets is provided)"""
98
98
 
99
- targets: Optional[str] = Field(default=None, description="Targets if not a global check")
99
+ targets: str | None = Field(default=None, description="Targets if not a global check")
100
100
 
101
101
 
102
102
  class TransformPythonInformation(BaseModel):
@@ -161,7 +161,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
161
161
 
162
162
  @flow(name="import-object-from-file", flow_run_name="Import objects")
163
163
  async def import_objects_from_files(
164
- self, infrahub_branch_name: str, git_branch_name: Optional[str] = None, commit: Optional[str] = None
164
+ self, infrahub_branch_name: str, git_branch_name: str | None = None, commit: str | None = None
165
165
  ) -> None:
166
166
  if not commit:
167
167
  commit = self.get_commit_value(branch_name=git_branch_name or infrahub_branch_name)
@@ -171,27 +171,27 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
171
171
  self.create_commit_worktree(commit)
172
172
  await self._update_sync_status(branch_name=infrahub_branch_name, status=RepositorySyncStatus.SYNCING)
173
173
 
174
- config_file = await self.get_repository_config(branch_name=infrahub_branch_name, commit=commit)
174
+ config_file = await self.get_repository_config(branch_name=infrahub_branch_name, commit=commit) # type: ignore[misc]
175
175
  sync_status = RepositorySyncStatus.IN_SYNC if config_file else RepositorySyncStatus.ERROR_IMPORT
176
176
  error: Exception | None = None
177
177
 
178
178
  try:
179
179
  if config_file:
180
- await self.import_schema_files(branch_name=infrahub_branch_name, commit=commit, config_file=config_file)
180
+ await self.import_schema_files(branch_name=infrahub_branch_name, commit=commit, config_file=config_file) # type: ignore[misc]
181
181
 
182
182
  await self.import_all_graphql_query(
183
183
  branch_name=infrahub_branch_name, commit=commit, config_file=config_file
184
- )
184
+ ) # type: ignore[misc]
185
185
 
186
186
  await self.import_all_python_files( # type: ignore[call-overload]
187
187
  branch_name=infrahub_branch_name, commit=commit, config_file=config_file
188
- )
188
+ ) # type: ignore[misc]
189
189
  await self.import_jinja2_transforms(
190
190
  branch_name=infrahub_branch_name, commit=commit, config_file=config_file
191
- )
191
+ ) # type: ignore[misc]
192
192
  await self.import_artifact_definitions(
193
193
  branch_name=infrahub_branch_name, commit=commit, config_file=config_file
194
- )
194
+ ) # type: ignore[misc]
195
195
 
196
196
  except Exception as exc:
197
197
  sync_status = RepositorySyncStatus.ERROR_IMPORT
@@ -443,7 +443,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
443
443
  await existing_artifact_definition.save()
444
444
 
445
445
  @task(name="repository-get-config", task_run_name="get repository config", cache_policy=NONE) # type: ignore[arg-type]
446
- async def get_repository_config(self, branch_name: str, commit: str) -> Optional[InfrahubRepositoryConfig]:
446
+ async def get_repository_config(self, branch_name: str, commit: str) -> InfrahubRepositoryConfig | None:
447
447
  branch_wt = self.get_worktree(identifier=commit or branch_name)
448
448
  log = get_run_logger()
449
449
 
@@ -636,7 +636,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
636
636
  module=module,
637
637
  file_path=file_info.relative_path_file,
638
638
  check_definition=check,
639
- )
639
+ ) # type: ignore[misc]
640
640
  )
641
641
 
642
642
  local_check_definitions = {check.name: check for check in checks}
@@ -797,7 +797,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
797
797
  module=module,
798
798
  file_path=file_info.relative_path_file,
799
799
  transform=transform,
800
- )
800
+ ) # type: ignore[misc]
801
801
  )
802
802
 
803
803
  local_transform_definitions = {transform.name: transform for transform in transforms}
@@ -1070,9 +1070,9 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
1070
1070
  ) -> None:
1071
1071
  await add_tags(branches=[branch_name], nodes=[str(self.id)])
1072
1072
 
1073
- await self.import_python_check_definitions(branch_name=branch_name, commit=commit, config_file=config_file)
1074
- await self.import_python_transforms(branch_name=branch_name, commit=commit, config_file=config_file)
1075
- await self.import_generator_definitions(branch_name=branch_name, commit=commit, config_file=config_file)
1073
+ await self.import_python_check_definitions(branch_name=branch_name, commit=commit, config_file=config_file) # type: ignore[misc]
1074
+ await self.import_python_transforms(branch_name=branch_name, commit=commit, config_file=config_file) # type: ignore[misc]
1075
+ await self.import_generator_definitions(branch_name=branch_name, commit=commit, config_file=config_file) # type: ignore[misc]
1076
1076
 
1077
1077
  @task(name="jinja2-template-render", task_run_name="Render Jinja2 template", cache_policy=NONE) # type: ignore[arg-type]
1078
1078
  async def render_jinja2_template(self, commit: str, location: str, data: dict) -> str:
@@ -1098,7 +1098,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
1098
1098
  location: str,
1099
1099
  class_name: str,
1100
1100
  client: InfrahubClient,
1101
- params: Optional[dict] = None,
1101
+ params: dict | None = None,
1102
1102
  ) -> InfrahubCheck:
1103
1103
  """Execute A Python Check stored in the repository."""
1104
1104
  log = get_run_logger()
@@ -1227,7 +1227,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
1227
1227
  if transformation.typename == InfrahubKind.TRANSFORMJINJA2:
1228
1228
  artifact_content = await self.render_jinja2_template.with_options(
1229
1229
  timeout_seconds=transformation.timeout.value
1230
- )(commit=commit, location=transformation.template_path.value, data=response)
1230
+ )(commit=commit, location=transformation.template_path.value, data=response) # type: ignore[misc]
1231
1231
  elif transformation.typename == InfrahubKind.TRANSFORMPYTHON:
1232
1232
  transformation_location = f"{transformation.file_path.value}::{transformation.class_name.value}"
1233
1233
  artifact_content = await self.execute_python_transform.with_options(
@@ -1238,7 +1238,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
1238
1238
  location=transformation_location,
1239
1239
  data=response,
1240
1240
  client=self.sdk,
1241
- )
1241
+ ) # type: ignore[misc]
1242
1242
 
1243
1243
  if definition.content_type.value == ContentType.APPLICATION_JSON.value and isinstance(artifact_content, dict):
1244
1244
  artifact_content_str = ujson.dumps(artifact_content, indent=2)
@@ -1270,7 +1270,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
1270
1270
  self,
1271
1271
  artifact: CoreArtifact,
1272
1272
  artifact_created: bool,
1273
- message: Union[CheckArtifactCreate, RequestArtifactGenerate],
1273
+ message: CheckArtifactCreate | RequestArtifactGenerate,
1274
1274
  ) -> ArtifactGenerateResult:
1275
1275
  response = await self.sdk.query_gql_query(
1276
1276
  name=message.query,
@@ -1289,7 +1289,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
1289
1289
  if message.transform_type == InfrahubKind.TRANSFORMJINJA2:
1290
1290
  artifact_content = await self.render_jinja2_template.with_options(timeout_seconds=message.timeout)(
1291
1291
  commit=message.commit, location=message.transform_location, data=response
1292
- )
1292
+ ) # type: ignore[misc]
1293
1293
  elif message.transform_type == InfrahubKind.TRANSFORMPYTHON:
1294
1294
  artifact_content = await self.execute_python_transform.with_options(timeout_seconds=message.timeout)(
1295
1295
  branch_name=message.branch_name,
@@ -1297,7 +1297,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
1297
1297
  location=message.transform_location,
1298
1298
  data=response,
1299
1299
  client=self.sdk,
1300
- )
1300
+ ) # type: ignore[misc]
1301
1301
 
1302
1302
  if message.content_type == ContentType.APPLICATION_JSON.value and isinstance(artifact_content, dict):
1303
1303
  artifact_content_str = ujson.dumps(artifact_content, indent=2)
@@ -1324,7 +1324,9 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
1324
1324
  artifact.name.value = message.artifact_name
1325
1325
  await artifact.save()
1326
1326
 
1327
- event = ArtifactEvent(
1327
+ event_class = ArtifactCreatedEvent if artifact_created else ArtifactUpdatedEvent
1328
+
1329
+ event = event_class(
1328
1330
  node_id=artifact.id,
1329
1331
  target_id=message.target_id,
1330
1332
  target_kind=message.target_kind,
@@ -1334,7 +1336,6 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
1334
1336
  checksum_previous=previous_checksum,
1335
1337
  storage_id=storage_id,
1336
1338
  storage_id_previous=previous_storage_id,
1337
- created=artifact_created,
1338
1339
  )
1339
1340
 
1340
1341
  await self.service.event.send(event=event)
infrahub/git/models.py CHANGED
@@ -1,5 +1,3 @@
1
- from typing import Optional
2
-
3
1
  from pydantic import BaseModel, ConfigDict, Field
4
2
 
5
3
  from infrahub.context import InfrahubContext
@@ -34,7 +32,7 @@ class RequestArtifactGenerate(BaseModel):
34
32
  target_id: str = Field(..., description="The ID of the target object for this artifact")
35
33
  target_kind: str = Field(..., description="The kind of the target object for this artifact")
36
34
  target_name: str = Field(..., description="Name of the artifact target")
37
- artifact_id: Optional[str] = Field(default=None, description="The id of the artifact if it previously existed")
35
+ artifact_id: str | None = Field(default=None, description="The id of the artifact if it previously existed")
38
36
  query: str = Field(..., description="The name of the query to use when collecting data")
39
37
  timeout: int = Field(..., description="Timeout for requests used to generate this artifact")
40
38
  variables: dict = Field(..., description="Input variables when generating the artifact")
@@ -47,8 +45,8 @@ class GitRepositoryAdd(BaseModel):
47
45
  location: str = Field(..., description="The external URL of the repository")
48
46
  repository_id: str = Field(..., description="The unique ID of the Repository")
49
47
  repository_name: str = Field(..., description="The name of the repository")
50
- created_by: Optional[str] = Field(default=None, description="The user ID of the user that created the repository")
51
- default_branch_name: Optional[str] = Field(None, description="Default branch for this repository")
48
+ created_by: str | None = Field(default=None, description="The user ID of the user that created the repository")
49
+ default_branch_name: str | None = Field(None, description="Default branch for this repository")
52
50
  infrahub_branch_name: str = Field(..., description="Infrahub branch on which to sync the remote repository")
53
51
  infrahub_branch_id: str = Field(..., description="Id of the Infrahub branch on which to sync the remote repository")
54
52
  internal_status: str = Field(..., description="Administrative status of the repository")
@@ -61,7 +59,7 @@ class GitRepositoryAddReadOnly(BaseModel):
61
59
  repository_id: str = Field(..., description="The unique ID of the Repository")
62
60
  repository_name: str = Field(..., description="The name of the repository")
63
61
  ref: str = Field(..., description="Ref to track on the external repository")
64
- created_by: Optional[str] = Field(default=None, description="The user ID of the user that created the repository")
62
+ created_by: str | None = Field(default=None, description="The user ID of the user that created the repository")
65
63
  infrahub_branch_name: str = Field(..., description="Infrahub branch on which to sync the remote repository")
66
64
  infrahub_branch_id: str = Field(..., description="Id of the Infrahub branch on which to sync the remote repository")
67
65
  internal_status: str = Field(..., description="Internal status of the repository")
@@ -73,8 +71,8 @@ class GitRepositoryPullReadOnly(BaseModel):
73
71
  location: str = Field(..., description="The external URL of the repository")
74
72
  repository_id: str = Field(..., description="The unique ID of the Repository")
75
73
  repository_name: str = Field(..., description="The name of the repository")
76
- ref: Optional[str] = Field(None, description="Ref to track on the external repository")
77
- commit: Optional[str] = Field(None, description="Specific commit to pull")
74
+ ref: str | None = Field(None, description="Ref to track on the external repository")
75
+ commit: str | None = Field(None, description="Specific commit to pull")
78
76
  infrahub_branch_name: str = Field(..., description="Infrahub branch on which to sync the remote repository")
79
77
  infrahub_branch_id: str = Field(..., description="Infrahub branch on which to sync the remote repository")
80
78
 
@@ -108,7 +106,7 @@ class GitDiffNamesOnly(BaseModel):
108
106
  repository_name: str = Field(..., description="The name of the repository")
109
107
  repository_kind: str = Field(..., description="The kind of the repository")
110
108
  first_commit: str = Field(..., description="The first commit")
111
- second_commit: Optional[str] = Field(None, description="The second commit")
109
+ second_commit: str | None = Field(None, description="The second commit")
112
110
 
113
111
 
114
112
  class GitDiffNamesOnlyResponse(BaseModel):
@@ -189,3 +187,18 @@ class CheckRepositoryMergeConflicts(BaseModel):
189
187
  repository_name: str = Field(..., description="The name of the Repository")
190
188
  source_branch: str = Field(..., description="The source branch")
191
189
  target_branch: str = Field(..., description="The target branch")
190
+
191
+
192
+ class RepositoryBranchInfo(BaseModel):
193
+ internal_status: str
194
+
195
+
196
+ class RepositoryData(BaseModel):
197
+ repository_id: str = Field(..., description="Id of the repository")
198
+ repository_name: str = Field(..., description="Name of the repository")
199
+ branches: dict[str, str] = Field(
200
+ ...,
201
+ description="Dictionary with the name of the branch as the key and the active commit id as the value",
202
+ )
203
+
204
+ branch_info: dict[str, RepositoryBranchInfo] = Field(default_factory=dict)
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Any, Union
3
+ from typing import TYPE_CHECKING, Any
4
4
 
5
5
  from git.exc import BadName, GitCommandError
6
6
  from infrahub_sdk.exceptions import GraphQLError
@@ -250,7 +250,7 @@ class InfrahubReadOnlyRepository(InfrahubRepositoryIntegrator):
250
250
 
251
251
  async def get_initialized_repo(
252
252
  repository_id: str, name: str, service: InfrahubServices, repository_kind: str, commit: str | None = None
253
- ) -> Union[InfrahubReadOnlyRepository, InfrahubRepository]:
253
+ ) -> InfrahubReadOnlyRepository | InfrahubRepository:
254
254
  if repository_kind == InfrahubKind.REPOSITORY:
255
255
  return await InfrahubRepository.init(
256
256
  id=repository_id, name=name, commit=commit, client=service._client, service=service
@@ -266,7 +266,7 @@ async def get_initialized_repo(
266
266
 
267
267
  async def initialize_repo(
268
268
  location: str, repository_id: str, name: str, service: InfrahubServices, repository_kind: str
269
- ) -> Union[InfrahubReadOnlyRepository, InfrahubRepository]:
269
+ ) -> InfrahubReadOnlyRepository | InfrahubRepository:
270
270
  if repository_kind == InfrahubKind.REPOSITORY:
271
271
  return await InfrahubRepository.new(
272
272
  location=location, id=repository_id, name=name, client=service._client, service=service