infrahub-server 1.1.7__py3-none-any.whl → 1.2.0b1__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 (399) hide show
  1. infrahub/api/artifact.py +16 -4
  2. infrahub/api/dependencies.py +8 -0
  3. infrahub/api/oauth2.py +0 -1
  4. infrahub/api/oidc.py +0 -1
  5. infrahub/api/query.py +18 -7
  6. infrahub/api/schema.py +32 -6
  7. infrahub/api/transformation.py +12 -5
  8. infrahub/{message_bus/messages/check_artifact_create.py → artifacts/models.py} +5 -3
  9. infrahub/{message_bus/operations/check/artifact.py → artifacts/tasks.py} +26 -25
  10. infrahub/cli/__init__.py +0 -2
  11. infrahub/cli/db.py +6 -7
  12. infrahub/cli/events.py +8 -3
  13. infrahub/cli/git_agent.py +9 -7
  14. infrahub/cli/tasks.py +4 -6
  15. infrahub/computed_attribute/models.py +1 -1
  16. infrahub/computed_attribute/tasks.py +64 -17
  17. infrahub/computed_attribute/triggers.py +90 -0
  18. infrahub/config.py +1 -1
  19. infrahub/context.py +39 -0
  20. infrahub/core/account.py +5 -8
  21. infrahub/core/attribute.py +50 -21
  22. infrahub/core/branch/models.py +4 -4
  23. infrahub/core/branch/tasks.py +130 -125
  24. infrahub/core/changelog/__init__.py +0 -0
  25. infrahub/core/changelog/diff.py +283 -0
  26. infrahub/core/changelog/models.py +499 -0
  27. infrahub/core/constants/__init__.py +43 -2
  28. infrahub/core/constants/infrahubkind.py +1 -0
  29. infrahub/core/constants/schema.py +2 -0
  30. infrahub/core/diff/combiner.py +1 -1
  31. infrahub/core/diff/enricher/cardinality_one.py +6 -1
  32. infrahub/core/diff/enricher/hierarchy.py +22 -7
  33. infrahub/core/diff/enricher/labels.py +6 -1
  34. infrahub/core/diff/enricher/path_identifier.py +5 -1
  35. infrahub/core/diff/enricher/summary_counts.py +107 -0
  36. infrahub/core/diff/merger/merger.py +3 -1
  37. infrahub/core/diff/model/path.py +34 -11
  38. infrahub/core/diff/parent_node_adder.py +78 -0
  39. infrahub/core/diff/payload_builder.py +13 -2
  40. infrahub/core/diff/query/all_conflicts.py +1 -1
  41. infrahub/core/diff/query/artifact.py +1 -1
  42. infrahub/core/diff/query/delete_query.py +1 -1
  43. infrahub/core/diff/query/diff_get.py +1 -1
  44. infrahub/core/diff/query/diff_summary.py +1 -1
  45. infrahub/core/diff/query/field_specifiers.py +1 -1
  46. infrahub/core/diff/query/field_summary.py +1 -1
  47. infrahub/core/diff/query/filters.py +2 -2
  48. infrahub/core/diff/query/get_conflict_query.py +1 -1
  49. infrahub/core/diff/query/has_conflicts_query.py +1 -1
  50. infrahub/core/diff/query/merge.py +3 -3
  51. infrahub/core/diff/query/merge_tracking_id.py +1 -1
  52. infrahub/core/diff/query/roots_metadata.py +1 -1
  53. infrahub/core/diff/query/save.py +191 -185
  54. infrahub/core/diff/query/summary_counts_enricher.py +52 -5
  55. infrahub/core/diff/query/time_range_query.py +1 -1
  56. infrahub/core/diff/query/update_conflict_query.py +1 -1
  57. infrahub/core/diff/repository/deserializer.py +9 -4
  58. infrahub/core/diff/repository/repository.py +156 -38
  59. infrahub/core/diff/tasks.py +13 -12
  60. infrahub/core/enums.py +1 -1
  61. infrahub/core/graph/__init__.py +1 -1
  62. infrahub/core/graph/index.py +3 -0
  63. infrahub/core/integrity/object_conflict/conflict_recorder.py +1 -1
  64. infrahub/core/ipam/reconciler.py +1 -1
  65. infrahub/core/ipam/tasks.py +2 -3
  66. infrahub/core/manager.py +20 -15
  67. infrahub/core/merge.py +5 -2
  68. infrahub/core/migrations/graph/__init__.py +4 -0
  69. infrahub/core/migrations/graph/m001_add_version_to_graph.py +1 -1
  70. infrahub/core/migrations/graph/m002_attribute_is_default.py +2 -2
  71. infrahub/core/migrations/graph/m003_relationship_parent_optional.py +2 -2
  72. infrahub/core/migrations/graph/m004_add_attr_documentation.py +1 -1
  73. infrahub/core/migrations/graph/m005_add_rel_read_only.py +1 -1
  74. infrahub/core/migrations/graph/m006_add_rel_on_delete.py +1 -1
  75. infrahub/core/migrations/graph/m007_add_rel_allow_override.py +1 -1
  76. infrahub/core/migrations/graph/m008_add_human_friendly_id.py +1 -1
  77. infrahub/core/migrations/graph/m009_add_generate_profile_attr.py +1 -1
  78. infrahub/core/migrations/graph/m010_add_generate_profile_attr_generic.py +1 -1
  79. infrahub/core/migrations/graph/m011_remove_profile_relationship_schema.py +2 -2
  80. infrahub/core/migrations/graph/m012_convert_account_generic.py +12 -23
  81. infrahub/core/migrations/graph/m013_convert_git_password_credential.py +7 -11
  82. infrahub/core/migrations/graph/m014_remove_index_attr_value.py +2 -2
  83. infrahub/core/migrations/graph/m015_diff_format_update.py +1 -1
  84. infrahub/core/migrations/graph/m016_diff_delete_bug_fix.py +1 -1
  85. infrahub/core/migrations/graph/m017_add_core_profile.py +1 -1
  86. infrahub/core/migrations/graph/m018_uniqueness_nulls.py +2 -2
  87. infrahub/core/migrations/graph/m019_restore_rels_to_time.py +256 -0
  88. infrahub/core/migrations/graph/m020_add_generate_template_attr.py +48 -0
  89. infrahub/core/migrations/query/attribute_add.py +1 -1
  90. infrahub/core/migrations/query/attribute_rename.py +1 -1
  91. infrahub/core/migrations/query/delete_element_in_schema.py +1 -1
  92. infrahub/core/migrations/query/node_duplicate.py +39 -19
  93. infrahub/core/migrations/query/relationship_duplicate.py +1 -1
  94. infrahub/core/migrations/query/schema_attribute_update.py +1 -1
  95. infrahub/core/migrations/schema/node_attribute_remove.py +1 -1
  96. infrahub/core/migrations/schema/node_remove.py +27 -13
  97. infrahub/core/migrations/schema/tasks.py +5 -5
  98. infrahub/core/migrations/shared.py +4 -4
  99. infrahub/core/models.py +7 -8
  100. infrahub/core/node/__init__.py +164 -45
  101. infrahub/core/node/base.py +1 -1
  102. infrahub/core/node/delete_validator.py +4 -4
  103. infrahub/core/node/ipam.py +7 -7
  104. infrahub/core/node/resource_manager/ip_prefix_pool.py +8 -5
  105. infrahub/core/node/standard.py +3 -5
  106. infrahub/core/property.py +1 -1
  107. infrahub/core/protocols.py +6 -0
  108. infrahub/core/protocols_base.py +4 -2
  109. infrahub/core/query/__init__.py +2 -5
  110. infrahub/core/query/attribute.py +9 -9
  111. infrahub/core/query/branch.py +5 -5
  112. infrahub/core/query/delete.py +1 -1
  113. infrahub/core/query/diff.py +4 -4
  114. infrahub/core/query/ipam.py +4 -4
  115. infrahub/core/query/node.py +11 -12
  116. infrahub/core/query/relationship.py +211 -25
  117. infrahub/core/query/resource_manager.py +10 -10
  118. infrahub/core/query/standard_node.py +6 -6
  119. infrahub/core/query/task.py +3 -3
  120. infrahub/core/query/task_log.py +1 -1
  121. infrahub/core/query/utils.py +5 -5
  122. infrahub/core/registry.py +0 -2
  123. infrahub/core/relationship/constraints/count.py +1 -1
  124. infrahub/core/relationship/constraints/peer_kind.py +1 -1
  125. infrahub/core/relationship/model.py +76 -38
  126. infrahub/core/schema/__init__.py +6 -4
  127. infrahub/core/schema/attribute_schema.py +8 -0
  128. infrahub/core/schema/basenode_schema.py +13 -3
  129. infrahub/core/schema/definitions/core/__init__.py +153 -0
  130. infrahub/core/schema/definitions/core/account.py +168 -0
  131. infrahub/core/schema/definitions/core/artifact.py +127 -0
  132. infrahub/core/schema/definitions/core/builtin.py +21 -0
  133. infrahub/core/schema/definitions/core/check.py +60 -0
  134. infrahub/core/schema/definitions/core/generator.py +96 -0
  135. infrahub/core/schema/definitions/core/graphql_query.py +77 -0
  136. infrahub/core/schema/definitions/core/group.py +105 -0
  137. infrahub/core/schema/definitions/core/ipam.py +252 -0
  138. infrahub/core/schema/definitions/core/lineage.py +17 -0
  139. infrahub/core/schema/definitions/core/menu.py +46 -0
  140. infrahub/core/schema/definitions/core/permission.py +161 -0
  141. infrahub/core/schema/definitions/core/profile.py +29 -0
  142. infrahub/core/schema/definitions/core/propose_change.py +88 -0
  143. infrahub/core/schema/definitions/core/propose_change_comment.py +188 -0
  144. infrahub/core/schema/definitions/core/propose_change_validator.py +326 -0
  145. infrahub/core/schema/definitions/core/repository.py +280 -0
  146. infrahub/core/schema/definitions/core/resource_pool.py +180 -0
  147. infrahub/core/schema/definitions/core/template.py +12 -0
  148. infrahub/core/schema/definitions/core/transform.py +87 -0
  149. infrahub/core/schema/definitions/core/webhook.py +108 -0
  150. infrahub/core/schema/definitions/internal.py +16 -0
  151. infrahub/core/schema/generated/genericnode_schema.py +5 -0
  152. infrahub/core/schema/generated/node_schema.py +5 -0
  153. infrahub/core/schema/generic_schema.py +5 -1
  154. infrahub/core/schema/manager.py +45 -42
  155. infrahub/core/schema/node_schema.py +4 -0
  156. infrahub/core/schema/profile_schema.py +4 -0
  157. infrahub/core/schema/relationship_schema.py +10 -2
  158. infrahub/core/schema/schema_branch.py +260 -16
  159. infrahub/core/schema/template_schema.py +36 -0
  160. infrahub/core/task/user_task.py +7 -5
  161. infrahub/core/timestamp.py +3 -3
  162. infrahub/core/utils.py +2 -2
  163. infrahub/core/validators/attribute/choices.py +1 -1
  164. infrahub/core/validators/attribute/enum.py +1 -1
  165. infrahub/core/validators/attribute/kind.py +1 -1
  166. infrahub/core/validators/attribute/length.py +1 -1
  167. infrahub/core/validators/attribute/optional.py +1 -1
  168. infrahub/core/validators/attribute/regex.py +1 -1
  169. infrahub/core/validators/attribute/unique.py +1 -1
  170. infrahub/core/validators/checks_runner.py +37 -0
  171. infrahub/core/validators/node/generate_profile.py +1 -1
  172. infrahub/core/validators/node/hierarchy.py +1 -1
  173. infrahub/core/validators/query.py +1 -1
  174. infrahub/core/validators/relationship/count.py +1 -1
  175. infrahub/core/validators/relationship/optional.py +1 -1
  176. infrahub/core/validators/relationship/peer.py +1 -1
  177. infrahub/core/validators/tasks.py +8 -6
  178. infrahub/core/validators/uniqueness/query.py +1 -1
  179. infrahub/database/__init__.py +3 -2
  180. infrahub/database/memgraph.py +1 -1
  181. infrahub/dependencies/builder/diff/combiner.py +1 -1
  182. infrahub/dependencies/builder/diff/conflicts_enricher.py +1 -1
  183. infrahub/dependencies/builder/diff/deserializer.py +4 -2
  184. infrahub/dependencies/builder/diff/enricher/hierarchy.py +3 -1
  185. infrahub/dependencies/builder/diff/enricher/summary_counts.py +8 -0
  186. infrahub/dependencies/builder/diff/parent_node_adder.py +8 -0
  187. infrahub/events/artifact_action.py +76 -0
  188. infrahub/events/branch_action.py +50 -21
  189. infrahub/events/group_action.py +117 -0
  190. infrahub/events/models.py +164 -51
  191. infrahub/events/node_action.py +70 -8
  192. infrahub/events/repository_action.py +8 -8
  193. infrahub/events/schema_action.py +21 -8
  194. infrahub/exceptions.py +9 -0
  195. infrahub/generators/models.py +1 -0
  196. infrahub/generators/tasks.py +34 -15
  197. infrahub/git/base.py +3 -5
  198. infrahub/git/constants.py +0 -1
  199. infrahub/git/integrator.py +60 -36
  200. infrahub/git/models.py +80 -1
  201. infrahub/git/repository.py +7 -8
  202. infrahub/git/tasks.py +432 -112
  203. infrahub/git_credential/helper.py +2 -3
  204. infrahub/graphql/analyzer.py +572 -11
  205. infrahub/graphql/app.py +34 -26
  206. infrahub/graphql/auth/query_permission_checker/anonymous_checker.py +5 -5
  207. infrahub/graphql/auth/query_permission_checker/default_branch_checker.py +4 -4
  208. infrahub/graphql/auth/query_permission_checker/merge_operation_checker.py +4 -4
  209. infrahub/graphql/auth/query_permission_checker/object_permission_checker.py +28 -35
  210. infrahub/graphql/auth/query_permission_checker/super_admin_checker.py +5 -5
  211. infrahub/graphql/context.py +33 -0
  212. infrahub/graphql/enums.py +1 -1
  213. infrahub/graphql/initialization.py +5 -1
  214. infrahub/graphql/loaders/node.py +2 -2
  215. infrahub/graphql/manager.py +63 -63
  216. infrahub/graphql/mutations/account.py +20 -13
  217. infrahub/graphql/mutations/artifact_definition.py +16 -12
  218. infrahub/graphql/mutations/branch.py +86 -40
  219. infrahub/graphql/mutations/computed_attribute.py +24 -15
  220. infrahub/graphql/mutations/diff.py +33 -17
  221. infrahub/graphql/mutations/diff_conflict.py +14 -8
  222. infrahub/graphql/mutations/generator.py +83 -0
  223. infrahub/graphql/mutations/graphql_query.py +19 -11
  224. infrahub/graphql/mutations/ipam.py +25 -23
  225. infrahub/graphql/mutations/main.py +233 -45
  226. infrahub/graphql/mutations/menu.py +10 -10
  227. infrahub/graphql/mutations/proposed_change.py +36 -28
  228. infrahub/graphql/mutations/relationship.py +341 -130
  229. infrahub/graphql/mutations/repository.py +41 -35
  230. infrahub/graphql/mutations/resource_manager.py +26 -26
  231. infrahub/graphql/mutations/schema.py +66 -33
  232. infrahub/graphql/mutations/tasks.py +10 -7
  233. infrahub/graphql/parser.py +1 -1
  234. infrahub/graphql/permissions.py +3 -10
  235. infrahub/graphql/queries/account.py +22 -18
  236. infrahub/graphql/queries/branch.py +6 -4
  237. infrahub/graphql/queries/diff/tree.py +63 -52
  238. infrahub/graphql/queries/event.py +115 -0
  239. infrahub/graphql/queries/internal.py +3 -3
  240. infrahub/graphql/queries/ipam.py +23 -18
  241. infrahub/graphql/queries/relationship.py +11 -10
  242. infrahub/graphql/queries/resource_manager.py +37 -25
  243. infrahub/graphql/queries/search.py +9 -8
  244. infrahub/graphql/queries/status.py +12 -9
  245. infrahub/graphql/queries/task.py +11 -9
  246. infrahub/graphql/resolvers/resolver.py +69 -43
  247. infrahub/graphql/resolvers/single_relationship.py +16 -10
  248. infrahub/graphql/schema.py +4 -0
  249. infrahub/graphql/subscription/__init__.py +1 -1
  250. infrahub/graphql/subscription/events.py +1 -1
  251. infrahub/graphql/subscription/graphql_query.py +8 -8
  252. infrahub/graphql/types/branch.py +2 -2
  253. infrahub/graphql/types/common.py +6 -1
  254. infrahub/graphql/types/context.py +12 -0
  255. infrahub/graphql/types/enums.py +2 -0
  256. infrahub/graphql/types/event.py +158 -0
  257. infrahub/graphql/types/interface.py +2 -2
  258. infrahub/graphql/types/node.py +3 -3
  259. infrahub/graphql/types/permission.py +2 -2
  260. infrahub/graphql/types/relationship.py +3 -3
  261. infrahub/graphql/types/standard_node.py +9 -11
  262. infrahub/graphql/utils.py +28 -182
  263. infrahub/groups/tasks.py +2 -3
  264. infrahub/lock.py +21 -21
  265. infrahub/menu/generator.py +0 -1
  266. infrahub/menu/menu.py +116 -138
  267. infrahub/menu/models.py +4 -4
  268. infrahub/message_bus/__init__.py +11 -13
  269. infrahub/message_bus/messages/__init__.py +0 -14
  270. infrahub/message_bus/messages/check_generator_run.py +1 -3
  271. infrahub/message_bus/messages/event_branch_merge.py +3 -0
  272. infrahub/message_bus/messages/proposed_change/request_proposedchange_refreshartifacts.py +6 -0
  273. infrahub/message_bus/messages/request_proposedchange_pipeline.py +2 -0
  274. infrahub/message_bus/messages/send_echo_request.py +1 -1
  275. infrahub/message_bus/operations/__init__.py +4 -13
  276. infrahub/message_bus/operations/check/__init__.py +2 -2
  277. infrahub/message_bus/operations/check/generator.py +1 -3
  278. infrahub/message_bus/operations/event/branch.py +7 -3
  279. infrahub/message_bus/operations/event/schema.py +1 -1
  280. infrahub/message_bus/operations/event/worker.py +0 -3
  281. infrahub/message_bus/operations/finalize/validator.py +1 -1
  282. infrahub/message_bus/operations/git/file.py +2 -2
  283. infrahub/message_bus/operations/git/repository.py +1 -1
  284. infrahub/message_bus/operations/requests/__init__.py +0 -4
  285. infrahub/message_bus/operations/requests/generator_definition.py +2 -4
  286. infrahub/message_bus/operations/requests/proposed_change.py +37 -20
  287. infrahub/message_bus/operations/send/echo.py +1 -1
  288. infrahub/message_bus/types.py +1 -1
  289. infrahub/permissions/globals.py +15 -0
  290. infrahub/pools/prefix.py +29 -165
  291. infrahub/prefect_server/__init__.py +0 -0
  292. infrahub/prefect_server/app.py +18 -0
  293. infrahub/prefect_server/database.py +20 -0
  294. infrahub/prefect_server/events.py +28 -0
  295. infrahub/prefect_server/models.py +46 -0
  296. infrahub/proposed_change/models.py +18 -1
  297. infrahub/proposed_change/tasks.py +195 -53
  298. infrahub/pytest_plugin.py +4 -4
  299. infrahub/server.py +13 -12
  300. infrahub/services/__init__.py +148 -63
  301. infrahub/services/adapters/cache/__init__.py +11 -11
  302. infrahub/services/adapters/cache/nats.py +42 -25
  303. infrahub/services/adapters/cache/redis.py +3 -11
  304. infrahub/services/adapters/event/__init__.py +10 -18
  305. infrahub/services/adapters/http/__init__.py +0 -5
  306. infrahub/services/adapters/http/httpx.py +22 -15
  307. infrahub/services/adapters/message_bus/__init__.py +25 -8
  308. infrahub/services/adapters/message_bus/local.py +9 -7
  309. infrahub/services/adapters/message_bus/nats.py +14 -8
  310. infrahub/services/adapters/message_bus/rabbitmq.py +23 -10
  311. infrahub/services/adapters/workflow/__init__.py +11 -8
  312. infrahub/services/adapters/workflow/local.py +27 -6
  313. infrahub/services/adapters/workflow/worker.py +23 -7
  314. infrahub/services/component.py +43 -40
  315. infrahub/services/protocols.py +7 -7
  316. infrahub/services/scheduler.py +30 -29
  317. infrahub/storage.py +2 -4
  318. infrahub/task_manager/constants.py +1 -1
  319. infrahub/task_manager/event.py +261 -0
  320. infrahub/task_manager/models.py +147 -3
  321. infrahub/task_manager/task.py +1 -1
  322. infrahub/tasks/artifact.py +19 -18
  323. infrahub/tasks/registry.py +1 -1
  324. infrahub/tasks/telemetry.py +13 -14
  325. infrahub/transformations/tasks.py +3 -5
  326. infrahub/trigger/__init__.py +0 -0
  327. infrahub/trigger/catalogue.py +16 -0
  328. infrahub/trigger/constants.py +9 -0
  329. infrahub/trigger/models.py +105 -0
  330. infrahub/trigger/tasks.py +91 -0
  331. infrahub/types.py +1 -1
  332. infrahub/utils.py +1 -1
  333. infrahub/webhook/constants.py +0 -2
  334. infrahub/webhook/models.py +161 -40
  335. infrahub/webhook/tasks.py +123 -202
  336. infrahub/webhook/triggers.py +27 -0
  337. infrahub/workers/infrahub_async.py +36 -25
  338. infrahub/workers/utils.py +63 -0
  339. infrahub/workflows/catalogue.py +71 -52
  340. infrahub/workflows/initialization.py +14 -8
  341. infrahub/workflows/models.py +28 -4
  342. infrahub/workflows/utils.py +1 -1
  343. infrahub_sdk/batch.py +2 -2
  344. infrahub_sdk/client.py +8 -0
  345. infrahub_sdk/config.py +1 -1
  346. infrahub_sdk/ctl/branch.py +3 -2
  347. infrahub_sdk/ctl/check.py +4 -4
  348. infrahub_sdk/ctl/cli_commands.py +16 -11
  349. infrahub_sdk/ctl/exceptions.py +0 -6
  350. infrahub_sdk/ctl/exporter.py +1 -1
  351. infrahub_sdk/ctl/generator.py +5 -5
  352. infrahub_sdk/ctl/importer.py +3 -2
  353. infrahub_sdk/ctl/menu.py +1 -1
  354. infrahub_sdk/ctl/object.py +1 -1
  355. infrahub_sdk/ctl/repository.py +23 -15
  356. infrahub_sdk/ctl/schema.py +2 -2
  357. infrahub_sdk/ctl/utils.py +6 -21
  358. infrahub_sdk/ctl/validate.py +2 -1
  359. infrahub_sdk/data.py +1 -1
  360. infrahub_sdk/exceptions.py +12 -0
  361. infrahub_sdk/generator.py +3 -0
  362. infrahub_sdk/node.py +5 -8
  363. infrahub_sdk/protocols.py +20 -8
  364. infrahub_sdk/schema/__init__.py +14 -5
  365. infrahub_sdk/schema/main.py +7 -0
  366. infrahub_sdk/task/__init__.py +1 -0
  367. infrahub_sdk/task/constants.py +3 -0
  368. infrahub_sdk/task/exceptions.py +25 -0
  369. infrahub_sdk/task/manager.py +545 -0
  370. infrahub_sdk/task/models.py +74 -0
  371. infrahub_sdk/testing/docker.py +30 -0
  372. infrahub_sdk/timestamp.py +134 -33
  373. infrahub_sdk/transfer/exporter/json.py +1 -1
  374. infrahub_sdk/utils.py +39 -1
  375. infrahub_sdk/yaml.py +2 -3
  376. {infrahub_server-1.1.7.dist-info → infrahub_server-1.2.0b1.dist-info}/METADATA +7 -6
  377. {infrahub_server-1.1.7.dist-info → infrahub_server-1.2.0b1.dist-info}/RECORD +383 -339
  378. infrahub_testcontainers/container.py +2 -3
  379. infrahub_testcontainers/docker-compose.test.yml +2 -2
  380. infrahub/core/branch/constants.py +0 -2
  381. infrahub/core/schema/definitions/core.py +0 -2274
  382. infrahub/graphql/query.py +0 -52
  383. infrahub/message_bus/messages/check_repository_checkdefinition.py +0 -20
  384. infrahub/message_bus/messages/check_repository_mergeconflicts.py +0 -16
  385. infrahub/message_bus/messages/check_repository_usercheck.py +0 -26
  386. infrahub/message_bus/messages/request_artifactdefinition_check.py +0 -17
  387. infrahub/message_bus/messages/request_repository_checks.py +0 -12
  388. infrahub/message_bus/messages/request_repository_userchecks.py +0 -18
  389. infrahub/message_bus/operations/check/repository.py +0 -293
  390. infrahub/message_bus/operations/requests/artifact_definition.py +0 -148
  391. infrahub/message_bus/operations/requests/repository.py +0 -133
  392. infrahub/schema/constants.py +0 -1
  393. infrahub/schema/tasks.py +0 -76
  394. infrahub/services/adapters/database/__init__.py +0 -9
  395. infrahub_sdk/ctl/_file.py +0 -13
  396. /infrahub/{schema → artifacts}/__init__.py +0 -0
  397. {infrahub_server-1.1.7.dist-info → infrahub_server-1.2.0b1.dist-info}/LICENSE.txt +0 -0
  398. {infrahub_server-1.1.7.dist-info → infrahub_server-1.2.0b1.dist-info}/WHEEL +0 -0
  399. {infrahub_server-1.1.7.dist-info → infrahub_server-1.2.0b1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,499 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Any, Self, cast
4
+ from uuid import UUID
5
+
6
+ from pydantic import BaseModel, Field, PrivateAttr, computed_field, field_validator, model_validator
7
+
8
+ from infrahub.core.constants import NULL_VALUE, DiffAction, RelationshipCardinality, RelationshipKind
9
+
10
+ if TYPE_CHECKING:
11
+ from infrahub.core.attribute import BaseAttribute
12
+ from infrahub.core.branch import Branch
13
+ from infrahub.core.manager import RelationshipSchema
14
+ from infrahub.core.query.relationship import RelationshipPeerData
15
+ from infrahub.core.relationship.model import Relationship
16
+ from infrahub.database import InfrahubDatabase
17
+
18
+
19
+ class PropertyChangelog(BaseModel):
20
+ name: str = Field(..., description="The name of the property")
21
+ value: str | bool | None = Field(..., description="The updated or current value of the property")
22
+ value_previous: str | bool | None = Field(
23
+ ...,
24
+ description="The previous value of the property, a `null` value indicates that the property didn't previously have a value",
25
+ )
26
+
27
+ @computed_field
28
+ def value_type(self) -> str:
29
+ """The value_type of the property, used to help external systems"""
30
+ if isinstance(self.value, str):
31
+ return "Text"
32
+
33
+ return "Boolean"
34
+
35
+ @computed_field
36
+ def value_update_status(self) -> DiffAction:
37
+ """Indicate how the value was changed during this update"""
38
+ if self.value == self.value_previous:
39
+ return DiffAction.UNCHANGED
40
+ if self.value_previous is not None and self.value is None:
41
+ return DiffAction.REMOVED
42
+ if self.value_previous is None and self.value is not None:
43
+ return DiffAction.ADDED
44
+
45
+ return DiffAction.UPDATED
46
+
47
+
48
+ class AttributeChangelog(BaseModel):
49
+ name: str = Field(..., description="The name of the attribute")
50
+ value: Any = Field(default=None, description="The current value of the attribute")
51
+ value_previous: Any = Field(default=None, description="The previous value of the attribute")
52
+ properties: dict[str, PropertyChangelog] = Field(
53
+ default_factory=dict, description="The properties that were updated during this update"
54
+ )
55
+ kind: str = Field(..., description="The attribute kind")
56
+
57
+ @computed_field
58
+ def value_update_status(self) -> DiffAction:
59
+ """Indicate how the peer was changed during this update"""
60
+ if self.value == self.value_previous:
61
+ return DiffAction.UNCHANGED
62
+ if self.value_previous is not None and self.value is None:
63
+ return DiffAction.REMOVED
64
+ if self.value_previous is None and self.value is not None:
65
+ return DiffAction.ADDED
66
+
67
+ return DiffAction.UPDATED
68
+
69
+ def add_property(self, name: str, value_current: bool | str | None, value_previous: bool | str | None) -> None:
70
+ self.properties[name] = PropertyChangelog(name=name, value=value_current, value_previous=value_previous)
71
+
72
+ @property
73
+ def has_updates(self) -> bool:
74
+ if self.value_update_status != DiffAction.UNCHANGED or self.properties:
75
+ return True
76
+ return False
77
+
78
+ def set_value(self, value: Any) -> None:
79
+ if isinstance(value, str) and value == NULL_VALUE:
80
+ self.value = None
81
+ return
82
+ self.value = value
83
+
84
+ def set_value_previous(self, value: Any) -> None:
85
+ if isinstance(value, str) and value == NULL_VALUE:
86
+ self.value_previous = None
87
+ return
88
+ self.value_previous = value
89
+
90
+ @field_validator("value", "value_previous")
91
+ @classmethod
92
+ def convert_null_values(cls, value: Any) -> Any:
93
+ if isinstance(value, str) and value == NULL_VALUE:
94
+ return None
95
+ return value
96
+
97
+ @model_validator(mode="after")
98
+ def filter_sensitive(self) -> Self:
99
+ if self.kind in ["HashedPassword", "Password"]:
100
+ if self.value is not None:
101
+ self.value = "***"
102
+ if self.value_previous is not None:
103
+ self.value_previous = "***"
104
+
105
+ return self
106
+
107
+
108
+ class RelationshipCardinalityOneChangelog(BaseModel):
109
+ name: str = Field(..., description="The name of the relationship")
110
+ peer_id_previous: str | None = Field(default=None, description="The previous peer of this relationship")
111
+ peer_kind_previous: str | None = Field(default=None, description="The node kind of the previous peer")
112
+ peer_id: str | None = Field(default=None, description="The current peer of this relationship")
113
+ peer_kind: str | None = Field(default=None, description="The node kind of the current peer")
114
+ properties: dict[str, PropertyChangelog] = Field(
115
+ default_factory=dict, description="Changes to properties of this relationship if any were made"
116
+ )
117
+ _parent: ChangelogRelatedNode | None = PrivateAttr(default=None)
118
+
119
+ @property
120
+ def parent(self) -> ChangelogRelatedNode | None:
121
+ return self._parent
122
+
123
+ @computed_field
124
+ def cardinality(self) -> str:
125
+ return "one"
126
+
127
+ @computed_field
128
+ def peer_status(self) -> DiffAction:
129
+ """Indicate how the peer was changed during this update"""
130
+ if self.peer_id_previous == self.peer_id:
131
+ return DiffAction.UNCHANGED
132
+ if self.peer_id_previous and not self.peer_id:
133
+ return DiffAction.REMOVED
134
+ if self.peer_id and not self.peer_id_previous:
135
+ return DiffAction.ADDED
136
+ return DiffAction.UPDATED
137
+
138
+ def add_property(self, name: str, value_current: bool | str | None, value_previous: bool | str | None) -> None:
139
+ self.properties[name] = PropertyChangelog(name=name, value=value_current, value_previous=value_previous)
140
+
141
+ def set_parent(self, parent_id: str, parent_kind: str) -> None:
142
+ self._parent = ChangelogRelatedNode(node_id=parent_id, node_kind=parent_kind)
143
+
144
+ def set_parent_from_relationship(self, rel_kind: RelationshipKind) -> None:
145
+ if rel_kind == RelationshipKind.PARENT:
146
+ if (
147
+ self.peer_status in [DiffAction.ADDED, DiffAction.UNCHANGED, DiffAction.UPDATED]
148
+ and self.peer_id
149
+ and self.peer_kind
150
+ ):
151
+ self._parent = ChangelogRelatedNode(node_id=self.peer_id, node_kind=self.peer_kind)
152
+ elif self.peer_id_previous and self.peer_kind_previous:
153
+ self._parent = ChangelogRelatedNode(node_id=self.peer_id_previous, node_kind=self.peer_kind_previous)
154
+
155
+ @property
156
+ def is_empty(self) -> bool:
157
+ return self.peer_status == DiffAction.UNCHANGED and not self.properties
158
+
159
+
160
+ class RelationshipPeerChangelog(BaseModel):
161
+ peer_id: str = Field(..., description="The ID of the peer")
162
+ peer_kind: str = Field(..., description="The node kind of the peer")
163
+ peer_status: DiffAction = Field(
164
+ ..., description="Indicate how the relationship to this peer was changed in this update"
165
+ )
166
+ properties: dict[str, PropertyChangelog] = Field(
167
+ default_factory=dict, description="Changes to properties of this relationship if any were made"
168
+ )
169
+
170
+ def add_property(self, name: str, value_current: bool | str | None, value_previous: bool | str | None) -> None:
171
+ self.properties[name] = PropertyChangelog(name=name, value=value_current, value_previous=value_previous)
172
+
173
+
174
+ class RelationshipCardinalityManyChangelog(BaseModel):
175
+ name: str
176
+ peers: list[RelationshipPeerChangelog] = Field(default_factory=list)
177
+
178
+ @computed_field
179
+ def cardinality(self) -> str:
180
+ return "many"
181
+
182
+ def add_new_peer(self, relationship: Relationship) -> None:
183
+ properties: dict[str, PropertyChangelog] = {}
184
+ properties["is_protected"] = PropertyChangelog(
185
+ name="is_protected", value=relationship.is_protected, value_previous=None
186
+ )
187
+ properties["is_visible"] = PropertyChangelog(
188
+ name="is_visible", value=relationship.is_protected, value_previous=None
189
+ )
190
+ if owner := getattr(relationship, "owner_id", None):
191
+ properties["owner"] = PropertyChangelog(name="owner", value=owner, value_previous=None)
192
+ if source := getattr(relationship, "source_id", None):
193
+ properties["source"] = PropertyChangelog(name="source_id", value=source, value_previous=None)
194
+
195
+ self.peers.append(
196
+ RelationshipPeerChangelog(
197
+ peer_id=relationship.get_peer_id(),
198
+ peer_kind=relationship.get_peer_kind(),
199
+ peer_status=DiffAction.ADDED,
200
+ properties=properties,
201
+ )
202
+ )
203
+
204
+ def remove_peer(self, peer_id: str, peer_kind: str) -> None:
205
+ self.peers.append(
206
+ RelationshipPeerChangelog(
207
+ peer_id=peer_id,
208
+ peer_kind=peer_kind,
209
+ peer_status=DiffAction.REMOVED,
210
+ )
211
+ )
212
+
213
+ @property
214
+ def is_empty(self) -> bool:
215
+ return not self.peers
216
+
217
+
218
+ class ChangelogRelatedNode(BaseModel):
219
+ node_id: str
220
+ node_kind: str
221
+
222
+
223
+ class NodeChangelog(BaseModel):
224
+ """Emitted when a node is updated"""
225
+
226
+ node_id: str
227
+ node_kind: str
228
+ display_label: str
229
+
230
+ attributes: dict[str, AttributeChangelog] = Field(default_factory=dict)
231
+ relationships: dict[str, RelationshipCardinalityOneChangelog | RelationshipCardinalityManyChangelog] = Field(
232
+ default_factory=dict
233
+ )
234
+
235
+ _parent: ChangelogRelatedNode | None = PrivateAttr(default=None)
236
+
237
+ @property
238
+ def parent(self) -> ChangelogRelatedNode | None:
239
+ return self._parent
240
+
241
+ @property
242
+ def updated_fields(self) -> list[str]:
243
+ """Return a list of update fields i.e. attributes and relationships"""
244
+ return list(self.relationships.keys()) + list(self.attributes.keys())
245
+
246
+ @property
247
+ def has_changes(self) -> bool:
248
+ return len(self.updated_fields) > 0
249
+
250
+ @property
251
+ def root_node_id(self) -> str:
252
+ """Return the top level node_id"""
253
+ if self.parent:
254
+ return self.parent.node_id
255
+ return self.node_id
256
+
257
+ def add_parent(self, parent: ChangelogRelatedNode) -> None:
258
+ self._parent = parent
259
+
260
+ def add_parent_from_relationship(self, parent: Relationship) -> None:
261
+ self._parent = ChangelogRelatedNode(node_id=parent.get_peer_id(), node_kind=parent.get_peer_kind())
262
+
263
+ def create_relationship(self, relationship: Relationship) -> None:
264
+ if relationship.schema.cardinality == RelationshipCardinality.ONE:
265
+ peer_id = relationship.get_peer_id()
266
+ peer_kind = relationship.get_peer_kind()
267
+ if relationship.schema.kind == RelationshipKind.PARENT:
268
+ self._parent = ChangelogRelatedNode(node_id=peer_id, node_kind=peer_kind)
269
+ changelog_relationship = RelationshipCardinalityOneChangelog(
270
+ name=relationship.schema.name,
271
+ peer_id=peer_id,
272
+ peer_kind=peer_kind,
273
+ )
274
+ if source_id := getattr(relationship, "source_id", None):
275
+ changelog_relationship.add_property(name="source", value_current=source_id, value_previous=None)
276
+ if owner_id := getattr(relationship, "owner_id", None):
277
+ changelog_relationship.add_property(name="owner", value_current=owner_id, value_previous=None)
278
+ changelog_relationship.add_property(
279
+ name="is_protected", value_current=relationship.is_protected, value_previous=None
280
+ )
281
+ changelog_relationship.add_property(
282
+ name="is_visible", value_current=relationship.is_visible, value_previous=None
283
+ )
284
+ self.relationships[changelog_relationship.name] = changelog_relationship
285
+ elif relationship.schema.cardinality == RelationshipCardinality.MANY:
286
+ if relationship.schema.name not in self.relationships:
287
+ self.relationships[relationship.schema.name] = RelationshipCardinalityManyChangelog(
288
+ name=relationship.schema.name
289
+ )
290
+ relationship_container = cast(
291
+ RelationshipCardinalityManyChangelog, self.relationships[relationship.schema.name]
292
+ )
293
+
294
+ relationship_container.add_new_peer(relationship=relationship)
295
+
296
+ def delete_relationship(self, relationship: Relationship) -> None:
297
+ if relationship.schema.cardinality == RelationshipCardinality.ONE:
298
+ peer_id = relationship.get_peer_id()
299
+ peer_kind = relationship.get_peer_kind()
300
+ changelog_relationship = RelationshipCardinalityOneChangelog(
301
+ name=relationship.schema.name,
302
+ peer_id_previous=peer_id,
303
+ peer_kind_previous=peer_kind,
304
+ )
305
+ self.relationships[changelog_relationship.name] = changelog_relationship
306
+ elif relationship.schema.cardinality == RelationshipCardinality.MANY:
307
+ if relationship.schema.name not in self.relationships:
308
+ self.relationships[relationship.schema.name] = RelationshipCardinalityManyChangelog(
309
+ name=relationship.schema.name
310
+ )
311
+ relationship_container = cast(
312
+ RelationshipCardinalityManyChangelog, self.relationships[relationship.schema.name]
313
+ )
314
+ relationship_container.remove_peer(
315
+ peer_id=relationship.get_peer_id(), peer_kind=relationship.get_peer_kind()
316
+ )
317
+
318
+ def add_attribute(self, attribute: AttributeChangelog) -> None:
319
+ if attribute.has_updates:
320
+ self.attributes[attribute.name] = attribute
321
+
322
+ def add_relationship(
323
+ self, relationship_changelog: RelationshipCardinalityOneChangelog | RelationshipCardinalityManyChangelog
324
+ ) -> None:
325
+ if isinstance(relationship_changelog, RelationshipCardinalityOneChangelog) and relationship_changelog.parent:
326
+ self.add_parent(parent=relationship_changelog.parent)
327
+ if relationship_changelog.is_empty:
328
+ return
329
+
330
+ self.relationships[relationship_changelog.name] = relationship_changelog
331
+
332
+ def create_attribute(self, attribute: BaseAttribute) -> None:
333
+ changelog_attribute = AttributeChangelog(
334
+ name=attribute.name, value=attribute.value, value_previous=None, kind=attribute.schema.kind
335
+ )
336
+ if source_id := getattr(attribute, "source_id", None):
337
+ changelog_attribute.add_property(name="source", value_current=source_id, value_previous=None)
338
+ if owner_id := getattr(attribute, "owner_id", None):
339
+ changelog_attribute.add_property(name="owner", value_current=owner_id, value_previous=None)
340
+ changelog_attribute.add_property(name="is_protected", value_current=attribute.is_protected, value_previous=None)
341
+ changelog_attribute.add_property(name="is_visible", value_current=attribute.is_visible, value_previous=None)
342
+ self.attributes[changelog_attribute.name] = changelog_attribute
343
+
344
+ def get_related_nodes(self) -> list[ChangelogRelatedNode]:
345
+ related_nodes: dict[str, ChangelogRelatedNode] = {}
346
+ for relationship in self.relationships.values():
347
+ if isinstance(relationship, RelationshipCardinalityOneChangelog):
348
+ if relationship.peer_id and relationship.peer_kind:
349
+ related_nodes[relationship.peer_id] = ChangelogRelatedNode(
350
+ node_id=relationship.peer_id, node_kind=relationship.peer_kind
351
+ )
352
+ if relationship.peer_id_previous and relationship.peer_kind_previous:
353
+ related_nodes[relationship.peer_id_previous] = ChangelogRelatedNode(
354
+ node_id=relationship.peer_id_previous, node_kind=relationship.peer_kind_previous
355
+ )
356
+ elif isinstance(relationship, RelationshipCardinalityManyChangelog):
357
+ for peer in relationship.peers:
358
+ related_nodes[peer.peer_id] = ChangelogRelatedNode(node_id=peer.peer_id, node_kind=peer.peer_kind)
359
+
360
+ if self.parent:
361
+ related_nodes[self.parent.node_id] = self.parent
362
+
363
+ return list(related_nodes.values())
364
+
365
+
366
+ class ChangelogRelationshipMapper:
367
+ def __init__(self, schema: RelationshipSchema) -> None:
368
+ self.schema = schema
369
+ self._cardinality_one_relationship: RelationshipCardinalityOneChangelog | None = None
370
+ self._cardinality_many_relationship: RelationshipCardinalityManyChangelog | None = None
371
+
372
+ @property
373
+ def cardinality_one_relationship(self) -> RelationshipCardinalityOneChangelog:
374
+ if not self._cardinality_one_relationship:
375
+ self._cardinality_one_relationship = RelationshipCardinalityOneChangelog(name=self.schema.name)
376
+
377
+ return self._cardinality_one_relationship
378
+
379
+ @property
380
+ def cardinality_many_relationship(self) -> RelationshipCardinalityManyChangelog:
381
+ if not self._cardinality_many_relationship:
382
+ self._cardinality_many_relationship = RelationshipCardinalityManyChangelog(name=self.schema.name)
383
+
384
+ return self._cardinality_many_relationship
385
+
386
+ def remove_peer(self, peer_data: RelationshipPeerData) -> None:
387
+ if self.schema.cardinality == RelationshipCardinality.ONE:
388
+ self.cardinality_one_relationship.peer_id_previous = str(peer_data.peer_id)
389
+ self.cardinality_one_relationship.peer_kind_previous = peer_data.peer_kind
390
+ elif self.schema.cardinality == RelationshipCardinality.MANY:
391
+ self.cardinality_many_relationship.remove_peer(
392
+ peer_id=str(peer_data.peer_id), peer_kind=peer_data.peer_kind
393
+ )
394
+
395
+ def _set_cardinality_one_peer(self, relationship: Relationship) -> None:
396
+ self.cardinality_one_relationship.peer_id = relationship.peer_id
397
+ self.cardinality_one_relationship.peer_kind = relationship.get_peer_kind()
398
+ self.cardinality_one_relationship.set_parent_from_relationship(rel_kind=relationship.schema.kind)
399
+
400
+ def add_parent_from_relationship(self, relationship: Relationship) -> None:
401
+ if self.schema.cardinality == RelationshipCardinality.ONE:
402
+ self.cardinality_one_relationship.set_parent(
403
+ parent_id=relationship.get_peer_id(), parent_kind=relationship.get_peer_kind()
404
+ )
405
+
406
+ def add_peer_from_relationship(self, relationship: Relationship) -> None:
407
+ if self.schema.cardinality == RelationshipCardinality.ONE:
408
+ self._set_cardinality_one_peer(relationship=relationship)
409
+ elif self.schema.cardinality == RelationshipCardinality.MANY:
410
+ self.cardinality_many_relationship.add_new_peer(relationship=relationship)
411
+
412
+ def add_updated_relationship(
413
+ self, relationship: Relationship, old_data: RelationshipPeerData, properties_to_update: list[str]
414
+ ) -> None:
415
+ if self.schema.cardinality == RelationshipCardinality.ONE:
416
+ self._set_cardinality_one_peer(relationship=relationship)
417
+ self.cardinality_one_relationship.peer_id_previous = self.cardinality_one_relationship.peer_id
418
+ self.cardinality_one_relationship.peer_kind_previous = self.cardinality_one_relationship.peer_kind
419
+ for property_to_update in properties_to_update:
420
+ previous_property = old_data.properties.get(property_to_update)
421
+ previous_value: str | bool | None = None
422
+ if previous_property:
423
+ if isinstance(previous_property.value, UUID):
424
+ previous_value = str(previous_property.value)
425
+ else:
426
+ previous_value = previous_property.value
427
+ property_name = (
428
+ property_to_update if property_to_update not in ["source", "owner"] else f"{property_to_update}_id"
429
+ )
430
+ self.cardinality_one_relationship.add_property(
431
+ name=property_to_update,
432
+ value_current=getattr(relationship, property_name),
433
+ value_previous=previous_value,
434
+ )
435
+ self.cardinality_one_relationship.set_parent_from_relationship(rel_kind=relationship.schema.kind)
436
+
437
+ def delete_relationship(self, peer_id: str, peer_kind: str, rel_schema: RelationshipSchema) -> None:
438
+ if self.schema.cardinality == RelationshipCardinality.ONE:
439
+ self.cardinality_one_relationship.peer_id_previous = peer_id
440
+ self.cardinality_one_relationship.peer_kind_previous = peer_kind
441
+ self.cardinality_one_relationship.set_parent_from_relationship(rel_kind=rel_schema.kind)
442
+
443
+ elif self.schema.cardinality == RelationshipCardinality.MANY:
444
+ self.cardinality_many_relationship.remove_peer(peer_id=peer_id, peer_kind=peer_kind)
445
+
446
+ @property
447
+ def changelog(self) -> RelationshipCardinalityOneChangelog | RelationshipCardinalityManyChangelog:
448
+ match self.schema.cardinality:
449
+ case RelationshipCardinality.ONE:
450
+ return self.cardinality_one_relationship
451
+ case RelationshipCardinality.MANY:
452
+ return self.cardinality_many_relationship
453
+
454
+
455
+ class RelationshipChangelogGetter:
456
+ def __init__(self, db: InfrahubDatabase, branch: Branch) -> None:
457
+ self._db = db
458
+ self._branch = branch
459
+
460
+ async def get_changelogs(self, primary_changelog: NodeChangelog) -> list[NodeChangelog]:
461
+ """Return secondary changelogs based on this update
462
+
463
+ These will typically include updates to relationships on other nodes.
464
+ """
465
+ schema_branch = self._db.schema.get_schema_branch(name=self._branch.name)
466
+ node_schema = schema_branch.get(name=primary_changelog.node_kind)
467
+ secondaries: list[NodeChangelog] = []
468
+
469
+ for relationship in primary_changelog.relationships.values():
470
+ rel_schema = node_schema.get_relationship(name=relationship.name)
471
+ if isinstance(relationship, RelationshipCardinalityOneChangelog):
472
+ # For now this code only looks at the scenario when a cardinality=one relationship
473
+ # is added to a node and it has a cardinality=many relationship coming back from
474
+ # another node, it will be expanded to include all variations.
475
+ if relationship.peer_status == DiffAction.ADDED:
476
+ peer_schema = schema_branch.get(name=str(relationship.peer_kind))
477
+ peer_relation = peer_schema.get_relationship_by_identifier(
478
+ id=str(rel_schema.identifier), raise_on_error=False
479
+ )
480
+ if peer_relation:
481
+ node_changelog = NodeChangelog(
482
+ node_id=str(relationship.peer_id),
483
+ node_kind=str(relationship.peer_kind),
484
+ display_label="n/a",
485
+ )
486
+ if peer_relation.cardinality == RelationshipCardinality.MANY:
487
+ node_changelog.relationships[peer_relation.name] = RelationshipCardinalityManyChangelog(
488
+ name=peer_relation.name,
489
+ peers=[
490
+ RelationshipPeerChangelog(
491
+ peer_id=primary_changelog.node_id,
492
+ peer_kind=primary_changelog.node_kind,
493
+ peer_status=DiffAction.ADDED,
494
+ )
495
+ ],
496
+ )
497
+ secondaries.append(node_changelog)
498
+
499
+ return secondaries
@@ -43,6 +43,29 @@ RESERVED_ATTR_GEN_NAMES = ["type"]
43
43
 
44
44
  NULL_VALUE = "NULL"
45
45
 
46
+ EVENT_NAMESPACE = "infrahub"
47
+
48
+
49
+ class EventType(InfrahubStringEnum):
50
+ BRANCH_CREATED = f"{EVENT_NAMESPACE}.branch.created"
51
+ BRANCH_DELETED = f"{EVENT_NAMESPACE}.branch.deleted"
52
+ BRANCH_MERGED = f"{EVENT_NAMESPACE}.branch.merged"
53
+ BRANCH_REBASED = f"{EVENT_NAMESPACE}.branch.rebased"
54
+
55
+ SCHEMA_UPDATED = f"{EVENT_NAMESPACE}.schema.update"
56
+
57
+ NODE_CREATED = f"{EVENT_NAMESPACE}.node.created"
58
+ NODE_UPDATED = f"{EVENT_NAMESPACE}.node.updated"
59
+ NODE_DELETED = f"{EVENT_NAMESPACE}.node.deleted"
60
+
61
+ GROUP_MEMBER_ADDED = f"{EVENT_NAMESPACE}.group.member_added"
62
+ GROUP_MEMBER_REMOVED = f"{EVENT_NAMESPACE}.group.member_removed"
63
+
64
+ REPOSITORY_UPDATE_COMMIT = f"{EVENT_NAMESPACE}.repository.update_commit"
65
+
66
+ ARTIFACT_CREATED = f"{EVENT_NAMESPACE}.artifact.created"
67
+ ARTIFACT_UPDATED = f"{EVENT_NAMESPACE}.artifact.updated"
68
+
46
69
 
47
70
  class PermissionLevel(enum.Flag):
48
71
  READ = 1
@@ -60,6 +83,7 @@ class GlobalPermissions(InfrahubStringEnum):
60
83
  MANAGE_ACCOUNTS = "manage_accounts"
61
84
  MANAGE_PERMISSIONS = "manage_permissions"
62
85
  MANAGE_REPOSITORIES = "manage_repositories"
86
+ OVERRIDE_CONTEXT = "override_context"
63
87
 
64
88
 
65
89
  class PermissionAction(InfrahubStringEnum):
@@ -175,11 +199,23 @@ class GeneratorInstanceStatus(InfrahubStringEnum):
175
199
 
176
200
 
177
201
  class MutationAction(InfrahubStringEnum):
178
- ADDED = "added"
179
- REMOVED = "removed"
202
+ CREATED = "created"
203
+ DELETED = "deleted"
180
204
  UPDATED = "updated"
181
205
  UNDEFINED = "undefined"
182
206
 
207
+ @classmethod
208
+ def from_diff_action(cls, diff_action: DiffAction) -> MutationAction:
209
+ match diff_action:
210
+ case DiffAction.ADDED:
211
+ return MutationAction.CREATED
212
+ case DiffAction.REMOVED:
213
+ return MutationAction.DELETED
214
+ case DiffAction.UPDATED:
215
+ return MutationAction.UPDATED
216
+ case DiffAction.UNCHANGED:
217
+ return MutationAction.UNDEFINED
218
+
183
219
 
184
220
  class PathResourceType(InfrahubStringEnum):
185
221
  SCHEMA = "schema"
@@ -225,6 +261,7 @@ class RelationshipKind(InfrahubStringEnum):
225
261
  GROUP = "Group"
226
262
  HIERARCHY = "Hierarchy"
227
263
  PROFILE = "Profile"
264
+ TEMPLATE = "Template"
228
265
 
229
266
 
230
267
  class RelationshipStatus(InfrahubStringEnum):
@@ -301,6 +338,7 @@ RESTRICTED_NAMESPACES: list[str] = [
301
338
  "Lineage",
302
339
  "Schema",
303
340
  "Profile",
341
+ "Template",
304
342
  ]
305
343
 
306
344
  NODE_NAME_REGEX = r"^[A-Z][a-zA-Z0-9]+$"
@@ -315,3 +353,6 @@ DEFAULT_KIND_MAX_LENGTH = 32
315
353
  NAMESPACE_REGEX = r"^[A-Z][a-z0-9]+$"
316
354
  NODE_KIND_REGEX = r"^[A-Z][a-zA-Z0-9]+$"
317
355
  DEFAULT_REL_IDENTIFIER_LENGTH = 128
356
+
357
+ OBJECT_TEMPLATE_RELATIONSHIP_NAME = "object_template"
358
+ OBJECT_TEMPLATE_NAME_ATTR = "template_name"
@@ -42,6 +42,7 @@ NUMBERPOOL = "CoreNumberPool"
42
42
  LINEAGEOWNER = "LineageOwner"
43
43
  LINEAGESOURCE = "LineageSource"
44
44
  OBJECTPERMISSION = "CoreObjectPermission"
45
+ OBJECTTEMPLATE = "CoreObjectTemplate"
45
46
  OBJECTTHREAD = "CoreObjectThread"
46
47
  PASSWORDCREDENTIAL = "CorePasswordCredential"
47
48
  PROFILE = "CoreProfile"
@@ -1,5 +1,7 @@
1
1
  from enum import Enum, Flag, auto
2
2
 
3
+ PARENT_CHILD_IDENTIFIER = "parent__child"
4
+
3
5
 
4
6
  class FlagProperty(Enum):
5
7
  IS_VISIBLE = "is_visible"
@@ -435,7 +435,7 @@ class DiffCombiner:
435
435
  nodes=combined_nodes,
436
436
  )
