infrahub-server 1.4.12__py3-none-any.whl → 1.5.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 (234) hide show
  1. infrahub/actions/tasks.py +208 -16
  2. infrahub/api/artifact.py +3 -0
  3. infrahub/api/diff/diff.py +1 -1
  4. infrahub/api/internal.py +2 -0
  5. infrahub/api/query.py +2 -0
  6. infrahub/api/schema.py +27 -3
  7. infrahub/auth.py +5 -5
  8. infrahub/cli/__init__.py +2 -0
  9. infrahub/cli/db.py +160 -157
  10. infrahub/cli/dev.py +118 -0
  11. infrahub/cli/tasks.py +46 -0
  12. infrahub/cli/upgrade.py +56 -9
  13. infrahub/computed_attribute/tasks.py +19 -7
  14. infrahub/config.py +7 -2
  15. infrahub/core/attribute.py +35 -24
  16. infrahub/core/branch/enums.py +1 -1
  17. infrahub/core/branch/models.py +9 -5
  18. infrahub/core/branch/needs_rebase_status.py +11 -0
  19. infrahub/core/branch/tasks.py +72 -10
  20. infrahub/core/changelog/models.py +2 -10
  21. infrahub/core/constants/__init__.py +4 -0
  22. infrahub/core/constants/infrahubkind.py +1 -0
  23. infrahub/core/convert_object_type/object_conversion.py +201 -0
  24. infrahub/core/convert_object_type/repository_conversion.py +89 -0
  25. infrahub/core/convert_object_type/schema_mapping.py +27 -3
  26. infrahub/core/diff/calculator.py +2 -2
  27. infrahub/core/diff/model/path.py +4 -0
  28. infrahub/core/diff/payload_builder.py +1 -1
  29. infrahub/core/diff/query/artifact.py +1 -0
  30. infrahub/core/diff/query/delete_query.py +9 -5
  31. infrahub/core/diff/query/field_summary.py +1 -0
  32. infrahub/core/diff/query/merge.py +39 -23
  33. infrahub/core/graph/__init__.py +1 -1
  34. infrahub/core/initialization.py +7 -4
  35. infrahub/core/manager.py +3 -81
  36. infrahub/core/migrations/__init__.py +3 -0
  37. infrahub/core/migrations/exceptions.py +4 -0
  38. infrahub/core/migrations/graph/__init__.py +13 -10
  39. infrahub/core/migrations/graph/load_schema_branch.py +21 -0
  40. infrahub/core/migrations/graph/m013_convert_git_password_credential.py +1 -1
  41. infrahub/core/migrations/graph/m037_index_attr_vals.py +11 -30
  42. infrahub/core/migrations/graph/m039_ipam_reconcile.py +9 -7
  43. infrahub/core/migrations/graph/m041_deleted_dup_edges.py +149 -0
  44. infrahub/core/migrations/graph/m042_profile_attrs_in_db.py +147 -0
  45. infrahub/core/migrations/graph/m043_create_hfid_display_label_in_db.py +164 -0
  46. infrahub/core/migrations/graph/m044_backfill_hfid_display_label_in_db.py +864 -0
  47. infrahub/core/migrations/query/__init__.py +7 -8
  48. infrahub/core/migrations/query/attribute_add.py +8 -6
  49. infrahub/core/migrations/query/attribute_remove.py +134 -0
  50. infrahub/core/migrations/runner.py +54 -0
  51. infrahub/core/migrations/schema/attribute_kind_update.py +9 -3
  52. infrahub/core/migrations/schema/attribute_supports_profile.py +90 -0
  53. infrahub/core/migrations/schema/node_attribute_add.py +26 -5
  54. infrahub/core/migrations/schema/node_attribute_remove.py +13 -109
  55. infrahub/core/migrations/schema/node_kind_update.py +2 -1
  56. infrahub/core/migrations/schema/node_remove.py +2 -1
  57. infrahub/core/migrations/schema/placeholder_dummy.py +3 -2
  58. infrahub/core/migrations/shared.py +66 -19
  59. infrahub/core/models.py +2 -2
  60. infrahub/core/node/__init__.py +207 -54
  61. infrahub/core/node/create.py +53 -49
  62. infrahub/core/node/lock_utils.py +124 -0
  63. infrahub/core/node/node_property_attribute.py +230 -0
  64. infrahub/core/node/resource_manager/ip_address_pool.py +2 -1
  65. infrahub/core/node/resource_manager/ip_prefix_pool.py +2 -1
  66. infrahub/core/node/resource_manager/number_pool.py +2 -1
  67. infrahub/core/node/standard.py +1 -1
  68. infrahub/core/property.py +11 -0
  69. infrahub/core/protocols.py +8 -1
  70. infrahub/core/query/attribute.py +82 -15
  71. infrahub/core/query/diff.py +61 -16
  72. infrahub/core/query/ipam.py +16 -4
  73. infrahub/core/query/node.py +92 -212
  74. infrahub/core/query/relationship.py +44 -26
  75. infrahub/core/query/subquery.py +0 -8
  76. infrahub/core/relationship/model.py +69 -24
  77. infrahub/core/schema/__init__.py +56 -0
  78. infrahub/core/schema/attribute_schema.py +4 -2
  79. infrahub/core/schema/basenode_schema.py +42 -2
  80. infrahub/core/schema/definitions/core/__init__.py +2 -0
  81. infrahub/core/schema/definitions/core/check.py +1 -1
  82. infrahub/core/schema/definitions/core/generator.py +2 -0
  83. infrahub/core/schema/definitions/core/group.py +16 -2
  84. infrahub/core/schema/definitions/core/repository.py +7 -0
  85. infrahub/core/schema/definitions/core/transform.py +1 -1
  86. infrahub/core/schema/definitions/internal.py +12 -3
  87. infrahub/core/schema/generated/attribute_schema.py +2 -2
  88. infrahub/core/schema/generated/base_node_schema.py +6 -1
  89. infrahub/core/schema/manager.py +3 -0
  90. infrahub/core/schema/node_schema.py +1 -0
  91. infrahub/core/schema/relationship_schema.py +0 -1
  92. infrahub/core/schema/schema_branch.py +295 -10
  93. infrahub/core/schema/schema_branch_display.py +135 -0
  94. infrahub/core/schema/schema_branch_hfid.py +120 -0
  95. infrahub/core/validators/aggregated_checker.py +1 -1
  96. infrahub/database/graph.py +21 -0
  97. infrahub/display_labels/__init__.py +0 -0
  98. infrahub/display_labels/gather.py +48 -0
  99. infrahub/display_labels/models.py +240 -0
  100. infrahub/display_labels/tasks.py +192 -0
  101. infrahub/display_labels/triggers.py +22 -0
  102. infrahub/events/branch_action.py +27 -1
  103. infrahub/events/group_action.py +1 -1
  104. infrahub/events/node_action.py +1 -1
  105. infrahub/generators/constants.py +7 -0
  106. infrahub/generators/models.py +38 -12
  107. infrahub/generators/tasks.py +34 -16
  108. infrahub/git/base.py +42 -2
  109. infrahub/git/integrator.py +22 -14
  110. infrahub/git/tasks.py +52 -2
  111. infrahub/graphql/analyzer.py +9 -0
  112. infrahub/graphql/api/dependencies.py +2 -4
  113. infrahub/graphql/api/endpoints.py +16 -6
  114. infrahub/graphql/app.py +2 -4
  115. infrahub/graphql/initialization.py +2 -3
  116. infrahub/graphql/manager.py +213 -137
  117. infrahub/graphql/middleware.py +12 -0
  118. infrahub/graphql/mutations/branch.py +16 -0
  119. infrahub/graphql/mutations/computed_attribute.py +110 -3
  120. infrahub/graphql/mutations/convert_object_type.py +44 -13
  121. infrahub/graphql/mutations/display_label.py +118 -0
  122. infrahub/graphql/mutations/generator.py +25 -7
  123. infrahub/graphql/mutations/hfid.py +125 -0
  124. infrahub/graphql/mutations/ipam.py +73 -41
  125. infrahub/graphql/mutations/main.py +61 -178
  126. infrahub/graphql/mutations/profile.py +195 -0
  127. infrahub/graphql/mutations/proposed_change.py +8 -1
  128. infrahub/graphql/mutations/relationship.py +2 -2
  129. infrahub/graphql/mutations/repository.py +22 -83
  130. infrahub/graphql/mutations/resource_manager.py +2 -2
  131. infrahub/graphql/mutations/webhook.py +1 -1
  132. infrahub/graphql/queries/resource_manager.py +1 -1
  133. infrahub/graphql/registry.py +173 -0
  134. infrahub/graphql/resolvers/resolver.py +2 -0
  135. infrahub/graphql/schema.py +8 -1
  136. infrahub/graphql/schema_sort.py +170 -0
  137. infrahub/graphql/types/branch.py +4 -1
  138. infrahub/graphql/types/enums.py +3 -0
  139. infrahub/groups/tasks.py +1 -1
  140. infrahub/hfid/__init__.py +0 -0
  141. infrahub/hfid/gather.py +48 -0
  142. infrahub/hfid/models.py +240 -0
  143. infrahub/hfid/tasks.py +191 -0
  144. infrahub/hfid/triggers.py +22 -0
  145. infrahub/lock.py +119 -42
  146. infrahub/locks/__init__.py +0 -0
  147. infrahub/locks/tasks.py +37 -0
  148. infrahub/message_bus/types.py +1 -0
  149. infrahub/patch/plan_writer.py +2 -2
  150. infrahub/permissions/constants.py +2 -0
  151. infrahub/profiles/__init__.py +0 -0
  152. infrahub/profiles/node_applier.py +101 -0
  153. infrahub/profiles/queries/__init__.py +0 -0
  154. infrahub/profiles/queries/get_profile_data.py +98 -0
  155. infrahub/profiles/tasks.py +63 -0
  156. infrahub/proposed_change/tasks.py +67 -14
  157. infrahub/repositories/__init__.py +0 -0
  158. infrahub/repositories/create_repository.py +113 -0
  159. infrahub/server.py +9 -1
  160. infrahub/services/__init__.py +8 -5
  161. infrahub/services/adapters/http/__init__.py +5 -0
  162. infrahub/services/adapters/workflow/worker.py +14 -3
  163. infrahub/task_manager/event.py +5 -0
  164. infrahub/task_manager/models.py +7 -0
  165. infrahub/task_manager/task.py +73 -0
  166. infrahub/tasks/registry.py +6 -4
  167. infrahub/trigger/catalogue.py +4 -0
  168. infrahub/trigger/models.py +2 -0
  169. infrahub/trigger/setup.py +13 -4
  170. infrahub/trigger/tasks.py +6 -0
  171. infrahub/webhook/models.py +1 -1
  172. infrahub/workers/dependencies.py +3 -1
  173. infrahub/workers/infrahub_async.py +10 -2
  174. infrahub/workflows/catalogue.py +118 -3
  175. infrahub/workflows/initialization.py +21 -0
  176. infrahub/workflows/models.py +17 -2
  177. infrahub/workflows/utils.py +2 -1
  178. infrahub_sdk/branch.py +17 -8
  179. infrahub_sdk/checks.py +1 -1
  180. infrahub_sdk/client.py +376 -95
  181. infrahub_sdk/config.py +29 -2
  182. infrahub_sdk/convert_object_type.py +61 -0
  183. infrahub_sdk/ctl/branch.py +3 -0
  184. infrahub_sdk/ctl/check.py +2 -3
  185. infrahub_sdk/ctl/cli_commands.py +20 -12
  186. infrahub_sdk/ctl/config.py +8 -2
  187. infrahub_sdk/ctl/generator.py +6 -3
  188. infrahub_sdk/ctl/graphql.py +184 -0
  189. infrahub_sdk/ctl/repository.py +39 -1
  190. infrahub_sdk/ctl/schema.py +40 -10
  191. infrahub_sdk/ctl/task.py +110 -0
  192. infrahub_sdk/ctl/utils.py +4 -0
  193. infrahub_sdk/ctl/validate.py +5 -3
  194. infrahub_sdk/diff.py +4 -5
  195. infrahub_sdk/exceptions.py +2 -0
  196. infrahub_sdk/generator.py +7 -1
  197. infrahub_sdk/graphql/__init__.py +12 -0
  198. infrahub_sdk/graphql/constants.py +1 -0
  199. infrahub_sdk/graphql/plugin.py +85 -0
  200. infrahub_sdk/graphql/query.py +77 -0
  201. infrahub_sdk/{graphql.py → graphql/renderers.py} +88 -75
  202. infrahub_sdk/graphql/utils.py +40 -0
  203. infrahub_sdk/node/attribute.py +2 -0
  204. infrahub_sdk/node/node.py +28 -20
  205. infrahub_sdk/node/relationship.py +1 -3
  206. infrahub_sdk/playback.py +1 -2
  207. infrahub_sdk/protocols.py +54 -6
  208. infrahub_sdk/pytest_plugin/plugin.py +7 -4
  209. infrahub_sdk/pytest_plugin/utils.py +40 -0
  210. infrahub_sdk/repository.py +1 -2
  211. infrahub_sdk/schema/__init__.py +70 -4
  212. infrahub_sdk/schema/main.py +1 -0
  213. infrahub_sdk/schema/repository.py +8 -0
  214. infrahub_sdk/spec/models.py +7 -0
  215. infrahub_sdk/spec/object.py +54 -6
  216. infrahub_sdk/spec/processors/__init__.py +0 -0
  217. infrahub_sdk/spec/processors/data_processor.py +10 -0
  218. infrahub_sdk/spec/processors/factory.py +34 -0
  219. infrahub_sdk/spec/processors/range_expand_processor.py +56 -0
  220. infrahub_sdk/spec/range_expansion.py +118 -0
  221. infrahub_sdk/task/models.py +6 -4
  222. infrahub_sdk/timestamp.py +18 -6
  223. infrahub_sdk/transforms.py +1 -1
  224. {infrahub_server-1.4.12.dist-info → infrahub_server-1.5.0.dist-info}/METADATA +9 -10
  225. {infrahub_server-1.4.12.dist-info → infrahub_server-1.5.0.dist-info}/RECORD +233 -176
  226. infrahub_testcontainers/container.py +114 -2
  227. infrahub_testcontainers/docker-compose-cluster.test.yml +5 -0
  228. infrahub_testcontainers/docker-compose.test.yml +5 -0
  229. infrahub_testcontainers/models.py +2 -2
  230. infrahub_testcontainers/performance_test.py +4 -4
  231. infrahub/core/convert_object_type/conversion.py +0 -134
  232. {infrahub_server-1.4.12.dist-info → infrahub_server-1.5.0.dist-info}/LICENSE.txt +0 -0
  233. {infrahub_server-1.4.12.dist-info → infrahub_server-1.5.0.dist-info}/WHEEL +0 -0
  234. {infrahub_server-1.4.12.dist-info → infrahub_server-1.5.0.dist-info}/entry_points.txt +0 -0
@@ -109,7 +109,7 @@ class BranchRebasedEvent(InfrahubEvent):
109
109
 
110
110
  event_name: ClassVar[str] = f"{EVENT_NAMESPACE}.branch.rebased"
111
111
 
112
- branch_id: str = Field(..., description="The ID of the mutated node")
112
+ branch_id: str = Field(..., description="The ID of the branch")
113
113
  branch_name: str = Field(..., description="The name of the branch")
114
114
 
115
115
  def get_resource(self) -> dict[str, str]:
@@ -128,3 +128,29 @@ class BranchRebasedEvent(InfrahubEvent):
128
128
  RefreshRegistryRebasedBranch(branch=self.branch_name),
129
129
  ]
130
130
  return events
131
+
132
+
133
+ class BranchMigratedEvent(InfrahubEvent):
134
+ """Event generated when a branch has been migrated"""
135
+
136
+ event_name: ClassVar[str] = f"{EVENT_NAMESPACE}.branch.migrated"
137
+
138
+ branch_id: str = Field(..., description="The ID of the branch")
139
+ branch_name: str = Field(..., description="The name of the branch")
140
+
141
+ def get_resource(self) -> dict[str, str]:
142
+ return {
143
+ "prefect.resource.id": f"infrahub.branch.{self.branch_name}",
144
+ "infrahub.branch.id": self.branch_id,
145
+ "infrahub.branch.name": self.branch_name,
146
+ }
147
+
148
+ def get_messages(self) -> list[InfrahubMessage]:
149
+ events: list[InfrahubMessage] = [
150
+ # EventBranchMigrated(
151
+ # branch=self.branch,
152
+ # meta=self.get_message_meta(),
153
+ # ),
154
+ RefreshRegistryRebasedBranch(branch=self.branch_name),
155
+ ]
156
+ return events
@@ -22,7 +22,7 @@ class GroupMutatedEvent(InfrahubEvent):
22
22
  def get_related(self) -> list[dict[str, str]]:
23
23
  related = super().get_related()
24
24
 
25
- if self.kind in [InfrahubKind.GENERATORGROUP, InfrahubKind.GRAPHQLQUERYGROUP]:
25
+ if self.kind in [InfrahubKind.GENERATORGROUP, InfrahubKind.GENERATORAWAREGROUP, InfrahubKind.GRAPHQLQUERYGROUP]:
26
26
  # Temporary workaround to avoid too large payloads for the related field
27
27
  return related
28
28
 
@@ -24,7 +24,7 @@ class NodeMutatedEvent(InfrahubEvent):
24
24
 
25
25
  def get_related(self) -> list[dict[str, str]]:
26
26
  related = super().get_related()
27
- if self.kind in [InfrahubKind.GENERATORGROUP, InfrahubKind.GRAPHQLQUERYGROUP]:
27
+ if self.kind in [InfrahubKind.GENERATORGROUP, InfrahubKind.GENERATORAWAREGROUP, InfrahubKind.GRAPHQLQUERYGROUP]:
28
28
  # Temporary workaround to avoid too large payloads for the related field
29
29
  return related
30
30
 
@@ -0,0 +1,7 @@
1
+ from enum import Enum
2
+
3
+
4
+ class GeneratorDefinitionRunSource(Enum):
5
+ PROPOSED_CHANGE = "proposed_change"
6
+ MERGE = "merge"
7
+ UNKNOWN = "unknown"
@@ -6,7 +6,7 @@ from pydantic import BaseModel, ConfigDict, Field
6
6
  class RequestGeneratorRun(BaseModel):
