infrahub-server 1.2.0rc0__py3-none-any.whl → 1.2.2__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 (365) 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 +5 -3
  5. infrahub/artifacts/tasks.py +3 -5
  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 +240 -12
  12. infrahub/computed_attribute/tasks.py +72 -432
  13. infrahub/computed_attribute/triggers.py +13 -47
  14. infrahub/config.py +43 -32
  15. infrahub/context.py +14 -0
  16. infrahub/core/account.py +4 -4
  17. infrahub/core/attribute.py +58 -58
  18. infrahub/core/branch/tasks.py +74 -22
  19. infrahub/core/changelog/diff.py +95 -36
  20. infrahub/core/changelog/models.py +217 -43
  21. infrahub/core/constants/__init__.py +28 -0
  22. infrahub/core/constants/infrahubkind.py +2 -0
  23. infrahub/core/constants/schema.py +2 -0
  24. infrahub/core/constraint/node/runner.py +9 -8
  25. infrahub/core/diff/branch_differ.py +10 -10
  26. infrahub/core/diff/enricher/cardinality_one.py +5 -0
  27. infrahub/core/diff/enricher/hierarchy.py +17 -4
  28. infrahub/core/diff/enricher/labels.py +5 -0
  29. infrahub/core/diff/enricher/path_identifier.py +4 -0
  30. infrahub/core/diff/ipam_diff_parser.py +4 -5
  31. infrahub/core/diff/model/diff.py +27 -27
  32. infrahub/core/diff/model/path.py +32 -9
  33. infrahub/core/diff/parent_node_adder.py +78 -0
  34. infrahub/core/diff/payload_builder.py +13 -2
  35. infrahub/core/diff/query/filters.py +2 -2
  36. infrahub/core/diff/query/merge.py +20 -17
  37. infrahub/core/diff/query/save.py +188 -182
  38. infrahub/core/diff/query/summary_counts_enricher.py +51 -4
  39. infrahub/core/diff/query_parser.py +4 -4
  40. infrahub/core/diff/repository/deserializer.py +8 -3
  41. infrahub/core/diff/repository/repository.py +156 -38
  42. infrahub/core/diff/tasks.py +4 -4
  43. infrahub/core/graph/__init__.py +1 -1
  44. infrahub/core/graph/index.py +3 -0
  45. infrahub/core/initialization.py +1 -10
  46. infrahub/core/ipam/constants.py +3 -4
  47. infrahub/core/ipam/reconciler.py +12 -12
  48. infrahub/core/ipam/utilization.py +10 -13
  49. infrahub/core/manager.py +36 -36
  50. infrahub/core/merge.py +7 -7
  51. infrahub/core/migrations/__init__.py +2 -3
  52. infrahub/core/migrations/graph/__init__.py +12 -3
  53. infrahub/core/migrations/graph/m017_add_core_profile.py +1 -5
  54. infrahub/core/migrations/graph/m018_uniqueness_nulls.py +4 -4
  55. infrahub/core/migrations/graph/m019_restore_rels_to_time.py +256 -0
  56. infrahub/core/migrations/graph/m020_duplicate_edges.py +160 -0
  57. infrahub/core/migrations/graph/m021_missing_hierarchy_merge.py +51 -0
  58. infrahub/core/migrations/graph/m022_add_generate_template_attr.py +48 -0
  59. infrahub/core/migrations/graph/m023_deduplicate_cardinality_one_relationships.py +96 -0
  60. infrahub/core/migrations/query/attribute_add.py +2 -2
  61. infrahub/core/migrations/query/node_duplicate.py +43 -26
  62. infrahub/core/migrations/query/schema_attribute_update.py +2 -2
  63. infrahub/core/migrations/schema/models.py +19 -4
  64. infrahub/core/migrations/schema/node_remove.py +26 -12
  65. infrahub/core/migrations/schema/tasks.py +2 -2
  66. infrahub/core/migrations/shared.py +16 -16
  67. infrahub/core/models.py +15 -6
  68. infrahub/core/node/__init__.py +43 -39
  69. infrahub/core/node/base.py +2 -4
  70. infrahub/core/node/constraints/attribute_uniqueness.py +2 -2
  71. infrahub/core/node/constraints/grouped_uniqueness.py +99 -47
  72. infrahub/core/node/constraints/interface.py +1 -2
  73. infrahub/core/node/delete_validator.py +3 -5
  74. infrahub/core/node/ipam.py +4 -4
  75. infrahub/core/node/permissions.py +7 -7
  76. infrahub/core/node/resource_manager/ip_address_pool.py +6 -6
  77. infrahub/core/node/resource_manager/ip_prefix_pool.py +6 -6
  78. infrahub/core/node/resource_manager/number_pool.py +3 -3
  79. infrahub/core/path.py +12 -12
  80. infrahub/core/property.py +11 -11
  81. infrahub/core/protocols.py +7 -0
  82. infrahub/core/protocols_base.py +21 -21
  83. infrahub/core/query/__init__.py +33 -33
  84. infrahub/core/query/attribute.py +6 -4
  85. infrahub/core/query/diff.py +3 -3
  86. infrahub/core/query/node.py +98 -37
  87. infrahub/core/query/relationship.py +228 -40
  88. infrahub/core/query/resource_manager.py +2 -0
  89. infrahub/core/query/standard_node.py +3 -3
  90. infrahub/core/query/subquery.py +9 -9
  91. infrahub/core/registry.py +13 -15
  92. infrahub/core/relationship/constraints/count.py +3 -4
  93. infrahub/core/relationship/constraints/peer_kind.py +3 -4
  94. infrahub/core/relationship/constraints/profiles_kind.py +2 -2
  95. infrahub/core/relationship/model.py +51 -59
  96. infrahub/core/schema/attribute_schema.py +16 -8
  97. infrahub/core/schema/basenode_schema.py +105 -44
  98. infrahub/core/schema/computed_attribute.py +3 -3
  99. infrahub/core/schema/definitions/core/__init__.py +147 -0
  100. infrahub/core/schema/definitions/core/account.py +171 -0
  101. infrahub/core/schema/definitions/core/artifact.py +136 -0
  102. infrahub/core/schema/definitions/core/builtin.py +24 -0
  103. infrahub/core/schema/definitions/core/check.py +68 -0
  104. infrahub/core/schema/definitions/core/core.py +17 -0
  105. infrahub/core/schema/definitions/core/generator.py +100 -0
  106. infrahub/core/schema/definitions/core/graphql_query.py +79 -0
  107. infrahub/core/schema/definitions/core/group.py +108 -0
  108. infrahub/core/schema/definitions/core/ipam.py +193 -0
  109. infrahub/core/schema/definitions/core/lineage.py +19 -0
  110. infrahub/core/schema/definitions/core/menu.py +48 -0
  111. infrahub/core/schema/definitions/core/permission.py +163 -0
  112. infrahub/core/schema/definitions/core/profile.py +18 -0
  113. infrahub/core/schema/definitions/core/propose_change.py +97 -0
  114. infrahub/core/schema/definitions/core/propose_change_comment.py +193 -0
  115. infrahub/core/schema/definitions/core/propose_change_validator.py +328 -0
  116. infrahub/core/schema/definitions/core/repository.py +286 -0
  117. infrahub/core/schema/definitions/core/resource_pool.py +170 -0
  118. infrahub/core/schema/definitions/core/template.py +27 -0
  119. infrahub/core/schema/definitions/core/transform.py +96 -0
  120. infrahub/core/schema/definitions/core/webhook.py +134 -0
  121. infrahub/core/schema/definitions/internal.py +16 -16
  122. infrahub/core/schema/dropdown.py +3 -4
  123. infrahub/core/schema/generated/attribute_schema.py +15 -18
  124. infrahub/core/schema/generated/base_node_schema.py +12 -14
  125. infrahub/core/schema/generated/node_schema.py +3 -5
  126. infrahub/core/schema/generated/relationship_schema.py +9 -11
  127. infrahub/core/schema/generic_schema.py +2 -2
  128. infrahub/core/schema/manager.py +20 -9
  129. infrahub/core/schema/node_schema.py +4 -2
  130. infrahub/core/schema/relationship_schema.py +14 -6
  131. infrahub/core/schema/schema_branch.py +292 -144
  132. infrahub/core/schema/schema_branch_computed.py +41 -4
  133. infrahub/core/task/task.py +3 -3
  134. infrahub/core/task/user_task.py +15 -15
  135. infrahub/core/timestamp.py +3 -3
  136. infrahub/core/utils.py +20 -18
  137. infrahub/core/validators/__init__.py +1 -3
  138. infrahub/core/validators/aggregated_checker.py +2 -2
  139. infrahub/core/validators/attribute/choices.py +2 -2
  140. infrahub/core/validators/attribute/enum.py +2 -2
  141. infrahub/core/validators/attribute/kind.py +2 -2
  142. infrahub/core/validators/attribute/length.py +2 -2
  143. infrahub/core/validators/attribute/optional.py +2 -2
  144. infrahub/core/validators/attribute/regex.py +2 -2
  145. infrahub/core/validators/attribute/unique.py +2 -2
  146. infrahub/core/validators/checks_runner.py +25 -2
  147. infrahub/core/validators/determiner.py +1 -3
  148. infrahub/core/validators/interface.py +6 -2
  149. infrahub/core/validators/model.py +22 -3
  150. infrahub/core/validators/models/validate_migration.py +17 -4
  151. infrahub/core/validators/node/attribute.py +2 -2
  152. infrahub/core/validators/node/generate_profile.py +2 -2
  153. infrahub/core/validators/node/hierarchy.py +3 -5
  154. infrahub/core/validators/node/inherit_from.py +27 -5
  155. infrahub/core/validators/node/relationship.py +2 -2
  156. infrahub/core/validators/relationship/count.py +4 -4
  157. infrahub/core/validators/relationship/optional.py +2 -2
  158. infrahub/core/validators/relationship/peer.py +2 -2
  159. infrahub/core/validators/shared.py +2 -2
  160. infrahub/core/validators/tasks.py +8 -0
  161. infrahub/core/validators/uniqueness/checker.py +22 -21
  162. infrahub/core/validators/uniqueness/index.py +2 -2
  163. infrahub/core/validators/uniqueness/model.py +11 -11
  164. infrahub/database/__init__.py +27 -22
  165. infrahub/database/metrics.py +7 -1
  166. infrahub/dependencies/builder/constraint/grouped/node_runner.py +1 -3
  167. infrahub/dependencies/builder/diff/deserializer.py +3 -1
  168. infrahub/dependencies/builder/diff/enricher/hierarchy.py +3 -1
  169. infrahub/dependencies/builder/diff/parent_node_adder.py +8 -0
  170. infrahub/dependencies/component/registry.py +2 -2
  171. infrahub/events/__init__.py +25 -2
  172. infrahub/events/artifact_action.py +64 -0
  173. infrahub/events/branch_action.py +33 -22
  174. infrahub/events/generator.py +71 -0
  175. infrahub/events/group_action.py +51 -21
  176. infrahub/events/models.py +18 -19
  177. infrahub/events/node_action.py +88 -37
  178. infrahub/events/repository_action.py +5 -18
  179. infrahub/events/schema_action.py +4 -9
  180. infrahub/events/utils.py +16 -0
  181. infrahub/events/validator_action.py +55 -0
  182. infrahub/exceptions.py +62 -26
  183. infrahub/generators/models.py +2 -3
  184. infrahub/generators/tasks.py +24 -4
  185. infrahub/git/base.py +87 -36
  186. infrahub/git/integrator.py +48 -48
  187. infrahub/git/models.py +101 -9
  188. infrahub/git/repository.py +3 -3
  189. infrahub/git/tasks.py +408 -6
  190. infrahub/git/utils.py +48 -0
  191. infrahub/git/worktree.py +1 -2
  192. infrahub/git_credential/askpass.py +1 -2
  193. infrahub/graphql/analyzer.py +12 -0
  194. infrahub/graphql/app.py +13 -15
  195. infrahub/graphql/context.py +39 -0
  196. infrahub/graphql/initialization.py +3 -0
  197. infrahub/graphql/loaders/node.py +2 -12
  198. infrahub/graphql/loaders/peers.py +77 -0
  199. infrahub/graphql/loaders/shared.py +13 -0
  200. infrahub/graphql/manager.py +17 -19
  201. infrahub/graphql/mutations/artifact_definition.py +5 -5
  202. infrahub/graphql/mutations/branch.py +26 -1
  203. infrahub/graphql/mutations/computed_attribute.py +9 -5
  204. infrahub/graphql/mutations/diff.py +23 -11
  205. infrahub/graphql/mutations/diff_conflict.py +5 -0
  206. infrahub/graphql/mutations/generator.py +83 -0
  207. infrahub/graphql/mutations/graphql_query.py +5 -5
  208. infrahub/graphql/mutations/ipam.py +54 -74
  209. infrahub/graphql/mutations/main.py +195 -132
  210. infrahub/graphql/mutations/menu.py +7 -7
  211. infrahub/graphql/mutations/models.py +2 -4
  212. infrahub/graphql/mutations/node_getter/by_default_filter.py +10 -10
  213. infrahub/graphql/mutations/node_getter/by_hfid.py +1 -3
  214. infrahub/graphql/mutations/node_getter/by_id.py +1 -3
  215. infrahub/graphql/mutations/node_getter/interface.py +1 -2
  216. infrahub/graphql/mutations/proposed_change.py +7 -7
  217. infrahub/graphql/mutations/relationship.py +93 -19
  218. infrahub/graphql/mutations/repository.py +8 -8
  219. infrahub/graphql/mutations/resource_manager.py +3 -3
  220. infrahub/graphql/mutations/schema.py +19 -4
  221. infrahub/graphql/mutations/webhook.py +137 -0
  222. infrahub/graphql/parser.py +4 -4
  223. infrahub/graphql/permissions.py +1 -10
  224. infrahub/graphql/queries/diff/tree.py +19 -14
  225. infrahub/graphql/queries/event.py +5 -2
  226. infrahub/graphql/queries/ipam.py +2 -2
  227. infrahub/graphql/queries/relationship.py +2 -2
  228. infrahub/graphql/queries/search.py +2 -2
  229. infrahub/graphql/resolvers/many_relationship.py +264 -0
  230. infrahub/graphql/resolvers/resolver.py +13 -110
  231. infrahub/graphql/schema.py +2 -0
  232. infrahub/graphql/subscription/graphql_query.py +2 -0
  233. infrahub/graphql/types/context.py +12 -0
  234. infrahub/graphql/types/event.py +84 -17
  235. infrahub/graphql/types/node.py +2 -2
  236. infrahub/graphql/utils.py +2 -2
  237. infrahub/groups/ancestors.py +29 -0
  238. infrahub/groups/parsers.py +107 -0
  239. infrahub/lock.py +20 -20
  240. infrahub/menu/constants.py +0 -1
  241. infrahub/menu/generator.py +9 -21
  242. infrahub/menu/menu.py +17 -38
  243. infrahub/menu/models.py +117 -16
  244. infrahub/menu/repository.py +111 -0
  245. infrahub/menu/utils.py +5 -8
  246. infrahub/message_bus/__init__.py +11 -13
  247. infrahub/message_bus/messages/__init__.py +1 -21
  248. infrahub/message_bus/messages/check_generator_run.py +3 -3
  249. infrahub/message_bus/messages/finalize_validator_execution.py +3 -0
  250. infrahub/message_bus/messages/proposed_change/request_proposedchange_refreshartifacts.py +6 -0
  251. infrahub/message_bus/messages/request_generatordefinition_check.py +2 -0
  252. infrahub/message_bus/messages/send_echo_request.py +1 -1
  253. infrahub/message_bus/operations/__init__.py +1 -10
  254. infrahub/message_bus/operations/check/__init__.py +2 -2
  255. infrahub/message_bus/operations/check/generator.py +1 -0
  256. infrahub/message_bus/operations/event/__init__.py +2 -2
  257. infrahub/message_bus/operations/event/worker.py +0 -3
  258. infrahub/message_bus/operations/finalize/validator.py +51 -1
  259. infrahub/message_bus/operations/requests/__init__.py +0 -2
  260. infrahub/message_bus/operations/requests/generator_definition.py +21 -23
  261. infrahub/message_bus/operations/requests/proposed_change.py +14 -10
  262. infrahub/permissions/globals.py +15 -0
  263. infrahub/pools/number.py +2 -4
  264. infrahub/proposed_change/models.py +3 -0
  265. infrahub/proposed_change/tasks.py +58 -45
  266. infrahub/pytest_plugin.py +13 -10
  267. infrahub/server.py +2 -3
  268. infrahub/services/__init__.py +2 -2
  269. infrahub/services/adapters/cache/__init__.py +4 -6
  270. infrahub/services/adapters/cache/nats.py +4 -5
  271. infrahub/services/adapters/cache/redis.py +3 -7
  272. infrahub/services/adapters/event/__init__.py +1 -1
  273. infrahub/services/adapters/message_bus/__init__.py +3 -3
  274. infrahub/services/adapters/message_bus/local.py +2 -2
  275. infrahub/services/adapters/message_bus/nats.py +4 -4
  276. infrahub/services/adapters/message_bus/rabbitmq.py +4 -4
  277. infrahub/services/adapters/workflow/local.py +2 -2
  278. infrahub/services/component.py +5 -5
  279. infrahub/services/protocols.py +7 -7
  280. infrahub/services/scheduler.py +1 -3
  281. infrahub/task_manager/event.py +102 -9
  282. infrahub/task_manager/models.py +27 -7
  283. infrahub/tasks/artifact.py +7 -6
  284. infrahub/telemetry/__init__.py +0 -0
  285. infrahub/telemetry/constants.py +9 -0
  286. infrahub/telemetry/database.py +86 -0
  287. infrahub/telemetry/models.py +65 -0
  288. infrahub/telemetry/task_manager.py +77 -0
  289. infrahub/{tasks/telemetry.py → telemetry/tasks.py} +49 -56
  290. infrahub/telemetry/utils.py +11 -0
  291. infrahub/trace.py +4 -4
  292. infrahub/transformations/tasks.py +2 -2
  293. infrahub/trigger/catalogue.py +4 -6
  294. infrahub/trigger/constants.py +0 -8
  295. infrahub/trigger/models.py +54 -5
  296. infrahub/trigger/setup.py +90 -0
  297. infrahub/trigger/tasks.py +35 -83
  298. infrahub/utils.py +11 -1
  299. infrahub/validators/__init__.py +0 -0
  300. infrahub/validators/events.py +42 -0
  301. infrahub/validators/tasks.py +41 -0
  302. infrahub/webhook/gather.py +17 -0
  303. infrahub/webhook/models.py +176 -44
  304. infrahub/webhook/tasks.py +154 -155
  305. infrahub/webhook/triggers.py +31 -7
  306. infrahub/workers/infrahub_async.py +2 -2
  307. infrahub/workers/utils.py +2 -2
  308. infrahub/workflows/catalogue.py +86 -35
  309. infrahub/workflows/initialization.py +8 -2
  310. infrahub/workflows/models.py +27 -1
  311. infrahub/workflows/utils.py +15 -6
  312. infrahub_sdk/client.py +35 -8
  313. infrahub_sdk/config.py +3 -0
  314. infrahub_sdk/context.py +13 -0
  315. infrahub_sdk/ctl/branch.py +3 -2
  316. infrahub_sdk/ctl/cli_commands.py +5 -1
  317. infrahub_sdk/ctl/utils.py +0 -16
  318. infrahub_sdk/exceptions.py +12 -0
  319. infrahub_sdk/generator.py +4 -1
  320. infrahub_sdk/graphql.py +45 -13
  321. infrahub_sdk/node.py +73 -22
  322. infrahub_sdk/protocols.py +21 -8
  323. infrahub_sdk/protocols_base.py +32 -11
  324. infrahub_sdk/query_groups.py +6 -35
  325. infrahub_sdk/schema/__init__.py +55 -26
  326. infrahub_sdk/schema/main.py +8 -0
  327. infrahub_sdk/task/__init__.py +11 -0
  328. infrahub_sdk/task/constants.py +3 -0
  329. infrahub_sdk/task/exceptions.py +25 -0
  330. infrahub_sdk/task/manager.py +551 -0
  331. infrahub_sdk/task/models.py +74 -0
  332. infrahub_sdk/testing/schemas/animal.py +9 -0
  333. infrahub_sdk/timestamp.py +142 -33
  334. infrahub_sdk/utils.py +29 -1
  335. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.2.dist-info}/METADATA +8 -6
  336. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.2.dist-info}/RECORD +349 -293
  337. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.2.dist-info}/entry_points.txt +1 -0
  338. infrahub_testcontainers/constants.py +2 -0
  339. infrahub_testcontainers/container.py +157 -12
  340. infrahub_testcontainers/docker-compose.test.yml +31 -6
  341. infrahub_testcontainers/helpers.py +18 -73
  342. infrahub_testcontainers/host.py +41 -0
  343. infrahub_testcontainers/measurements.py +93 -0
  344. infrahub_testcontainers/models.py +38 -0
  345. infrahub_testcontainers/performance_test.py +166 -0
  346. infrahub_testcontainers/plugin.py +136 -0
  347. infrahub_testcontainers/prometheus.yml +30 -0
  348. infrahub/core/schema/definitions/core.py +0 -2286
  349. infrahub/message_bus/messages/check_repository_checkdefinition.py +0 -20
  350. infrahub/message_bus/messages/check_repository_mergeconflicts.py +0 -16
  351. infrahub/message_bus/messages/check_repository_usercheck.py +0 -26
  352. infrahub/message_bus/messages/event_branch_create.py +0 -11
  353. infrahub/message_bus/messages/event_branch_delete.py +0 -11
  354. infrahub/message_bus/messages/event_branch_rebased.py +0 -9
  355. infrahub/message_bus/messages/event_node_mutated.py +0 -15
  356. infrahub/message_bus/messages/event_schema_update.py +0 -9
  357. infrahub/message_bus/messages/request_repository_checks.py +0 -12
  358. infrahub/message_bus/messages/request_repository_userchecks.py +0 -18
  359. infrahub/message_bus/operations/check/repository.py +0 -293
  360. infrahub/message_bus/operations/event/node.py +0 -20
  361. infrahub/message_bus/operations/event/schema.py +0 -17
  362. infrahub/message_bus/operations/requests/repository.py +0 -133
  363. infrahub/webhook/constants.py +0 -1
  364. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.2.dist-info}/LICENSE.txt +0 -0
  365. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.2.dist-info}/WHEEL +0 -0
@@ -3,11 +3,11 @@ from __future__ import annotations
3
3
  import ipaddress
4
4
  import re
5
5
  from enum import Enum
6
- from typing import TYPE_CHECKING, Any, Optional, Union
6
+ from typing import TYPE_CHECKING, Any
7
7
 
8
8
  import netaddr
9
9
  import ujson
10
- from infrahub_sdk.timestamp import TimestampFormatError
10
+ from infrahub_sdk.exceptions import TimestampFormatError
11
11
  from infrahub_sdk.utils import is_valid_url
12
12
  from infrahub_sdk.uuidt import UUIDT
13
13
  from pydantic import BaseModel, Field
@@ -43,7 +43,7 @@ if TYPE_CHECKING:
43
43
  MAX_STRING_LENGTH = 4096
44
44
 
45
45
 
46
- def validate_string_length(value: Optional[str]) -> None:
46
+ def validate_string_length(value: str | None) -> None:
47
47
  """
48
48
  Validates input string length does not exceed a given threshold, as Neo4J cannot index string values larger than 8167 bytes,
49
49
  see https://neo4j.com/developer/kb/index-limitations-and-workaround/.
@@ -75,7 +75,7 @@ class AttributeCreateData(BaseModel):
75
75
 
76
76
 
77
77
  class BaseAttribute(FlagPropertyMixin, NodePropertyMixin):
78
- type: Optional[Union[type, tuple[type]]] = None
78
+ type: type | tuple[type] | None = None
79
79
 
80
80
  _rel_to_node_label: str = RELATIONSHIP_TO_NODE_LABEL
81
81
  _rel_to_value_label: str = RELATIONSHIP_TO_VALUE_LABEL
@@ -87,10 +87,10 @@ class BaseAttribute(FlagPropertyMixin, NodePropertyMixin):
87
87
  branch: Branch,
88
88
  at: Timestamp,
89
89
  node: Node,
90
- id: Optional[str] = None,
91
- db_id: Optional[str] = None,
92
- data: Optional[Union[dict, str, AttributeFromDB]] = None,
93
- updated_at: Optional[Union[Timestamp, str]] = None,
90
+ id: str | None = None,
91
+ db_id: str | None = None,
92
+ data: dict | str | AttributeFromDB | None = None,
93
+ updated_at: Timestamp | str | None = None,
94
94
  is_default: bool = False,
95
95
  is_from_profile: bool = False,
96
96
  **kwargs,
@@ -106,7 +106,7 @@ class BaseAttribute(FlagPropertyMixin, NodePropertyMixin):
106
106
  self.at = at
107
107
  self.is_default = is_default
108
108
  self.is_from_profile = is_from_profile
109
- self.from_pool: Optional[dict] = None
109
+ self.from_pool: dict | None = None
110
110
 
111
111
  self._init_node_property_mixin(kwargs)
112
112
  self._init_flag_property_mixin(kwargs)
@@ -317,7 +317,7 @@ class BaseAttribute(FlagPropertyMixin, NodePropertyMixin):
317
317
  """Deserialize the value coming from the database."""
318
318
  return data.value
319
319
 
320
- async def save(self, db: InfrahubDatabase, at: Optional[Timestamp] = None) -> AttributeChangelog | None:
320
+ async def save(self, db: InfrahubDatabase, at: Timestamp | None = None) -> AttributeChangelog | None:
321
321
  """Create or Update the Attribute in the database."""
322
322
 
323
323
  save_at = Timestamp(at)
@@ -327,7 +327,7 @@ class BaseAttribute(FlagPropertyMixin, NodePropertyMixin):
327
327
 
328
328
  return await self._update(at=save_at, db=db)
329
329
 
330
- async def delete(self, db: InfrahubDatabase, at: Optional[Timestamp] = None) -> AttributeChangelog | None:
330
+ async def delete(self, db: InfrahubDatabase, at: Timestamp | None = None) -> AttributeChangelog | None:
331
331
  if not self.db_id:
332
332
  return None
333
333
 
@@ -388,7 +388,7 @@ class BaseAttribute(FlagPropertyMixin, NodePropertyMixin):
388
388
 
389
389
  return changelog
390
390
 
391
- async def _update(self, db: InfrahubDatabase, at: Optional[Timestamp] = None) -> AttributeChangelog | None:
391
+ async def _update(self, db: InfrahubDatabase, at: Timestamp | None = None) -> AttributeChangelog | None:
392
392
  """Update the attribute in the database.