437
437
  )
438
- base_branch_diff, diff_branch_diff = combined_diffs # pylint: disable=unbalanced-tuple-unpacking
438
+ base_branch_diff, diff_branch_diff = combined_diffs
439
439
  base_branch_diff.partner_uuid = diff_branch_diff.uuid
440
440
  diff_branch_diff.partner_uuid = base_branch_diff.uuid
441
441
  return EnrichedDiffs(
@@ -3,6 +3,7 @@ from typing import TYPE_CHECKING, Any
3
3
  from infrahub.core.constants import NULL_VALUE, DiffAction, RelationshipCardinality
4
4
  from infrahub.core.constants.database import DatabaseEdgeType
5
5
  from infrahub.database import InfrahubDatabase
6
+ from infrahub.log import get_logger
6
7
 
7
8
  from ..model.path import (
8
9
  CalculatedDiffs,
@@ -16,6 +17,8 @@ from .interface import DiffEnricherInterface
16
17
  if TYPE_CHECKING:
17
18
  from infrahub.core.schema import MainSchemaTypes
18
19
 
20
+ log = get_logger()
21
+
19
22
 
20
23
  class DiffCardinalityOneEnricher(DiffEnricherInterface):
21
24
  """Clean up diffs for cardinality=one relationships to make them cleaner and more intuitive
@@ -32,8 +35,9 @@ class DiffCardinalityOneEnricher(DiffEnricherInterface):
32
35
  self.db = db
33
36
  self._node_schema_map: dict[str, MainSchemaTypes] = {}
34
37
 
35
- async def enrich(self, enriched_diff_root: EnrichedDiffRoot, calculated_diffs: CalculatedDiffs) -> None:
38
+ async def enrich(self, enriched_diff_root: EnrichedDiffRoot, calculated_diffs: CalculatedDiffs) -> None: # noqa: ARG002
36
39
  self._node_schema_map = {}
40
+ log.info("Beginning cardinality-one diff enrichment...")
37
41
  for diff_node in enriched_diff_root.nodes:
38
42
  for relationship_group in diff_node.relationships:
39
43
  if (
@@ -41,6 +45,7 @@ class DiffCardinalityOneEnricher(DiffEnricherInterface):
41
45
  and len(relationship_group.relationships) > 0
42
46
  ):
43
47
  self.consolidate_cardinality_one_diff_elements(diff_relationship=relationship_group)
48
+ log.info("Cardinality-one diff enrichment complete.")
44
49
 
45
50
  def _determine_action(self, previous_value: Any, new_value: Any) -> DiffAction:
46
51
  if previous_value == new_value: