infrahub-server 1.2.12__py3-none-any.whl → 1.3.0__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 (205) hide show
  1. infrahub/actions/constants.py +130 -0
  2. infrahub/actions/gather.py +114 -0
  3. infrahub/actions/models.py +243 -0
  4. infrahub/actions/parsers.py +104 -0
  5. infrahub/actions/schema.py +393 -0
  6. infrahub/actions/tasks.py +119 -0
  7. infrahub/actions/triggers.py +21 -0
  8. infrahub/branch/__init__.py +0 -0
  9. infrahub/branch/tasks.py +29 -0
  10. infrahub/branch/triggers.py +22 -0
  11. infrahub/cli/db.py +3 -4
  12. infrahub/computed_attribute/gather.py +3 -1
  13. infrahub/computed_attribute/tasks.py +23 -29
  14. infrahub/core/account.py +24 -47
  15. infrahub/core/attribute.py +13 -15
  16. infrahub/core/constants/__init__.py +10 -0
  17. infrahub/core/constants/infrahubkind.py +9 -0
  18. infrahub/core/constraint/node/runner.py +3 -1
  19. infrahub/core/convert_object_type/__init__.py +0 -0
  20. infrahub/core/convert_object_type/conversion.py +124 -0
  21. infrahub/core/convert_object_type/schema_mapping.py +56 -0
  22. infrahub/core/diff/coordinator.py +8 -1
  23. infrahub/core/diff/query/all_conflicts.py +1 -5
  24. infrahub/core/diff/query/artifact.py +10 -20
  25. infrahub/core/diff/query/delete_query.py +8 -4
  26. infrahub/core/diff/query/diff_get.py +3 -6
  27. infrahub/core/diff/query/field_specifiers.py +1 -1
  28. infrahub/core/diff/query/field_summary.py +2 -4
  29. infrahub/core/diff/query/merge.py +72 -125
  30. infrahub/core/diff/query/save.py +28 -43
  31. infrahub/core/diff/query/summary_counts_enricher.py +34 -54
  32. infrahub/core/diff/query/time_range_query.py +0 -1
  33. infrahub/core/diff/repository/repository.py +4 -0
  34. infrahub/core/manager.py +14 -11
  35. infrahub/core/migrations/graph/m003_relationship_parent_optional.py +1 -2
  36. infrahub/core/migrations/graph/m012_convert_account_generic.py +1 -1
  37. infrahub/core/migrations/graph/m013_convert_git_password_credential.py +2 -6
  38. infrahub/core/migrations/graph/m015_diff_format_update.py +1 -2
  39. infrahub/core/migrations/graph/m016_diff_delete_bug_fix.py +1 -2
  40. infrahub/core/migrations/graph/m019_restore_rels_to_time.py +11 -22
  41. infrahub/core/migrations/graph/m020_duplicate_edges.py +3 -6
  42. infrahub/core/migrations/graph/m021_missing_hierarchy_merge.py +1 -2
  43. infrahub/core/migrations/graph/m023_deduplicate_cardinality_one_relationships.py +2 -2
  44. infrahub/core/migrations/graph/m024_missing_hierarchy_backfill.py +1 -2
  45. infrahub/core/migrations/graph/m028_delete_diffs.py +1 -2
  46. infrahub/core/migrations/graph/m029_duplicates_cleanup.py +30 -48
  47. infrahub/core/migrations/graph/m030_illegal_edges.py +1 -2
  48. infrahub/core/migrations/query/attribute_add.py +1 -2
  49. infrahub/core/migrations/query/attribute_rename.py +6 -11
  50. infrahub/core/migrations/query/delete_element_in_schema.py +19 -17
  51. infrahub/core/migrations/query/node_duplicate.py +19 -21
  52. infrahub/core/migrations/query/relationship_duplicate.py +19 -18
  53. infrahub/core/migrations/schema/node_attribute_remove.py +4 -8
  54. infrahub/core/migrations/schema/node_remove.py +19 -20
  55. infrahub/core/models.py +29 -2
  56. infrahub/core/node/__init__.py +131 -28
  57. infrahub/core/node/base.py +1 -1
  58. infrahub/core/node/create.py +211 -0
  59. infrahub/core/node/resource_manager/number_pool.py +31 -5
  60. infrahub/core/node/standard.py +6 -1
  61. infrahub/core/path.py +15 -1
  62. infrahub/core/protocols.py +57 -0
  63. infrahub/core/protocols_base.py +3 -0
  64. infrahub/core/query/__init__.py +2 -2
  65. infrahub/core/query/delete.py +3 -3
  66. infrahub/core/query/diff.py +19 -32
  67. infrahub/core/query/ipam.py +10 -20
  68. infrahub/core/query/node.py +29 -47
  69. infrahub/core/query/relationship.py +55 -34
  70. infrahub/core/query/resource_manager.py +1 -2
  71. infrahub/core/query/standard_node.py +19 -5
  72. infrahub/core/query/subquery.py +2 -4
  73. infrahub/core/relationship/constraints/count.py +10 -9
  74. infrahub/core/relationship/constraints/interface.py +2 -1
  75. infrahub/core/relationship/constraints/peer_kind.py +2 -1
  76. infrahub/core/relationship/constraints/peer_parent.py +56 -0
  77. infrahub/core/relationship/constraints/peer_relatives.py +72 -0
  78. infrahub/core/relationship/constraints/profiles_kind.py +1 -1
  79. infrahub/core/relationship/model.py +4 -1
  80. infrahub/core/schema/__init__.py +2 -1
  81. infrahub/core/schema/attribute_parameters.py +160 -0
  82. infrahub/core/schema/attribute_schema.py +130 -7
  83. infrahub/core/schema/basenode_schema.py +27 -3
  84. infrahub/core/schema/definitions/core/__init__.py +29 -1
  85. infrahub/core/schema/definitions/core/group.py +45 -0
  86. infrahub/core/schema/definitions/core/resource_pool.py +9 -0
  87. infrahub/core/schema/definitions/internal.py +43 -5
  88. infrahub/core/schema/generated/attribute_schema.py +16 -3
  89. infrahub/core/schema/generated/relationship_schema.py +11 -1
  90. infrahub/core/schema/manager.py +7 -2
  91. infrahub/core/schema/schema_branch.py +104 -9
  92. infrahub/core/validators/__init__.py +15 -2
  93. infrahub/core/validators/attribute/choices.py +1 -3
  94. infrahub/core/validators/attribute/enum.py +1 -3
  95. infrahub/core/validators/attribute/kind.py +1 -3
  96. infrahub/core/validators/attribute/length.py +13 -7
  97. infrahub/core/validators/attribute/min_max.py +118 -0
  98. infrahub/core/validators/attribute/number_pool.py +106 -0
  99. infrahub/core/validators/attribute/optional.py +1 -4
  100. infrahub/core/validators/attribute/regex.py +5 -6
  101. infrahub/core/validators/attribute/unique.py +1 -3
  102. infrahub/core/validators/determiner.py +18 -2
  103. infrahub/core/validators/enum.py +12 -0
  104. infrahub/core/validators/node/hierarchy.py +3 -6
  105. infrahub/core/validators/query.py +1 -3
  106. infrahub/core/validators/relationship/count.py +6 -12
  107. infrahub/core/validators/relationship/optional.py +2 -4
  108. infrahub/core/validators/relationship/peer.py +177 -12
  109. infrahub/core/validators/tasks.py +1 -1
  110. infrahub/core/validators/uniqueness/query.py +5 -9
  111. infrahub/database/__init__.py +12 -4
  112. infrahub/database/validation.py +1 -2
  113. infrahub/dependencies/builder/constraint/grouped/node_runner.py +4 -0
  114. infrahub/dependencies/builder/constraint/relationship_manager/peer_parent.py +8 -0
  115. infrahub/dependencies/builder/constraint/relationship_manager/peer_relatives.py +8 -0
  116. infrahub/dependencies/builder/constraint/schema/aggregated.py +2 -0
  117. infrahub/dependencies/builder/constraint/schema/relationship_peer.py +8 -0
  118. infrahub/dependencies/builder/diff/deserializer.py +1 -1
  119. infrahub/dependencies/registry.py +4 -0
  120. infrahub/events/group_action.py +1 -0
  121. infrahub/events/models.py +1 -1
  122. infrahub/git/base.py +5 -3
  123. infrahub/git/integrator.py +96 -5
  124. infrahub/git/tasks.py +1 -0
  125. infrahub/graphql/analyzer.py +139 -18
  126. infrahub/graphql/manager.py +4 -0
  127. infrahub/graphql/mutations/action.py +164 -0
  128. infrahub/graphql/mutations/convert_object_type.py +71 -0
  129. infrahub/graphql/mutations/main.py +24 -175
  130. infrahub/graphql/mutations/proposed_change.py +20 -17
  131. infrahub/graphql/mutations/relationship.py +32 -0
  132. infrahub/graphql/mutations/resource_manager.py +63 -7
  133. infrahub/graphql/queries/convert_object_type_mapping.py +34 -0
  134. infrahub/graphql/queries/resource_manager.py +7 -1
  135. infrahub/graphql/resolvers/many_relationship.py +1 -1
  136. infrahub/graphql/resolvers/resolver.py +2 -2
  137. infrahub/graphql/resolvers/single_relationship.py +1 -1
  138. infrahub/graphql/schema.py +6 -0
  139. infrahub/menu/menu.py +34 -2
  140. infrahub/message_bus/messages/__init__.py +0 -10
  141. infrahub/message_bus/operations/__init__.py +0 -8
  142. infrahub/message_bus/operations/refresh/registry.py +3 -6
  143. infrahub/patch/queries/delete_duplicated_edges.py +10 -15
  144. infrahub/pools/models.py +14 -0
  145. infrahub/pools/number.py +5 -3
  146. infrahub/pools/registration.py +22 -0
  147. infrahub/pools/tasks.py +126 -0
  148. infrahub/prefect_server/models.py +1 -19
  149. infrahub/proposed_change/models.py +68 -3
  150. infrahub/proposed_change/tasks.py +911 -34
  151. infrahub/schema/__init__.py +0 -0
  152. infrahub/schema/tasks.py +27 -0
  153. infrahub/schema/triggers.py +23 -0
  154. infrahub/task_manager/models.py +10 -6
  155. infrahub/trigger/catalogue.py +6 -0
  156. infrahub/trigger/models.py +23 -6
  157. infrahub/trigger/setup.py +26 -2
  158. infrahub/trigger/tasks.py +4 -2
  159. infrahub/types.py +6 -0
  160. infrahub/webhook/tasks.py +4 -8
  161. infrahub/workflows/catalogue.py +103 -1
  162. infrahub_sdk/client.py +43 -10
  163. infrahub_sdk/ctl/generator.py +4 -4
  164. infrahub_sdk/ctl/repository.py +1 -1
  165. infrahub_sdk/node/__init__.py +39 -0
  166. infrahub_sdk/node/attribute.py +122 -0
  167. infrahub_sdk/node/constants.py +21 -0
  168. infrahub_sdk/{node.py → node/node.py} +158 -803
  169. infrahub_sdk/node/parsers.py +15 -0
  170. infrahub_sdk/node/property.py +24 -0
  171. infrahub_sdk/node/related_node.py +266 -0
  172. infrahub_sdk/node/relationship.py +302 -0
  173. infrahub_sdk/protocols.py +112 -0
  174. infrahub_sdk/protocols_base.py +34 -2
  175. infrahub_sdk/pytest_plugin/items/python_transform.py +2 -1
  176. infrahub_sdk/query_groups.py +17 -5
  177. infrahub_sdk/schema/main.py +1 -0
  178. infrahub_sdk/schema/repository.py +16 -0
  179. infrahub_sdk/spec/object.py +1 -1
  180. infrahub_sdk/store.py +1 -1
  181. infrahub_sdk/testing/schemas/car_person.py +1 -0
  182. infrahub_sdk/utils.py +7 -20
  183. infrahub_sdk/yaml.py +6 -5
  184. {infrahub_server-1.2.12.dist-info → infrahub_server-1.3.0.dist-info}/METADATA +3 -3
  185. {infrahub_server-1.2.12.dist-info → infrahub_server-1.3.0.dist-info}/RECORD +192 -166
  186. infrahub_testcontainers/container.py +0 -1
  187. infrahub_testcontainers/docker-compose.test.yml +1 -1
  188. infrahub_testcontainers/helpers.py +8 -2
  189. infrahub/message_bus/messages/check_generator_run.py +0 -26
  190. infrahub/message_bus/messages/finalize_validator_execution.py +0 -15
  191. infrahub/message_bus/messages/proposed_change/base_with_diff.py +0 -16
  192. infrahub/message_bus/messages/proposed_change/request_proposedchange_refreshartifacts.py +0 -11
  193. infrahub/message_bus/messages/request_generatordefinition_check.py +0 -20
  194. infrahub/message_bus/messages/request_proposedchange_pipeline.py +0 -23
  195. infrahub/message_bus/operations/check/__init__.py +0 -3
  196. infrahub/message_bus/operations/check/generator.py +0 -156
  197. infrahub/message_bus/operations/finalize/__init__.py +0 -3
  198. infrahub/message_bus/operations/finalize/validator.py +0 -133
  199. infrahub/message_bus/operations/requests/__init__.py +0 -9
  200. infrahub/message_bus/operations/requests/generator_definition.py +0 -140
  201. infrahub/message_bus/operations/requests/proposed_change.py +0 -629
  202. /infrahub/{message_bus/messages/proposed_change → actions}/__init__.py +0 -0
  203. {infrahub_server-1.2.12.dist-info → infrahub_server-1.3.0.dist-info}/LICENSE.txt +0 -0
  204. {infrahub_server-1.2.12.dist-info → infrahub_server-1.3.0.dist-info}/WHEEL +0 -0
  205. {infrahub_server-1.2.12.dist-info → infrahub_server-1.3.0.dist-info}/entry_points.txt +0 -0