393
393
 
394
394
  Get the current value
@@ -497,10 +497,10 @@ class BaseAttribute(FlagPropertyMixin, NodePropertyMixin):
497
497
  async def to_graphql(
498
498
  self,
499
499
  db: InfrahubDatabase,
500
- fields: Optional[dict] = None,
501
- related_node_ids: Optional[set] = None,
500
+ fields: dict | None = None,
501
+ related_node_ids: set | None = None,
502
502
  filter_sensitive: bool = False,
503
- permissions: Optional[dict] = None,
503
+ permissions: dict | None = None,
504
504
  include_properties: bool = True,
505
505
  ) -> dict:
506
506
  """Generate GraphQL Payload for this attribute."""
@@ -677,7 +677,7 @@ class String(BaseAttribute):
677
677
 
678
678
 
679
679
  class StringOptional(String):
680
- value: Optional[str]
680
+ value: str | None
681
681
 
682
682
 
683
683
  class HashedPassword(BaseAttribute):
@@ -690,13 +690,13 @@ class HashedPassword(BaseAttribute):
690
690
 
691
691
 
692
692
  class HashedPasswordOptional(HashedPassword):
693
- value: Optional[str]
693
+ value: str | None
694
694
 
695
695
 
696
696
  class Integer(BaseAttribute):
697
697
  type = int
698
698
  value: int
699
- from_pool: Optional[str] = None
699
+ from_pool: str | None = None
700
700
 
701
701
  @classmethod
702
702
  def validate_format(cls, value: Any, name: str, schema: AttributeSchema) -> None:
@@ -715,7 +715,7 @@ class Integer(BaseAttribute):
715
715
 
716
716
 
717
717
  class IntegerOptional(Integer):
718
- value: Optional[int]
718
+ value: int | None
719
719
 
720
720
 
721
721
  class Boolean(BaseAttribute):
@@ -724,7 +724,7 @@ class Boolean(BaseAttribute):
724
724
 
725
725
 
726
726
  class BooleanOptional(Boolean):
727
- value: Optional[bool]
727
+ value: bool | None
728
728
 
729
729
 
730
730
  class DateTime(BaseAttribute):
@@ -745,7 +745,7 @@ class DateTime(BaseAttribute):
745
745
 
746
746
 
747
747
  class DateTimeOptional(DateTime):
748
- value: Optional[str]
748
+ value: str | None
749
749
 
750
750
 
751
751
  class Dropdown(BaseAttribute):
@@ -792,7 +792,7 @@ class Dropdown(BaseAttribute):
792
792
 
793
793
 
794
794
  class DropdownOptional(Dropdown):
795
- value: Optional[str]
795
+ value: str | None
796
796
 
797
797
 
798
798
  class URL(BaseAttribute):
@@ -808,7 +808,7 @@ class URL(BaseAttribute):
808
808
 
809
809
 
810
810
  class URLOptional(URL):
811
- value: Optional[str]
811
+ value: str | None
812
812
 
813
813
 
814
814
  class IPNetwork(BaseAttribute):
@@ -820,35 +820,35 @@ class IPNetwork(BaseAttribute):
820
820
  return ["value", "version", "binary_address", "prefixlen"]
821
821
 
822
822
  @property
823
- def obj(self) -> Union[ipaddress.IPv4Network, ipaddress.IPv6Network]:
823
+ def obj(self) -> ipaddress.IPv4Network | ipaddress.IPv6Network:
824
824
  """Return an ipaddress interface object."""
825
825
  if not self.value:
826
826
  raise ValueError("value for IPNetwork must be defined")
827
827
  return ipaddress.ip_network(str(self.value))
828
828
 
829
829
  @property
830
- def broadcast_address(self) -> Optional[str]:
830
+ def broadcast_address(self) -> str | None:
831
831
  """Return the broadcast address of the ip network."""
832
832
  if not self.value:
833
833
  return None
834
834
  return str(self.obj.broadcast_address)
835
835
 
836
836
  @property
837
- def hostmask(self) -> Optional[str]:
837
+ def hostmask(self) -> str | None:
838
838
  """Return the hostmask of the ip network."""
839
839
  if not self.value:
840
840
  return None
841
841
  return str(self.obj.hostmask)
842
842
 
843
843
  @property
844
- def netmask(self) -> Optional[str]:
844
+ def netmask(self) -> str | None:
845
845
  """Return the netmask of the ip network."""
846
846
  if not self.value:
847
847
  return None
848
848
  return str(self.obj.netmask)
849
849
 
850
850
  @property
851
- def network_address(self) -> Optional[str]:
851
+ def network_address(self) -> str | None:
852
852
  """Return the netmask of the ip network."""
853
853
  if not self.value:
854
854
  return None
@@ -865,35 +865,35 @@ class IPNetwork(BaseAttribute):
865
865
  return convert_ip_to_binary_str(obj=self.obj)
866
866
 
867
867
  @property
868
- def prefixlen(self) -> Optional[int]:
868
+ def prefixlen(self) -> int | None:
869
869
  """Return the prefix length the ip network."""
870
870
  if not self.value:
871
871
  return None
872
872
  return ipaddress.ip_network(str(self.value)).prefixlen
873
873
 
874
874
  @property
875
- def num_addresses(self) -> Optional[int]:
875
+ def num_addresses(self) -> int | None:
876
876
  """Return the number of possible addresses in the ip network."""
877
877
  if not self.value:
878
878
  return None
879
879
  return ipaddress.ip_network(str(self.value)).num_addresses
880
880
 
881
881
  @property
882
- def version(self) -> Optional[int]:
882
+ def version(self) -> int | None:
883
883
  """Return the IP version of the ip network."""
884
884
  if not self.value:
885
885
  return None
886
886
  return ipaddress.ip_network(str(self.value)).version
887
887
 
888
888
  @property
889
- def with_hostmask(self) -> Optional[str]:
889
+ def with_hostmask(self) -> str | None:
890
890
  """Return the network ip and the associated hostmask of the ip network."""