7
7
  """Runs a generator."""
8
8
 
9
- generator_definition: ProposedChangeGeneratorDefinition = Field(..., description="The Generator definition")
9
+ generator_definition: GeneratorDefinitionModel = Field(..., description="The Generator definition")
10
10
  generator_instance: str | None = Field(
11
11
  default=None, description="The id of the generator instance if it previously existed"
12
12
  )
@@ -31,14 +31,40 @@ class RequestGeneratorDefinitionRun(BaseModel):
31
31
  target_members: list[str] = Field(default_factory=list, description="List of targets to run the generator for")
32
32
 
33
33
 
34
- class ProposedChangeGeneratorDefinition(BaseModel):
35
- definition_id: str
36
- definition_name: str
37
- query_name: str
38
- convert_query_response: bool
39
- query_models: list[str]
40
- repository_id: str
41
- class_name: str
42
- file_path: str
43
- parameters: dict
44
- group_id: str
34
+ class GeneratorDefinitionModel(BaseModel):
35
+ definition_id: str = Field(..., description="The id of the generator definition.")
36
+ definition_name: str = Field(..., description="The name of the generator definition.")
37
+ query_name: str = Field(..., description="The name of the query to use when collecting data.")
38
+ convert_query_response: bool = Field(
39
+ ...,
40
+ description="Decide if the generator should convert the result of the GraphQL query to SDK InfrahubNode objects.",
41
+ )
42
+ class_name: str = Field(..., description="The name of the generator class to run.")
43
+ file_path: str = Field(..., description="The file path of the generator in the repository.")
44
+ group_id: str = Field(..., description="The group to target when running this generator")
45
+ parameters: dict = Field(..., description="The input parameters required to run this check")
46
+
47
+ execute_in_proposed_change: bool = Field(
48
+ ..., description="Indicates if the generator should execute in a proposed change."
49
+ )
50
+ execute_after_merge: bool = Field(..., description="Indicates if the generator should execute after a merge.")
51
+
52
+ @classmethod
53
+ def from_pc_generator_definition(cls, model: ProposedChangeGeneratorDefinition) -> GeneratorDefinitionModel:
54
+ return GeneratorDefinitionModel(
55
+ definition_id=model.definition_id,
56
+ definition_name=model.definition_name,
57
+ query_name=model.query_name,
58
+ convert_query_response=model.convert_query_response,
59
+ class_name=model.class_name,
60
+ file_path=model.file_path,
61
+ group_id=model.group_id,
62
+ parameters=model.parameters,
63
+ execute_in_proposed_change=model.execute_in_proposed_change,
64
+ execute_after_merge=model.execute_after_merge,
65
+ )
66
+
67
+
68
+ class ProposedChangeGeneratorDefinition(GeneratorDefinitionModel):
69
+ query_models: list[str] = Field(..., description="The models to use when collecting data.")
70
+ repository_id: str = Field(..., description="The id of the repository.")
@@ -14,7 +14,9 @@ from prefect.states import Completed, Failed
14
14
  from infrahub import lock
15
15
  from infrahub.context import InfrahubContext # noqa: TC001 needed for prefect flow
16
16
  from infrahub.core.constants import GeneratorInstanceStatus, InfrahubKind
17
+ from infrahub.generators.constants import GeneratorDefinitionRunSource
17
18
  from infrahub.generators.models import (
19
+ GeneratorDefinitionModel,
18
20
  ProposedChangeGeneratorDefinition,
19
21
  RequestGeneratorDefinitionRun,
20
22
  RequestGeneratorRun,
@@ -53,9 +55,12 @@ async def run_generator(model: RequestGeneratorRun) -> None:
53
55
  name=model.generator_definition.definition_name,
54
56
  class_name=model.generator_definition.class_name,
55
57
  file_path=model.generator_definition.file_path,
58
+ parameters=model.generator_definition.parameters,
56
59
  query=model.generator_definition.query_name,
57
60
  targets=model.generator_definition.group_id,
58
61
  convert_query_response=model.generator_definition.convert_query_response,
62
+ execute_in_proposed_change=model.generator_definition.execute_in_proposed_change,
63
+ execute_after_merge=model.generator_definition.execute_after_merge,
59
64
  )
60
65
 
61
66
  commit_worktree = repository.get_commit_worktree(commit=model.commit)
@@ -79,6 +84,8 @@ async def run_generator(model: RequestGeneratorRun) -> None:
79
84
  params=model.variables,
80
85
  generator_instance=generator_instance.id,
81
86
  convert_query_response=generator_definition.convert_query_response,
87
+ execute_in_proposed_change=generator_definition.execute_in_proposed_change,
88
+ execute_after_merge=generator_definition.execute_after_merge,
82
89
  infrahub_node=InfrahubNode,
83
90
  )
84
91
  await generator.run(identifier=generator_definition.name)
@@ -128,28 +135,39 @@ async def _define_instance(model: RequestGeneratorRun, client: InfrahubClient) -
128
135
 
129
136
 
130
137
  @flow(name="generator-definition-run", flow_run_name="Run all generators")
131
- async def run_generator_definition(branch: str, context: InfrahubContext) -> None:
138
+ async def run_generator_definition(
139
+ branch: str, context: InfrahubContext, source: GeneratorDefinitionRunSource = GeneratorDefinitionRunSource.UNKNOWN
140
+ ) -> None:
132
141
  await add_tags(branches=[branch])
133
142
 
134
143
  generators = await get_client().filters(
135
144
  kind=InfrahubKind.GENERATORDEFINITION, prefetch_relationships=True, populate_store=True, branch=branch
136
145
  )
137
146
 
138
- generator_definitions = [
139
- ProposedChangeGeneratorDefinition(
140
- definition_id=generator.id,
141
- definition_name=generator.name.value,
142
- class_name=generator.class_name.value,
143
- file_path=generator.file_path.value,
144
- query_name=generator.query.peer.name.value,
145
- query_models=generator.query.peer.models.value,
146
- repository_id=generator.repository.peer.id,
147
- parameters=generator.parameters.value,
148
- group_id=generator.targets.peer.id,
149
- convert_query_response=generator.convert_query_response.value,
147
+ generator_definitions: list[ProposedChangeGeneratorDefinition] = []
148
+
149
+ for generator in generators:
150
+ if (
151
+ source == GeneratorDefinitionRunSource.PROPOSED_CHANGE and not generator.execute_in_proposed_change.value
152
+ ) or (source == GeneratorDefinitionRunSource.MERGE and not generator.execute_after_merge.value):
153
+ continue
154
+
155
+ generator_definitions.append(
156
+ ProposedChangeGeneratorDefinition(
157
+ definition_id=generator.id,
158
+ definition_name=generator.name.value,
159
+ class_name=generator.class_name.value,
160
+ file_path=generator.file_path.value,
161
+ query_name=generator.query.peer.name.value,
162
+ query_models=generator.query.peer.models.value,
163
+ repository_id=generator.repository.peer.id,
164
+ parameters=generator.parameters.value,
165
+ group_id=generator.targets.peer.id,
166
+ convert_query_response=generator.convert_query_response.value,
167
+ execute_in_proposed_change=generator.execute_in_proposed_change.value,
168
+ execute_after_merge=generator.execute_after_merge.value,
169
+ )
150
170
  )
151
- for generator in generators
152
- ]
153
171
 
154
172
  for generator_definition in generator_definitions:
155
173
  model = RequestGeneratorDefinitionRun(branch=branch, generator_definition=generator_definition)
@@ -209,7 +227,7 @@ async def request_generator_definition_run(
209
227
 
210
228
  generator_instance = instance_by_member.get(member.id)
211
229
  request_generator_run_model = RequestGeneratorRun(
212
- generator_definition=model.generator_definition,
230
+ generator_definition=GeneratorDefinitionModel.from_pc_generator_definition(model.generator_definition),
213
231
  commit=repository.commit.value,
214
232
  generator_instance=generator_instance,
215
233
  repository_id=repository.id,
infrahub/git/base.py CHANGED
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING, NoReturn
7
7
  from uuid import UUID # noqa: TC003
8
8
 
9
9
  import git
10
- from git import Blob, Repo
10
+ from git import BadName, Blob, Repo
11
11
  from git.exc import GitCommandError, InvalidGitRepositoryError
12
12
  from git.refs.remote import RemoteReference
13
13
  from infrahub_sdk import InfrahubClient # noqa: TC002
@@ -67,6 +67,15 @@ class RepoFileInformation(BaseModel):
67
67
  """Extension of the file Example: py """
68
68
 
69
69
 
70
+ class RepoChangedFiles(BaseModel):
71
+ added: list[str] = Field(default_factory=list)
72
+ copied: list[tuple[str, str]] = Field(default_factory=list)
73
+ deleted: list[str] = Field(default_factory=list)
74
+ renamed: list[tuple[str, str]] = Field(default_factory=list)
75
+ modified: list[str] = Field(default_factory=list)
76
+ type_changed: list[tuple[str, str]] = Field(default_factory=list)
77
+
78
+
70
79
  def extract_repo_file_information(
71
80
  full_filename: Path, repo_directory: Path, worktree_directory: Path | None = None
72
81
  ) -> RepoFileInformation:
@@ -932,7 +941,10 @@ class InfrahubRepositoryBase(BaseModel, ABC):
932
941
  def _raise_enriched_error_static(
933
942
  error: GitCommandError, name: str, location: str, branch_name: str | None = None
934
943
  ) -> NoReturn:
935
- if "Repository not found" in error.stderr or "does not appear to be a git" in error.stderr:
944
+ if any(
945
+ err in error.stderr
946
+ for err in ("Repository not found", "does not appear to be a git", "Failed to connect to")
947
+ ):
936
948
  raise RepositoryConnectionError(identifier=name) from error
937
949
 
938
950
  if "error: pathspec" in error.stderr:
@@ -970,3 +982,31 @@ class InfrahubRepositoryBase(BaseModel, ABC):
970
982
  if branch_name == self.default_branch and branch_name != registry.default_branch:
971
983
  return registry.default_branch
972
984
  return branch_name
985
+
986
+ def get_changed_files(self, first_commit: str, second_commit: str | None = None) -> RepoChangedFiles:
987
+ """Return the changes between two commits in this repo."""
988
+ changes = RepoChangedFiles()
989
+ repo = self.get_git_repo_main()
990
+
991
+ try:
992
+ commit_a = repo.commit(first_commit)
993
+ commit_b = repo.commit(second_commit) if second_commit else repo.head.commit
994
+ except BadName as exc:
995
+ raise CommitNotFoundError(identifier=str(self.id), commit=exc.args[0]) from exc
996
+
997
+ for diff in commit_a.diff(commit_b):
998
+ match diff.change_type:
999
+ case "A":
1000
+ changes.added.append(diff.b_path)
1001
+ case "C":
1002
+ changes.copied.append((diff.a_path, diff.b_path))
1003
+ case "D":
1004
+ changes.deleted.append(diff.a_path)
1005
+ case "R":
1006
+ changes.renamed.append((diff.a_path, diff.b_path))
1007
+ case "M":
1008
+ changes.modified.append(diff.b_path)
1009
+ case "T":
1010
+ changes.type_changed.append((diff.a_path, diff.b_path))
1011
+
1012
+ return changes
@@ -226,7 +226,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
226
226
  )
227
227
  )
228
228
 
229
- @task(name="import-jinja2-tansforms", task_run_name="Import Jinja2 transform", cache_policy=NONE) # type: ignore[arg-type]
229
+ @task(name="import-jinja2-transforms", task_run_name="Import Jinja2 transform", cache_policy=NONE)
230
230
  async def import_jinja2_transforms(
231
231
  self,
232
232
  branch_name: str,
@@ -331,7 +331,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
331
331
 
332
332
  await existing_transform.save()
333
333
 
334
- @task(name="import-artifact-definitions", task_run_name="Import Artifact Definitions", cache_policy=NONE) # type: ignore[arg-type]
334
+ @task(name="import-artifact-definitions", task_run_name="Import Artifact Definitions", cache_policy=NONE)
335
335
  async def import_artifact_definitions(
336
336
  self,
337
337
  branch_name: str,
@@ -432,7 +432,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
432
432
 
433
433
  await existing_artifact_definition.save()
434
434
 
435
- @task(name="repository-get-config", task_run_name="get repository config", cache_policy=NONE) # type: ignore[arg-type]
435
+ @task(name="repository-get-config", task_run_name="get repository config", cache_policy=NONE)
436
436
  async def get_repository_config(self, branch_name: str, commit: str) -> InfrahubRepositoryConfig | None:
437
437
  branch_wt = self.get_worktree(identifier=commit or branch_name)
438
438
  log = get_run_logger()
@@ -469,7 +469,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
469
469
  log.error(f"Unable to load the configuration file {config_file_name}, the format is not valid : {exc}")
470
470
  return None
471
471
 
472
- @task(name="import-schema-files", task_run_name="Import schema files", cache_policy=NONE) # type: ignore[arg-type]
472
+ @task(name="import-schema-files", task_run_name="Import schema files", cache_policy=NONE)
473
473
  async def import_schema_files(self, branch_name: str, commit: str, config_file: InfrahubRepositoryConfig) -> None:
474
474
  log = get_run_logger()
475
475
  branch_wt = self.get_worktree(identifier=commit or branch_name)
@@ -541,7 +541,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
541
541
  for schema_file in schemas_data:
542
542
  log.info(f"schema '{schema_file.identifier}' loaded successfully!")
543
543
 
544
- @task(name="import-graphql-queries", task_run_name="Import GraphQL Queries", cache_policy=NONE) # type: ignore[arg-type]
544
+ @task(name="import-graphql-queries", task_run_name="Import GraphQL Queries", cache_policy=NONE)
545
545
  async def import_all_graphql_query(
546
546
  self, branch_name: str, commit: str, config_file: InfrahubRepositoryConfig
547
547
  ) -> None:
@@ -599,7 +599,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
599
599
  await obj.save()
600
600
  return obj
601
601
 
602
- @task(name="import-python-check-definitions", task_run_name="Import Python Check Definitions", cache_policy=NONE) # type: ignore[arg-type]
602
+ @task(name="import-python-check-definitions", task_run_name="Import Python Check Definitions", cache_policy=NONE)
603
603
  async def import_python_check_definitions(
604
604
  self, branch_name: str, commit: str, config_file: InfrahubRepositoryConfig
605
605
  ) -> None:
@@ -670,7 +670,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
670
670
  log.info(f"CheckDefinition '{check_name!r}' not found locally, deleting")
671
671
  await check_definition_in_graph[check_name].delete()
672
672
 
673
- @task(name="import-generator-definitions", task_run_name="Import Generator Definitions", cache_policy=NONE) # type: ignore[arg-type]
673
+ @task(name="import-generator-definitions", task_run_name="Import Generator Definitions", cache_policy=NONE)
674
674
  async def import_generator_definitions(
675
675
  self, branch_name: str, commit: str, config_file: InfrahubRepositoryConfig
676
676
  ) -> None:
@@ -756,11 +756,13 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
756
756
  or existing_generator.parameters.value != generator.parameters
757
757
  or existing_generator.convert_query_response.value != generator.convert_query_response
758
758
  or existing_generator.targets.id != generator.targets
759
+ or existing_generator.execute_in_proposed_change.value != generator.execute_in_proposed_change
760
+ or existing_generator.execute_after_merge.value != generator.execute_after_merge
759
761
  ):
760
762
  return True
761
763
  return False
762
764
 
763
- @task(name="import-python-transforms", task_run_name="Import Python Transforms", cache_policy=NONE) # type: ignore[arg-type]
765
+ @task(name="import-python-transforms", task_run_name="Import Python Transforms", cache_policy=NONE)
764
766
  async def import_python_transforms(
765
767
  self, branch_name: str, commit: str, config_file: InfrahubRepositoryConfig
766
768
  ) -> None:
@@ -885,7 +887,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
885
887
  file_type=file_type,
886
888
  )
887
889
 
888
- @task(name="import-objects", task_run_name="Import Objects", cache_policy=NONE) # type: ignore[arg-type]
890
+ @task(name="import-objects", task_run_name="Import Objects", cache_policy=NONE)
889
891
  async def import_objects(
890
892
  self,
891
893
  branch_name: str,
@@ -905,7 +907,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
905
907
  object_type=RepositoryObjects.MENU,
906
908
  )
907
909
 
908
- @task(name="check-definition-get", task_run_name="Get Check Definition", cache_policy=NONE) # type: ignore[arg-type]
910
+ @task(name="check-definition-get", task_run_name="Get Check Definition", cache_policy=NONE)
909
911
  async def get_check_definition(
910
912
  self,
911
913
  branch_name: str,
@@ -945,7 +947,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
945
947
  raise
946
948
  return checks
947
949
 
948
- @task(name="python-transform-get", task_run_name="Get Python Transform", cache_policy=NONE) # type: ignore[arg-type]
950
+ @task(name="python-transform-get", task_run_name="Get Python Transform", cache_policy=NONE)
949
951
  async def get_python_transforms(
950
952
  self, branch_name: str, module: types.ModuleType, file_path: str, transform: InfrahubPythonTransformConfig
951
953
  ) -> list[TransformPythonInformation]:
@@ -1023,6 +1025,12 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
1023
1025
  if existing_generator.targets.id != generator.targets:
1024
1026
  existing_generator.targets = {"id": generator.targets, "source": str(self.id), "is_protected": True}
1025
1027
 
1028
+ if existing_generator.execute_in_proposed_change.value != generator.execute_in_proposed_change:
1029
+ existing_generator.execute_in_proposed_change.value = generator.execute_in_proposed_change
1030
+
1031
+ if existing_generator.execute_after_merge.value != generator.execute_after_merge:
1032
+ existing_generator.execute_after_merge.value = generator.execute_after_merge
1033
+
1026
1034
  await existing_generator.save()
1027
1035
 
1028
1036
  async def create_python_check_definition(
@@ -1152,7 +1160,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
1152
1160
  await self.import_python_transforms(branch_name=branch_name, commit=commit, config_file=config_file) # type: ignore[misc]
1153
1161
  await self.import_generator_definitions(branch_name=branch_name, commit=commit, config_file=config_file) # type: ignore[misc]
1154
1162
 
1155
- @task(name="jinja2-template-render", task_run_name="Render Jinja2 template", cache_policy=NONE) # type: ignore[arg-type]
1163
+ @task(name="jinja2-template-render", task_run_name="Render Jinja2 template", cache_policy=NONE)
1156
1164
  async def render_jinja2_template(self, commit: str, location: str, data: dict) -> str:
1157
1165
  log = get_run_logger()
1158
1166
  commit_worktree = self.get_commit_worktree(commit=commit)
@@ -1168,7 +1176,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
1168
1176
  repository_name=self.name, commit=commit, location=location, message=exc.message
1169
1177
  ) from exc
1170
1178
 
1171
- @task(name="python-check-execute", task_run_name="Execute Python Check", cache_policy=NONE) # type: ignore[arg-type]
1179
+ @task(name="python-check-execute", task_run_name="Execute Python Check", cache_policy=NONE)
1172
1180
  async def execute_python_check(
1173
1181
  self,
1174
1182
  branch_name: str,
@@ -1227,7 +1235,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
1227
1235
  repository_name=self.name, class_name=class_name, commit=commit, location=location, message=str(exc)
1228
1236
  ) from exc
1229
1237
 
1230
- @task(name="python-transform-execute", task_run_name="Execute Python Transform", cache_policy=NONE) # type: ignore[arg-type]
1238
+ @task(name="python-transform-execute", task_run_name="Execute Python Transform", cache_policy=NONE)
1231
1239
  async def execute_python_transform(
1232
1240
  self,
1233
1241
  branch_name: str,
infrahub/git/tasks.py CHANGED
@@ -1,3 +1,5 @@
1
+ from typing import Any
2
+
1
3
  from infrahub_sdk import InfrahubClient
2
4
  from infrahub_sdk.protocols import (
3
5
  CoreArtifact,
@@ -14,7 +16,12 @@ from prefect.logging import get_run_logger
14
16
 
15
17
  from infrahub import lock
16
18
  from infrahub.context import InfrahubContext
17
- from infrahub.core.constants import InfrahubKind, RepositoryInternalStatus, ValidatorConclusion
19
+ from infrahub.core.constants import (
20
+ InfrahubKind,
21
+ RepositoryInternalStatus,
22
+ RepositoryOperationalStatus,
23
+ ValidatorConclusion,
24
+ )
18
25
  from infrahub.core.manager import NodeManager
19
26
  from infrahub.core.registry import registry
20
27
  from infrahub.exceptions import CheckError, RepositoryError
@@ -152,6 +159,39 @@ async def create_branch(branch: str, branch_id: str) -> None:
152
159
  pass
153
160
 
154
161
 
162
+ @flow(name="sync-git-repo-with-origin", flow_run_name="Sync git repo with origin")
163
+ async def sync_git_repo_with_origin_and_tag_on_failure(
164
+ client: InfrahubClient,
165
+ repository_id: str,
166
+ repository_name: str,
167
+ repository_location: str,
168
+ internal_status: str,
169
+ default_branch_name: str,
170
+ operational_status: str,
171
+ staging_branch: str | None = None,
172
+ infrahub_branch: str | None = None,
173
+ ) -> None:
174
+ repo = await InfrahubRepository.init(
175
+ id=repository_id,
176
+ name=repository_name,
177
+ location=repository_location,
178
+ client=client,
179
+ internal_status=internal_status,
180
+ default_branch_name=default_branch_name,
181
+ )
182
+
183
+ try:
184
+ await repo.sync(staging_branch=staging_branch)
185
+ except RepositoryError:
186
+ if operational_status == RepositoryOperationalStatus.ONLINE.value:
187
+ params: dict[str, Any] = {
188
+ "branches": [infrahub_branch] if infrahub_branch else [],
189
+ "nodes": [str(repository_id)],
190
+ }
191
+ await add_tags(**params)
192
+ raise
193
+
194
+
155
195
  @flow(name="git_repositories_sync", flow_run_name="Sync Git Repositories")
156
196
  async def sync_remote_repositories() -> None:
157
197
  log = get_run_logger()
@@ -204,7 +244,17 @@ async def sync_remote_repositories() -> None:
204
244
  continue
205
245
 
206
246
  try:
207
- await repo.sync(staging_branch=staging_branch)
247
+ await sync_git_repo_with_origin_and_tag_on_failure(
248
+ client=client,
249
+ repository_id=repository_data.repository.id,
250
+ repository_name=repository_data.repository.name.value,
251
+ repository_location=repository_data.repository.location.value,
252
+ internal_status=active_internal_status,
253
+ default_branch_name=repository_data.repository.default_branch.value,
254
+ operational_status=repository_data.repository.operational_status.value,
255
+ staging_branch=staging_branch,
256
+ infrahub_branch=infrahub_branch,
257
+ )
208
258
  # Tell workers to fetch to stay in sync
209
259
  message = messages.RefreshGitFetch(
210
260
  meta=Meta(initiator_id=WORKER_IDENTITY, request_id=get_log_data().get("request_id", "")),
@@ -312,6 +312,13 @@ class GraphQLQueryReport:
312
312
  return []
313
313
 
314
314
  def required_argument(self, argument: GraphQLArgument) -> bool:
315
+ if argument.name == "ids" and argument.kind == "list_value":
316
+ for variable in self.variables:
317
+ if f"['${variable.name}']" == argument.as_variable_name and variable.required:
318
+ return True
319
+
320
+ return False
321
+
315
322
  if not argument.is_variable:
316
323
  # If the argument isn't a variable it would have been
317
324
  # statically defined in the input and as such required
@@ -364,6 +371,8 @@ class GraphQLQueryReport:
364
371
  if [[argument.name]] == query.infrahub_model.uniqueness_constraints:
365
372
  if self.required_argument(argument=argument):
366
373
  targets_single_query = True
374
+ elif argument.name == "ids" and self.required_argument(argument=argument):
375
+ targets_single_query = True
367
376
 
368
377
  if not targets_single_query:
369
378
  return False
@@ -1,5 +1,3 @@
1
- from typing import Any
2
-
3
1
  from infrahub import config
4
2
 
5
3
  from ..app import InfrahubGraphQLApp
@@ -36,5 +34,5 @@ def build_graphql_query_permission_checker() -> GraphQLQueryPermissionChecker:
36
34
  )
37
35
 
38
36
 
39
- def build_graphql_app(**kwargs: Any) -> InfrahubGraphQLApp:
40
- return InfrahubGraphQLApp(build_graphql_query_permission_checker(), **kwargs)
37
+ def build_graphql_app() -> InfrahubGraphQLApp:
38
+ return InfrahubGraphQLApp(build_graphql_query_permission_checker())
@@ -2,14 +2,15 @@ from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING
4
4
 
5
- from fastapi import APIRouter, Depends
5
+ from fastapi import APIRouter, Depends, Query
6
6
  from fastapi.responses import PlainTextResponse
7
- from graphql import print_schema
7
+ from graphql import parse, print_ast, print_schema
8
8
  from starlette.routing import Route, WebSocketRoute
9
9
 
10
10
  from infrahub.api.dependencies import get_branch_dep, get_current_user
11
11
  from infrahub.core import registry
12
- from infrahub.graphql.manager import GraphQLSchemaManager
12
+ from infrahub.graphql.registry import registry as graphql_registry
13
+ from infrahub.graphql.schema_sort import sort_schema_ast
13
14
 
14
15
  from .dependencies import build_graphql_app
15
16
 
@@ -27,11 +28,20 @@ router.routes.append(WebSocketRoute(path="/graphql", endpoint=graphql_app))
27
28
  router.routes.append(WebSocketRoute(path="/graphql/{branch_name:str}", endpoint=graphql_app))
28
29
 
29
30
 
30
- @router.get("/schema.graphql", include_in_schema=False)
31
+ @router.get("/schema.graphql")
31
32
  async def get_graphql_schema(
32
- branch: Branch = Depends(get_branch_dep), _: AccountSession = Depends(get_current_user)
33
+ branch: Branch = Depends(get_branch_dep),
34
+ _: AccountSession = Depends(get_current_user),
35
+ sort_schema: bool = Query(default=False, alias="sorted", description="Whether to sort the schema alphabetically."),
33
36
  ) -> PlainTextResponse:
34
37
  schema_branch = registry.schema.get_schema_branch(name=branch.name)
35
- gqlm = GraphQLSchemaManager.get_manager_for_branch(branch=branch, schema_branch=schema_branch)
38
+ gqlm = graphql_registry.get_manager_for_branch(branch=branch, schema_branch=schema_branch)
36
39
  graphql_schema = gqlm.get_graphql_schema()
40
+
41
+ if sort_schema:
42
+ schema_str = print_schema(graphql_schema)
43
+ schema_ast = parse(schema_str)
44
+ sorted_schema_ast = sort_schema_ast(schema_ast)
45
+ return PlainTextResponse(content=print_ast(sorted_schema_ast))
46
+
37
47
  return PlainTextResponse(content=print_schema(graphql_schema))
infrahub/graphql/app.py CHANGED
@@ -23,7 +23,6 @@ from graphql import (
23
23
  ExecutionResult,
24
24
  GraphQLError,
25
25
  GraphQLFormattedError,
26
- Middleware,
27
26
  OperationType,
28
27
  graphql,
29
28
  parse,
@@ -59,6 +58,7 @@ from .metrics import (
59
58
  GRAPHQL_RESPONSE_SIZE_METRICS,
60
59
  GRAPHQL_TOP_LEVEL_QUERIES_METRICS,
61
60
  )
61
+ from .middleware import raise_on_mutation_on_branch_needing_rebase
62
62
 
63
63
  if TYPE_CHECKING:
64
64
  import graphene
@@ -99,7 +99,6 @@ class InfrahubGraphQLApp:
99
99
  *,
100
100
  on_get: Callable[[Request], Response | Awaitable[Response]] | None = None,
101
101
  root_value: RootValue = None,
102
- middleware: Middleware | None = None,
103
102
  error_formatter: Callable[[GraphQLError], GraphQLFormattedError] = format_error,
104
103
  execution_context_class: type[ExecutionContext] | None = None,
105
104
  ) -> None:
@@ -107,7 +106,6 @@ class InfrahubGraphQLApp:
107
106
  self.on_get = on_get
108
107
  self.root_value = root_value
109
108
  self.error_formatter = error_formatter
110
- self.middleware = middleware
111
109
  self.execution_context_class = execution_context_class
112
110
  self.logger = get_logger(name="infrahub.graphql")
113
111
  self.permission_checker = permission_checker
@@ -259,7 +257,7 @@ class InfrahubGraphQLApp:
259
257
  source=query,
260
258
  context_value=graphql_params.context,
261
259
  root_value=self.root_value,
262
- middleware=self.middleware,
260
+ middleware=[raise_on_mutation_on_branch_needing_rebase],
263
261
  variable_values=variable_values,
264
262
  operation_name=operation_name,
265
263
  execution_context_class=self.execution_context_class,
@@ -9,12 +9,11 @@ from infrahub.context import InfrahubContext
9
9
  from infrahub.core import registry
10
10
  from infrahub.core.timestamp import Timestamp
11
11
  from infrahub.exceptions import InitializationError
12
+ from infrahub.graphql.registry import registry as graphql_registry
12
13
  from infrahub.graphql.resolvers.many_relationship import ManyRelationshipResolver
13
14
  from infrahub.graphql.resolvers.single_relationship import SingleRelationshipResolver
14
15
  from infrahub.permissions import PermissionManager
15
16
 
16
- from .manager import GraphQLSchemaManager
17
-
18
17
  if TYPE_CHECKING:
19
18
  from graphql import GraphQLSchema
20
19
  from starlette.requests import HTTPConnection
@@ -91,7 +90,7 @@ async def prepare_graphql_params(
91
90
  ) -> GraphqlParams:
92
91
  branch = registry.get_branch_from_registry(branch=branch)
93
92
  schema_branch = registry.schema.get_schema_branch(name=branch.name)
94
- gqlm = GraphQLSchemaManager.get_manager_for_branch(branch=branch, schema_branch=schema_branch)
93
+ gqlm = graphql_registry.get_manager_for_branch(branch=branch, schema_branch=schema_branch)
95
94
  gql_schema = gqlm.get_graphql_schema(
96
95
  include_query=include_query,
97
96
  include_mutation=include_mutation,