@@ -1,629 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from enum import IntFlag
4
- from typing import TYPE_CHECKING
5
-
6
- from prefect import flow, task
7
- from prefect.logging import get_run_logger
8
- from pydantic import BaseModel
9
-
10
- from infrahub import lock
11
- from infrahub.core.constants import CheckType, InfrahubKind, RepositoryInternalStatus
12
- from infrahub.core.diff.coordinator import DiffCoordinator
13
- from infrahub.core.registry import registry
14
- from infrahub.dependencies.registry import get_component_registry
15
- from infrahub.git.models import TriggerRepositoryInternalChecks
16
- from infrahub.git.repository import InfrahubRepository
17
- from infrahub.message_bus import InfrahubMessage, messages
18
- from infrahub.message_bus.types import (
19
- ProposedChangeArtifactDefinition,
20
- ProposedChangeBranchDiff,
21
- ProposedChangeRepository,
22
- ProposedChangeSubscriber,
23
- )
24
- from infrahub.proposed_change.branch_diff import (
25
- get_diff_summary_cache,
26
- get_modified_kinds,
27
- get_modified_node_ids,
28
- has_data_changes,
29
- has_node_changes,
30
- set_diff_summary_cache,
31
- )
32
- from infrahub.proposed_change.models import (
33
- RequestArtifactDefinitionCheck,
34
- RequestProposedChangeDataIntegrity,
35
- RequestProposedChangeRepositoryChecks,
36
- RequestProposedChangeRunGenerators,
37
- RequestProposedChangeSchemaIntegrity,
38
- RequestProposedChangeUserTests,
39
- )
40
- from infrahub.services import InfrahubServices # noqa: TC001
41
- from infrahub.workflows.catalogue import (
42
- GIT_REPOSITORY_INTERNAL_CHECKS_TRIGGER,
43
- REQUEST_ARTIFACT_DEFINITION_CHECK,
44
- REQUEST_PROPOSED_CHANGE_DATA_INTEGRITY,
45
- REQUEST_PROPOSED_CHANGE_REPOSITORY_CHECKS,
46
- REQUEST_PROPOSED_CHANGE_RUN_GENERATORS,
47
- REQUEST_PROPOSED_CHANGE_SCHEMA_INTEGRITY,
48
- REQUEST_PROPOSED_CHANGE_USER_TESTS,
49
- )
50
- from infrahub.workflows.utils import add_tags
51
-
52
- if TYPE_CHECKING:
53
- from infrahub_sdk.diff import NodeDiff
54
-
55
-
56
- class DefinitionSelect(IntFlag):
57
- NONE = 0
58
- MODIFIED_KINDS = 1
59
- FILE_CHANGES = 2
60
-
61
- @staticmethod
62
- def add_flag(current: DefinitionSelect, flag: DefinitionSelect, condition: bool) -> DefinitionSelect:
63
- if condition:
64
- return current | flag
65
- return current
66
-
67
- @property
68
- def log_line(self) -> str:
69
- change_types = []
70
- if DefinitionSelect.MODIFIED_KINDS in self:
71
- change_types.append("data changes within relevant object kinds")
72
-
73
- if DefinitionSelect.FILE_CHANGES in self:
74
- change_types.append("file modifications in Git repositories")
75
-
76
- if self:
77
- return f"Requesting generation due to {' and '.join(change_types)}"
78
-
79
- return "Doesn't require changes due to no relevant modified kinds or file changes in Git"
80
-
81
-
82
- @flow(name="proposed-changed-pipeline", flow_run_name="Execute Pipeline")
83
- async def pipeline(message: messages.RequestProposedChangePipeline, service: InfrahubServices) -> None:
84
- events: list[InfrahubMessage] = []
85
-
86
- repositories = await _get_proposed_change_repositories(message=message, service=service)
87
-
88
- if message.source_branch_sync_with_git and await _validate_repository_merge_conflicts(
89
- repositories=repositories, service=service
90
- ):
91
- for repo in repositories:
92
- if not repo.read_only and repo.internal_status == RepositoryInternalStatus.ACTIVE.value:
93
- model = TriggerRepositoryInternalChecks(
94
- proposed_change=message.proposed_change,
95
- repository=repo.repository_id,
96
- source_branch=repo.source_branch,
97
- target_branch=repo.destination_branch,
98
- )
99
- await service.workflow.submit_workflow(
100
- workflow=GIT_REPOSITORY_INTERNAL_CHECKS_TRIGGER,
101
- context=message.context,
102
- parameters={"model": model},
103
- )
104
- return
105
-
106
- await _gather_repository_repository_diffs(repositories=repositories, service=service)
107
-
108
- async with service.database.start_session() as dbs:
109
- destination_branch = await registry.get_branch(db=dbs, branch=message.destination_branch)
110
- source_branch = await registry.get_branch(db=dbs, branch=message.source_branch)
111
- component_registry = get_component_registry()
112
- diff_coordinator = await component_registry.get_component(DiffCoordinator, db=dbs, branch=source_branch)
113
- await diff_coordinator.update_branch_diff(base_branch=destination_branch, diff_branch=source_branch)
114
-
115
- diff_summary = await service.client.get_diff_summary(branch=message.source_branch)
116
- await set_diff_summary_cache(pipeline_id=message.pipeline_id, diff_summary=diff_summary, cache=service.cache)
117
- branch_diff = ProposedChangeBranchDiff(repositories=repositories, pipeline_id=message.pipeline_id)
118
- await _populate_subscribers(
119
- branch_diff=branch_diff, diff_summary=diff_summary, service=service, branch=message.source_branch
120
- )
121
-
122
- if message.check_type is CheckType.ARTIFACT:
123
- events.append(
124
- messages.RequestProposedChangeRefreshArtifacts(
125
- context=message.context,
126
- proposed_change=message.proposed_change,
127
- source_branch=message.source_branch,
128
- source_branch_sync_with_git=message.source_branch_sync_with_git,
129
- destination_branch=message.destination_branch,
130
- branch_diff=branch_diff,
131
- )
132
- )
133
-
134
- if message.check_type in [CheckType.ALL, CheckType.GENERATOR]:
135
- model_proposed_change_run_generator = RequestProposedChangeRunGenerators(
136
- proposed_change=message.proposed_change,
137
- source_branch=message.source_branch,
138
- source_branch_sync_with_git=message.source_branch_sync_with_git,
139
- destination_branch=message.destination_branch,
140
- branch_diff=branch_diff,
141
- refresh_artifacts=message.check_type is CheckType.ALL,
142
- do_repository_checks=message.check_type is CheckType.ALL,
143
- )
144
- await service.workflow.submit_workflow(
145
- workflow=REQUEST_PROPOSED_CHANGE_RUN_GENERATORS,
146
- context=message.context,
147
- parameters={"model": model_proposed_change_run_generator},
148
- )
149
-
150
- if message.check_type in [CheckType.ALL, CheckType.DATA] and has_node_changes(
151
- diff_summary=diff_summary, branch=message.source_branch
152
- ):
153
- model_proposed_change_data_integrity = RequestProposedChangeDataIntegrity(
154
- proposed_change=message.proposed_change,
155
- source_branch=message.source_branch,
156
- source_branch_sync_with_git=message.source_branch_sync_with_git,
157
- destination_branch=message.destination_branch,
158
- branch_diff=branch_diff,
159
- )
160
- await service.workflow.submit_workflow(
161
- workflow=REQUEST_PROPOSED_CHANGE_DATA_INTEGRITY,
162
- context=message.context,
163
- parameters={"model": model_proposed_change_data_integrity},
164
- )
165
-
166
- if message.check_type in [CheckType.REPOSITORY, CheckType.USER]:
167
- model_proposed_change_repo_checks = RequestProposedChangeRepositoryChecks(
168
- proposed_change=message.proposed_change,
169
- source_branch=message.source_branch,
170
- source_branch_sync_with_git=message.source_branch_sync_with_git,
171
- destination_branch=message.destination_branch,
172
- branch_diff=branch_diff,
173
- )
174
- await service.workflow.submit_workflow(
175
- workflow=REQUEST_PROPOSED_CHANGE_REPOSITORY_CHECKS,
176
- context=message.context,
177
- parameters={"model": model_proposed_change_repo_checks},
178
- )
179
-
180
- if message.check_type in [CheckType.ALL, CheckType.SCHEMA] and has_data_changes(
181
- diff_summary=diff_summary, branch=message.source_branch
182
- ):
183
- await service.workflow.submit_workflow(
184
- workflow=REQUEST_PROPOSED_CHANGE_SCHEMA_INTEGRITY,
185
- context=message.context,
186
- parameters={
187
- "model": RequestProposedChangeSchemaIntegrity(
188
- proposed_change=message.proposed_change,
189
- source_branch=message.source_branch,
190
- source_branch_sync_with_git=message.source_branch_sync_with_git,
191
- destination_branch=message.destination_branch,
192
- branch_diff=branch_diff,
193
- )
194
- },
195
- )
196
-
197
- if message.check_type in [CheckType.ALL, CheckType.TEST]:
198
- await service.workflow.submit_workflow(
199
- workflow=REQUEST_PROPOSED_CHANGE_USER_TESTS,
200
- context=message.context,
201
- parameters={
202
- "model": RequestProposedChangeUserTests(
203
- proposed_change=message.proposed_change,
204
- source_branch=message.source_branch,
205
- source_branch_sync_with_git=message.source_branch_sync_with_git,
206
- destination_branch=message.destination_branch,
207
- branch_diff=branch_diff,
208
- )
209
- },
210
- )
211
-
212
- for event in events:
213
- event.assign_meta(parent=message)
214
- await service.message_bus.send(message=event)
215
-
216
-
217
- @flow(
218
- name="proposed-changed-refresh-artifact",
219
- flow_run_name="Trigger artifacts refresh",
220
- )
221
- async def refresh_artifacts(message: messages.RequestProposedChangeRefreshArtifacts, service: InfrahubServices) -> None:
222
- await add_tags(branches=[message.source_branch], nodes=[message.proposed_change])
223
- log = get_run_logger()
224
-
225
- definition_information = await service.client.execute_graphql(
226
- query=GATHER_ARTIFACT_DEFINITIONS,
227
- branch_name=message.source_branch,
228
- )
229
- artifact_definitions = _parse_artifact_definitions(
230
- definitions=definition_information[InfrahubKind.ARTIFACTDEFINITION]["edges"]
231
- )
232
-
233
- diff_summary = await get_diff_summary_cache(pipeline_id=message.branch_diff.pipeline_id, cache=service.cache)
234
- modified_kinds = get_modified_kinds(diff_summary=diff_summary, branch=message.source_branch)
235
-
236
- for artifact_definition in artifact_definitions:
237
- # Request artifact definition checks if the source branch that is managed in combination
238
- # to the Git repository containing modifications which could indicate changes to the transforms
239
- # in code
240
- # Alternatively if the queries used touches models that have been modified in the path
241
- # impacted artifact definitions will be included for consideration
242
-
243
- select = DefinitionSelect.NONE
244
- select = select.add_flag(
245
- current=select,
246
- flag=DefinitionSelect.FILE_CHANGES,
247
- condition=message.source_branch_sync_with_git and message.branch_diff.has_file_modifications,
248
- )
249
-
250
- for changed_model in modified_kinds:
251
- condition = False
252
- if (changed_model in artifact_definition.query_models) or (
253
- changed_model.startswith("Profile")
254
- and changed_model.replace("Profile", "", 1) in artifact_definition.query_models
255
- ):
256
- condition = True
257
-
258
- select = select.add_flag(
259
- current=select,
260
- flag=DefinitionSelect.MODIFIED_KINDS,
261
- condition=condition,
262
- )
263
-
264
- if select:
265
- log.info(f"Trigger processing of {artifact_definition.definition_name}")
266
- model = RequestArtifactDefinitionCheck(
267
- context=message.context,
268
- artifact_definition=artifact_definition,
269
- branch_diff=message.branch_diff,
270
- proposed_change=message.proposed_change,
271
- source_branch=message.source_branch,
272
- source_branch_sync_with_git=message.source_branch_sync_with_git,
273
- destination_branch=message.destination_branch,
274
- )
275
-
276
- await service.workflow.submit_workflow(REQUEST_ARTIFACT_DEFINITION_CHECK, parameters={"model": model})
277
-
278
-
279
- GATHER_ARTIFACT_DEFINITIONS = """
280
- query GatherArtifactDefinitions {
281
- CoreArtifactDefinition {
282
- edges {
283
- node {
284
- id
285
- name {
286
- value
287
- }
288
- artifact_name {
289
- value
290
- }
291
- content_type {
292
- value
293
- }
294
- transformation {
295
- node {
296
- __typename
297
- timeout {
298
- value
299
- }
300
- query {
301
- node {
302
- models {
303
- value
304
- }
305
- name {
306
- value
307
- }
308
- }
309
- }
310
- ... on CoreTransformJinja2 {
311
- template_path {
312
- value
313
- }
314
- }
315
- ... on CoreTransformPython {
316
- class_name {
317
- value
318
- }
319
- file_path {
320
- value
321
- }
322
- convert_query_response {
323
- value
324
- }
325
- }
326
- repository {
327
- node {
328
- id
329
- }
330
- }
331
- }
332
- }
333
- }
334
- }
335
- }
336
- }
337
- """
338
-
339
- GATHER_GRAPHQL_QUERY_SUBSCRIBERS = """
340
- query GatherGraphQLQuerySubscribers($members: [ID!]) {
341
- CoreGraphQLQueryGroup(members__ids: $members) {
342
- edges {
343
- node {
344
- subscribers {
345
- edges {
346
- node {
347
- id
348
- __typename
349
- }
350
- }
351
- }
352
- }
353
- }
354
- }
355
- }
356
- """
357
-
358
-
359
- DESTINATION_ALLREPOSITORIES = """
360
- query DestinationBranchRepositories {
361
- CoreGenericRepository {
362
- edges {
363
- node {
364
- __typename
365
- id
366
- name {
367
- value
368
- }
369
- internal_status {
370
- value
371
- }
372
- ... on CoreRepository {
373
- commit {
374
- value
375
- }
376
- }
377
- ... on CoreReadOnlyRepository {
378
- commit {
379
- value
380
- }
381
- }
382
- }
383
- }
384
- }
385
- }
386
- """
387
-
388
- SOURCE_REPOSITORIES = """
389
- query MyQuery {
390
- CoreRepository {
391
- edges {
392
- node {
393
- __typename
394
- id
395
- name {
396
- value
397
- }
398
- internal_status {
399
- value
400
- }
401
- commit {
402
- value
403
- }
404
- }
405
- }
406
- }
407
- }
408
- """
409
- SOURCE_READONLY_REPOSITORIES = """
410
- query MyQuery {
411
- CoreReadOnlyRepository {
412
- edges {
413
- node {
414
- __typename
415
- id
416
- name {
417
- value
418
- }
419
- internal_status {
420
- value
421
- }
422
- commit {
423
- value
424
- }
425
- }
426
- }
427
- }
428
- }
429
- """
430
-
431
-
432
- class Repository(BaseModel):
433
- repository_id: str
434
- repository_name: str
435
- read_only: bool
436
- commit: str
437
- internal_status: str
438
-
439
-
440
- def _parse_proposed_change_repositories(
441
- message: messages.RequestProposedChangePipeline, source: list[dict], destination: list[dict]
442
- ) -> list[ProposedChangeRepository]:
443
- """This function assumes that the repos is a list of the edges
444
-
445
- The data should come from the queries:
446
- * DESTINATION_ALLREPOSITORIES
447
- * SOURCE_REPOSITORIES
448
- * SOURCE_READONLY_REPOSITORIES
449
- """
450
- destination_repos = _parse_repositories(repositories=destination)
451
- source_repos = _parse_repositories(repositories=source)
452
- pc_repos: dict[str, ProposedChangeRepository] = {}
453
- for repo in destination_repos:
454
- if repo.repository_id not in pc_repos:
455
- pc_repos[repo.repository_id] = ProposedChangeRepository(
456
- repository_id=repo.repository_id,
457
- repository_name=repo.repository_name,
458
- read_only=repo.read_only,
459
- internal_status=repo.internal_status,
460
- destination_commit=repo.commit,
461
- source_branch=message.source_branch,
462
- destination_branch=message.destination_branch,
463
- )
464
- else:
465
- pc_repos[repo.repository_id].destination_commit = repo.commit
466
-
467
- for repo in source_repos:
468
- if repo.repository_id not in pc_repos:
469
- pc_repos[repo.repository_id] = ProposedChangeRepository(
470
- repository_id=repo.repository_id,
471
- repository_name=repo.repository_name,
472
- read_only=repo.read_only,
473
- internal_status=repo.internal_status,
474
- source_commit=repo.commit,
475
- source_branch=message.source_branch,
476
- destination_branch=message.destination_branch,
477
- )
478
- else:
479
- pc_repos[repo.repository_id].source_commit = repo.commit
480
- pc_repos[repo.repository_id].internal_status = repo.internal_status
481
-
482
- return list(pc_repos.values())
483
-
484
-
485
- def _parse_repositories(repositories: list[dict]) -> list[Repository]:
486
- """This function assumes that the repos is a list of the edges
487
-
488
- The data should come from the queries:
489
- * DESTINATION_ALLREPOSITORIES
490
- * SOURCE_REPOSITORIES
491
- * SOURCE_READONLY_REPOSITORIES
492
- """
493
- parsed = []
494
- for repo in repositories:
495
- parsed.append(
496
- Repository(
497
- repository_id=repo["node"]["id"],
498
- repository_name=repo["node"]["name"]["value"],
499
- read_only=repo["node"]["__typename"] == InfrahubKind.READONLYREPOSITORY,
500
- commit=repo["node"]["commit"]["value"] or "",
501
- internal_status=repo["node"]["internal_status"]["value"],
502
- )
503
- )
504
- return parsed
505
-
506
-
507
- def _parse_artifact_definitions(definitions: list[dict]) -> list[ProposedChangeArtifactDefinition]:
508
- """This function assumes that definitions is a list of the edges
509
-
510
- The edge should be of type CoreArtifactDefinition from the query
511
- * GATHER_ARTIFACT_DEFINITIONS
512
- """
513
-
514
- parsed = []
515
- for definition in definitions:
516
- artifact_definition = ProposedChangeArtifactDefinition(
517
- definition_id=definition["node"]["id"],
518
- definition_name=definition["node"]["name"]["value"],
519
- artifact_name=definition["node"]["artifact_name"]["value"],
520
- content_type=definition["node"]["content_type"]["value"],
521
- timeout=definition["node"]["transformation"]["node"]["timeout"]["value"],
522
- query_name=definition["node"]["transformation"]["node"]["query"]["node"]["name"]["value"],
523
- query_models=definition["node"]["transformation"]["node"]["query"]["node"]["models"]["value"] or [],
524
- repository_id=definition["node"]["transformation"]["node"]["repository"]["node"]["id"],
525
- transform_kind=definition["node"]["transformation"]["node"]["__typename"],
526
- )
527
- if artifact_definition.transform_kind == InfrahubKind.TRANSFORMJINJA2:
528
- artifact_definition.template_path = definition["node"]["transformation"]["node"]["template_path"]["value"]
529
- elif artifact_definition.transform_kind == InfrahubKind.TRANSFORMPYTHON:
530
- artifact_definition.class_name = definition["node"]["transformation"]["node"]["class_name"]["value"]
531
- artifact_definition.file_path = definition["node"]["transformation"]["node"]["file_path"]["value"]
532
- artifact_definition.convert_query_response = definition["node"]["transformation"]["node"][
533
- "convert_query_response"
534
- ]["value"]
535
-
536
- parsed.append(artifact_definition)
537
-
538
- return parsed
539
-
540
-
541
- async def _get_proposed_change_repositories(
542
- message: messages.RequestProposedChangePipeline, service: InfrahubServices
543
- ) -> list[ProposedChangeRepository]:
544
- destination_all = await service.client.execute_graphql(
545
- query=DESTINATION_ALLREPOSITORIES, branch_name=message.destination_branch
546
- )
547
- source_managed = await service.client.execute_graphql(query=SOURCE_REPOSITORIES, branch_name=message.source_branch)
548
- source_readonly = await service.client.execute_graphql(
549
- query=SOURCE_READONLY_REPOSITORIES, branch_name=message.source_branch
550
- )
551
-
552
- destination_all = destination_all[InfrahubKind.GENERICREPOSITORY]["edges"]
553
- source_all = (
554
- source_managed[InfrahubKind.REPOSITORY]["edges"] + source_readonly[InfrahubKind.READONLYREPOSITORY]["edges"]
555
- )
556
-
557
- return _parse_proposed_change_repositories(message=message, source=source_all, destination=destination_all)
558
-
559
-
560
- @task(name="proposed-change-validate-repository-conflicts", task_run_name="Validate conflicts on repository") # type: ignore[arg-type]
561
- async def _validate_repository_merge_conflicts(
562
- repositories: list[ProposedChangeRepository], service: InfrahubServices
563
- ) -> bool:
564
- log = get_run_logger()
565
- conflicts = False
566
- for repo in repositories:
567
- if repo.has_diff and not repo.is_staging:
568
- git_repo = await InfrahubRepository.init(
569
- id=repo.repository_id,
570
- name=repo.repository_name,
571
- client=service.client,
572
- service=service,
573
- )
574
- async with lock.registry.get(name=repo.repository_name, namespace="repository"):
575
- repo.conflicts = await git_repo.get_conflicts(
576
- source_branch=repo.source_branch, dest_branch=repo.destination_branch
577
- )
578
- if repo.conflicts:
579
- log.info(f"{len(repo.conflicts)} conflict(s) identified on {repo.repository_name}")
580
- conflicts = True
581
- else:
582
- log.info(f"no conflict identified for {repo.repository_name}")
583
-
584
- return conflicts
585
-
586
-
587
- async def _gather_repository_repository_diffs(
588
- repositories: list[ProposedChangeRepository], service: InfrahubServices
589
- ) -> None:
590
- for repo in repositories:
591
- if repo.has_diff and repo.source_commit and repo.destination_commit:
592
- # TODO we need to find a way to return all files in the repo if the repo is new
593
- git_repo = await InfrahubRepository.init(
594
- id=repo.repository_id,
595
- name=repo.repository_name,
596
- client=service.client,
597
- service=service,
598
- )
599
-
600
- files_changed: list[str] = []
601
- files_added: list[str] = []
602
- files_removed: list[str] = []
603
-
604
- if repo.destination_branch:
605
- files_changed, files_added, files_removed = await git_repo.calculate_diff_between_commits(
606
- first_commit=repo.source_commit, second_commit=repo.destination_commit
607
- )
608
- else:
609
- files_added = await git_repo.list_all_files(commit=repo.source_commit)
610
-
611
- repo.files_removed = files_removed
612
- repo.files_added = files_added
613
- repo.files_changed = files_changed
614
-
615
-
616
- async def _populate_subscribers(
617
- branch_diff: ProposedChangeBranchDiff, diff_summary: list[NodeDiff], service: InfrahubServices, branch: str
618
- ) -> None:
619
- result = await service.client.execute_graphql(
620
- query=GATHER_GRAPHQL_QUERY_SUBSCRIBERS,
621
- branch_name=branch,
622
- variables={"members": get_modified_node_ids(diff_summary=diff_summary, branch=branch)},
623
- )
624
-
625
- for group in result[InfrahubKind.GRAPHQLQUERYGROUP]["edges"]:
626
- for subscriber in group["node"]["subscribers"]["edges"]:
627
- branch_diff.subscribers.append(
628
- ProposedChangeSubscriber(subscriber_id=subscriber["node"]["id"], kind=subscriber["node"]["__typename"])
629
- )