891
891
  if not self.value:
892
892
  return None
893
893
  return ipaddress.ip_network(str(self.value)).with_hostmask
894
894
 
895
895
  @property
896
- def with_netmask(self) -> Optional[str]:
896
+ def with_netmask(self) -> str | None:
897
897
  """Return the network ip and the associated netmask of the ip network."""
898
898
  if not self.value:
899
899
  return None
@@ -941,7 +941,7 @@ class IPNetwork(BaseAttribute):
941
941
 
942
942
 
943
943
  class IPNetworkOptional(IPNetwork):
944
- value: Optional[str]
944
+ value: str | None
945
945
 
946
946
 
947
947
  class IPHost(BaseAttribute):
@@ -953,63 +953,63 @@ class IPHost(BaseAttribute):
953
953
  return ["value", "version", "binary_address"]
954
954
 
955
955
  @property
956
- def obj(self) -> Union[ipaddress.IPv4Interface, ipaddress.IPv6Interface]:
956
+ def obj(self) -> ipaddress.IPv4Interface | ipaddress.IPv6Interface:
957
957
  """Return the ip adress without a prefix or subnet mask."""
958
958
  if not self.value:
959
959
  raise ValueError("value for IPHost must be defined")
960
960
  return ipaddress.ip_interface(str(self.value))
961
961
 
962
962
  @property
963
- def ip(self) -> Optional[str]:
963
+ def ip(self) -> str | None:
964
964
  """Return the ip adress without a prefix or subnet mask."""
965
965
  if not self.value:
966
966
  return None
967
967
  return str(self.obj.ip)
968
968
 
969
969
  @property
970
- def hostmask(self) -> Optional[str]:
970
+ def hostmask(self) -> str | None:
971
971
  """Return the hostmask of the ip address."""
972
972
  if not self.value:
973
973
  return None
974
974
  return str(self.obj.hostmask)
975
975
 
976
976
  @property
977
- def netmask(self) -> Optional[str]:
977
+ def netmask(self) -> str | None:
978
978
  """Return the netmask of the ip address."""
979
979
  if not self.value:
980
980
  return None
981
981
  return str(self.obj.netmask)
982
982
 
983
983
  @property
984
- def network(self) -> Optional[str]:
984
+ def network(self) -> str | None:
985
985
  """Return the network encapsuling the ip address."""
986
986
  if not self.value:
987
987
  return None
988
988
  return str(self.obj.network)
989
989
 
990
990
  @property
991
- def prefixlen(self) -> Optional[int]:
991
+ def prefixlen(self) -> int | None:
992
992
  """Return the prefix length of the ip address."""
993
993
  if not self.value:
994
994
  return None
995
995
  return self.obj.network.prefixlen
996
996
 
997
997
  @property
998
- def version(self) -> Optional[int]:
998
+ def version(self) -> int | None:
999
999
  """Return the IP version of the ip address."""
1000
1000
  if not self.value:
1001
1001
  return None
1002
1002
  return self.obj.version
1003
1003
 
1004
1004
  @property
1005
- def with_hostmask(self) -> Optional[str]:
1005
+ def with_hostmask(self) -> str | None:
1006
1006
  """Return the ip address and the associated hostmask of the ip address."""
1007
1007
  if not self.value:
1008
1008
  return None
1009
1009
  return self.obj.with_hostmask
1010
1010
 
1011
1011
  @property
1012
- def with_netmask(self) -> Optional[str]:
1012
+ def with_netmask(self) -> str | None:
1013
1013
  """Return the ip address and the associated netmask of the ip address."""
1014
1014
  if not self.value:
1015
1015
  return None
@@ -1066,7 +1066,7 @@ class IPHost(BaseAttribute):
1066
1066
 
1067
1067
 
1068
1068
  class IPHostOptional(IPHost):
1069
- value: Optional[str]
1069
+ value: str | None
1070
1070
 
1071
1071
 
1072
1072
  class MacAddress(BaseAttribute):
@@ -1081,7 +1081,7 @@ class MacAddress(BaseAttribute):
1081
1081
  return netaddr.EUI(addr=self.value)
1082
1082
 
1083
1083
  @property
1084
- def oui(self) -> Optional[str]:
1084
+ def oui(self) -> str | None:
1085
1085
  """Return the OUI (Organisationally Unique Identifier) for the MAC address."""
1086
1086
  if not self.value:
1087
1087
  return None
@@ -1093,58 +1093,58 @@ class MacAddress(BaseAttribute):
1093
1093
  return str(self.obj).removesuffix(f"-{self.ei}")
1094
1094
 
1095
1095
  @property
1096
- def ei(self) -> Optional[str]:
1096
+ def ei(self) -> str | None:
1097
1097
  """Return the EI (Extension Identifier) for the MAC address."""
1098
1098
  if not self.value:
1099
1099
  return None
1100
1100
  return self.obj.ei
1101
1101
 
1102
1102
  @property
1103
- def version(self) -> Optional[int]:
1103
+ def version(self) -> int | None:
1104
1104
  """Return the version of the MAC address."""
1105
1105
  if not self.value:
1106
1106
  return None
1107
1107
  return self.obj.version
1108
1108
 
1109
1109
  @property
1110
- def binary(self) -> Optional[str]:
1110
+ def binary(self) -> str | None:
1111
1111
  """Return the MAC address in binary format."""
1112
1112
  if not self.value:
1113
1113
  return None
1114
1114
  return self.obj.bin
1115
1115
 
1116
1116
  @property
1117
- def eui48(self) -> Optional[str]:
1117
+ def eui48(self) -> str | None:
1118
1118
  if not self.value:
1119
1119
  return None
1120
1120
  return self.obj.format(dialect=netaddr.mac_eui48)
1121
1121
 
1122
1122
  @property
1123
- def eui64(self) -> Optional[str]:
1123
+ def eui64(self) -> str | None:
1124
1124
  if not self.value:
1125
1125
  return None
1126
1126
  return str(self.obj.eui64())
1127
1127
 
1128
1128
  @property
1129
- def bare(self) -> Optional[str]:
1129
+ def bare(self) -> str | None:
1130
1130
  if not self.value:
1131
1131
  return None
1132
1132
  return self.obj.format(dialect=netaddr.mac_bare)
1133
1133
 
1134
1134
  @property
1135
- def dot_notation(self) -> Optional[str]:
1135
+ def dot_notation(self) -> str | None:
1136
1136
  if not self.value:
1137
1137
  return None
1138
1138
  return self.obj.format(dialect=netaddr.mac_cisco)
1139
1139
 
1140
1140
  @property
1141
- def semicolon_notation(self) -> Optional[str]:
1141
+ def semicolon_notation(self) -> str | None:
1142
1142
  if not self.value:
1143
1143
  return None
1144
1144
  return self.obj.format(dialect=netaddr.mac_unix)
1145
1145
 
1146
1146
  @property
1147
- def split_notation(self) -> Optional[str]:
1147
+ def split_notation(self) -> str | None:
1148
1148
  if not self.value:
1149
1149
  return None
1150
1150
  return self.obj.format(dialect=netaddr.mac_pgsql)
@@ -1172,7 +1172,7 @@ class MacAddress(BaseAttribute):
1172
1172
 
1173
1173
 
1174
1174
  class MacAddressOptional(MacAddress):
1175
- value: Optional[str]
1175
+ value: str | None
1176
1176
 
1177
1177
 
1178
1178
  class ListAttribute(BaseAttribute):
@@ -1208,12 +1208,12 @@ class ListAttribute(BaseAttribute):
1208
1208
 
1209
1209
 
1210
1210
  class ListAttributeOptional(ListAttribute):
1211
- value: Optional[list[Any]]
1211
+ value: list[Any] | None
1212
1212
 
1213
1213
 
1214
1214
  class JSONAttribute(BaseAttribute):
1215
1215
  type = (dict, list)
1216
- value: Union[dict, list]
1216
+ value: dict | list
1217
1217
 
1218
1218
  @classmethod
1219
1219
  def deserialize_from_string(cls, value_as_string: str) -> Any:
@@ -1244,4 +1244,4 @@ class JSONAttribute(BaseAttribute):
1244
1244
 
1245
1245
 
1246
1246
  class JSONAttributeOptional(JSONAttribute):
1247
- value: Optional[Union[dict, list]]
1247
+ value: dict | list | None
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from typing import Any
4
+ from uuid import uuid4
4
5
 
5
6
  import pydantic
6
7
  from prefect import flow, get_run_logger
@@ -11,23 +12,24 @@ from infrahub import lock
11
12
  from infrahub.context import InfrahubContext # noqa: TC001 needed for prefect flow
12
13
  from infrahub.core import registry
13
14
  from infrahub.core.branch import Branch
14
- from infrahub.core.changelog.diff import DiffChangelogCollector
15
+ from infrahub.core.changelog.diff import DiffChangelogCollector, MigrationTracker
15
16
  from infrahub.core.constants import MutationAction
16
17
  from infrahub.core.diff.coordinator import DiffCoordinator
17
18
  from infrahub.core.diff.ipam_diff_parser import IpamDiffParser
18
19
  from infrahub.core.diff.merger.merger import DiffMerger
19
- from infrahub.core.diff.model.path import BranchTrackingId
20
+ from infrahub.core.diff.model.path import BranchTrackingId, EnrichedDiffRoot, EnrichedDiffRootMetadata
20
21
  from infrahub.core.diff.repository.repository import DiffRepository
21
22
  from infrahub.core.merge import BranchMerger
22
23
  from infrahub.core.migrations.schema.models import SchemaApplyMigrationData
23
24
  from infrahub.core.migrations.schema.tasks import schema_apply_migrations
25
+ from infrahub.core.timestamp import Timestamp
24
26
  from infrahub.core.validators.determiner import ConstraintValidatorDeterminer
25
27
  from infrahub.core.validators.models.validate_migration import SchemaValidateMigrationData
26
28
  from infrahub.core.validators.tasks import schema_validate_migrations
27
29
  from infrahub.dependencies.registry import get_component_registry
28
30
  from infrahub.events.branch_action import BranchCreatedEvent, BranchDeletedEvent, BranchMergedEvent, BranchRebasedEvent
29
31
  from infrahub.events.models import EventMeta, InfrahubEvent
30
- from infrahub.events.node_action import NodeMutatedEvent
32
+ from infrahub.events.node_action import get_node_event
31
33
  from infrahub.exceptions import BranchNotFoundError, MergeFailedError, ValidationError
32
34
  from infrahub.graphql.mutations.models import BranchCreateModel # noqa: TC001
33
35
  from infrahub.log import get_log_data
@@ -44,7 +46,7 @@ from infrahub.workflows.utils import add_tags
44
46
 
45
47
 
46
48
  @flow(name="branch-rebase", flow_run_name="Rebase branch {branch}")
47
- async def rebase_branch(branch: str, context: InfrahubContext, service: InfrahubServices) -> None:
49
+ async def rebase_branch(branch: str, context: InfrahubContext, service: InfrahubServices) -> None: # noqa: PLR0915
48
50
  async with service.database.start_session() as db:
49
51
  log = get_run_logger()
50
52
  await add_tags(branches=[branch])
@@ -54,6 +56,7 @@ async def rebase_branch(branch: str, context: InfrahubContext, service: Infrahub
54
56
  diff_repository = await component_registry.get_component(DiffRepository, db=db, branch=obj)
55
57
  diff_coordinator = await component_registry.get_component(DiffCoordinator, db=db, branch=obj)
56
58
  diff_merger = await component_registry.get_component(DiffMerger, db=db, branch=obj)
59
+ initial_from_time = Timestamp(obj.get_branched_from())
57
60
  merger = BranchMerger(
58
61
  db=db,
59
62
  diff_coordinator=diff_coordinator,
@@ -62,7 +65,7 @@ async def rebase_branch(branch: str, context: InfrahubContext, service: Infrahub
62
65
  source_branch=obj,
63
66
  service=service,
64
67
  )
65
- diff_repository = await component_registry.get_component(DiffRepository, db=db, branch=obj)
68
+
66
69
  enriched_diff_metadata = await diff_coordinator.update_branch_diff(base_branch=base_branch, diff_branch=obj)
67
70
  async for _ in diff_repository.get_all_conflicts_for_diff(
68
71
  diff_branch_name=enriched_diff_metadata.diff_branch_name, diff_id=enriched_diff_metadata.uuid
@@ -97,7 +100,7 @@ async def rebase_branch(branch: str, context: InfrahubContext, service: Infrahub
97
100
  raise ValidationError(",\n".join(error_messages))
98
101
 
99
102
  schema_in_main_before = merger.destination_schema.duplicate()
100
-
103
+ migrations = []
101
104
  async with lock.registry.global_graph_lock():
102
105
  async with db.start_transaction() as dbt:
103
106
  await obj.rebase(db=dbt)
@@ -134,6 +137,14 @@ async def rebase_branch(branch: str, context: InfrahubContext, service: Infrahub
134
137
  for error in errors:
135
138
  log.error(error)
136
139
 
140
+ default_branch_diff = await _get_diff_root(
141
+ diff_coordinator=diff_coordinator,
142
+ enriched_diff_metadata=enriched_diff_metadata,
143
+ diff_repository=diff_repository,
144
+ base_branch=base_branch,
145
+ target_from=initial_from_time,
146
+ )
147
+
137
148
  # -------------------------------------------------------------
138
149
  # Trigger the reconciliation of IPAM data after the rebase
139
150
  # -------------------------------------------------------------
@@ -156,16 +167,32 @@ async def rebase_branch(branch: str, context: InfrahubContext, service: Infrahub
156
167
  # -------------------------------------------------------------
157
168
  # Generate an event to indicate that a branch has been rebased
158
169
  # -------------------------------------------------------------
159
- # TODO Add account information
160
- await service.event.send(
161
- event=BranchRebasedEvent(
162
- branch_name=obj.name, branch_id=str(obj.uuid), meta=EventMeta(branch=obj, context=context)
163
- )
170
+ rebase_event = BranchRebasedEvent(
171
+ branch_name=obj.name, branch_id=str(obj.uuid), meta=EventMeta(branch=obj, context=context)
172
+ )
173
+ events: list[InfrahubEvent] = [rebase_event]
174
+ changelog_collector = DiffChangelogCollector(
175
+ diff=default_branch_diff, branch=obj, db=db, migration_tracker=MigrationTracker(migrations=migrations)
164
176
  )
177
+ for action, node_changelog in changelog_collector.collect_changelogs():
178
+ node_event_class = get_node_event(MutationAction.from_diff_action(diff_action=action))
179
+ mutate_event = node_event_class(
180
+ kind=node_changelog.node_kind,
181
+ node_id=node_changelog.node_id,
182
+ changelog=node_changelog,
183
+ fields=node_changelog.updated_fields,
184
+ meta=EventMeta.from_parent(parent=rebase_event, branch=obj),
185
+ )
186
+ events.append(mutate_event)
187
+
188
+ for event in events:
189
+ await service.event.send(event)
165
190
 
166
191
 
167
192
  @flow(name="branch-merge", flow_run_name="Merge branch {branch} into main")
168
- async def merge_branch(branch: str, context: InfrahubContext, service: InfrahubServices) -> None:
193
+ async def merge_branch(
194
+ branch: str, context: InfrahubContext, service: InfrahubServices, proposed_change_id: str | None = None
195
+ ) -> None:
169
196
  async with service.database.start_session() as db:
170
197
  log = get_run_logger()
171
198
 
@@ -174,7 +201,12 @@ async def merge_branch(branch: str, context: InfrahubContext, service: InfrahubS
174
201
  obj = await Branch.get_by_name(db=db, name=branch)
175
202
  default_branch = await registry.get_branch(db=db, branch=registry.default_branch)
176
203
  component_registry = get_component_registry()
177
- merge_event = BranchMergedEvent(meta=EventMeta.from_context(context=context, branch=obj))
204
+ merge_event = BranchMergedEvent(
205
+ branch_name=obj.name,
206
+ branch_id=str(obj.get_uuid()),
207
+ proposed_change_id=proposed_change_id,
208
+ meta=EventMeta.from_context(context=context, branch=registry.get_global_branch()),
209
+ )
178
210
 
179
211
  merger: BranchMerger | None = None
180
212
  async with lock.registry.global_graph_lock():
@@ -252,16 +284,15 @@ async def merge_branch(branch: str, context: InfrahubContext, service: InfrahubS
252
284
  events: list[InfrahubEvent] = [merge_event]
253
285
 
254
286
  for action, node_changelog in node_events:
255
- meta = EventMeta.from_parent(parent=merge_event)
256
- mutate_event = NodeMutatedEvent(
287
+ meta = EventMeta.from_parent(parent=merge_event, branch=default_branch)
288
+ node_event_class = get_node_event(MutationAction.from_diff_action(diff_action=action))
289
+ mutate_event = node_event_class(
257
290
  kind=node_changelog.node_kind,
258
291
  node_id=node_changelog.node_id,
259
- data=node_changelog,
260
- action=MutationAction.from_diff_action(diff_action=action),
292
+ changelog=node_changelog,
261
293
  fields=node_changelog.updated_fields,
262
294
  meta=meta,
263
295
  )
264
- mutate_event.set_context_branch(branch=default_branch)
265
296
  events.append(mutate_event)
266
297
 
267
298
  for event in events:
@@ -280,7 +311,7 @@ async def delete_branch(branch: str, context: InfrahubContext, service: Infrahub
280
311
  branch_name=branch,
281
312
  branch_id=str(obj.uuid),
282
313
  sync_with_git=obj.sync_with_git,
283
- meta=EventMeta(branch=obj, context=context),
314
+ meta=EventMeta.from_context(context=context, branch=registry.get_global_branch()),
284
315
  )
285
316
 
286
317
  await service.workflow.submit_workflow(
@@ -348,9 +379,7 @@ async def create_branch(model: BranchCreateModel, context: InfrahubContext, serv
348
379
  branch_name=obj.name,
349
380
  branch_id=str(obj.uuid),
350
381
  sync_with_git=obj.sync_with_git,
351
- meta=EventMeta(
352
- branch=obj, account_id=context.account.account_id, initiator_id=WORKER_IDENTITY, context=context
353
- ),
382
+ meta=EventMeta.from_context(context=context, branch=registry.get_global_branch()),
354
383
  )
355
384
  await service.event.send(event=event)
356
385
 
@@ -360,3 +389,26 @@ async def create_branch(model: BranchCreateModel, context: InfrahubContext, serv
360
389
  context=context,
361
390
  parameters={"branch": obj.name, "branch_id": str(obj.uuid)},
362
391
  )
392
+
393
+
394
+ async def _get_diff_root(
395
+ diff_coordinator: DiffCoordinator,
396
+ enriched_diff_metadata: EnrichedDiffRootMetadata,
397
+ diff_repository: DiffRepository,
398
+ base_branch: Branch,
399
+ target_from: Timestamp,
400
+ ) -> EnrichedDiffRoot:
401
+ default_branch_diff = await diff_coordinator.create_or_update_arbitrary_timeframe_diff(
402
+ base_branch=base_branch,
403
+ diff_branch=base_branch,
404
+ from_time=target_from,
405
+ to_time=enriched_diff_metadata.to_time,
406
+ name=str(uuid4()),
407
+ )
408
+ # make sure we have the actual diff with data and not just the metadata
409
+ if not isinstance(default_branch_diff, EnrichedDiffRoot):
410
+ default_branch_diff = await diff_repository.get_one(
411
+ diff_branch_name=base_branch.name, diff_id=default_branch_diff.uuid
412
+ )
413
+
414
+ return default_branch_diff