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.
- infrahub/actions/tasks.py +208 -16
- infrahub/api/artifact.py +3 -0
- infrahub/api/diff/diff.py +1 -1
- infrahub/api/internal.py +2 -0
- infrahub/api/query.py +2 -0
- infrahub/api/schema.py +27 -3
- infrahub/auth.py +5 -5
- infrahub/cli/__init__.py +2 -0
- infrahub/cli/db.py +160 -157
- infrahub/cli/dev.py +118 -0
- infrahub/cli/tasks.py +46 -0
- infrahub/cli/upgrade.py +56 -9
- infrahub/computed_attribute/tasks.py +19 -7
- infrahub/config.py +7 -2
- infrahub/core/attribute.py +35 -24
- infrahub/core/branch/enums.py +1 -1
- infrahub/core/branch/models.py +9 -5
- infrahub/core/branch/needs_rebase_status.py +11 -0
- infrahub/core/branch/tasks.py +72 -10
- infrahub/core/changelog/models.py +2 -10
- infrahub/core/constants/__init__.py +4 -0
- infrahub/core/constants/infrahubkind.py +1 -0
- infrahub/core/convert_object_type/object_conversion.py +201 -0
- infrahub/core/convert_object_type/repository_conversion.py +89 -0
- infrahub/core/convert_object_type/schema_mapping.py +27 -3
- infrahub/core/diff/calculator.py +2 -2
- infrahub/core/diff/model/path.py +4 -0
- infrahub/core/diff/payload_builder.py +1 -1
- infrahub/core/diff/query/artifact.py +1 -0
- infrahub/core/diff/query/delete_query.py +9 -5
- infrahub/core/diff/query/field_summary.py +1 -0
- infrahub/core/diff/query/merge.py +39 -23
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/initialization.py +7 -4
- infrahub/core/manager.py +3 -81
- infrahub/core/migrations/__init__.py +3 -0
- infrahub/core/migrations/exceptions.py +4 -0
- infrahub/core/migrations/graph/__init__.py +13 -10
- infrahub/core/migrations/graph/load_schema_branch.py +21 -0
- infrahub/core/migrations/graph/m013_convert_git_password_credential.py +1 -1
- infrahub/core/migrations/graph/m037_index_attr_vals.py +11 -30
- infrahub/core/migrations/graph/m039_ipam_reconcile.py +9 -7
- infrahub/core/migrations/graph/m041_deleted_dup_edges.py +149 -0
- infrahub/core/migrations/graph/m042_profile_attrs_in_db.py +147 -0
- infrahub/core/migrations/graph/m043_create_hfid_display_label_in_db.py +164 -0
- infrahub/core/migrations/graph/m044_backfill_hfid_display_label_in_db.py +864 -0
- infrahub/core/migrations/query/__init__.py +7 -8
- infrahub/core/migrations/query/attribute_add.py +8 -6
- infrahub/core/migrations/query/attribute_remove.py +134 -0
- infrahub/core/migrations/runner.py +54 -0
- infrahub/core/migrations/schema/attribute_kind_update.py +9 -3
- infrahub/core/migrations/schema/attribute_supports_profile.py +90 -0
- infrahub/core/migrations/schema/node_attribute_add.py +26 -5
- infrahub/core/migrations/schema/node_attribute_remove.py +13 -109
- infrahub/core/migrations/schema/node_kind_update.py +2 -1
- infrahub/core/migrations/schema/node_remove.py +2 -1
- infrahub/core/migrations/schema/placeholder_dummy.py +3 -2
- infrahub/core/migrations/shared.py +66 -19
- infrahub/core/models.py +2 -2
- infrahub/core/node/__init__.py +207 -54
- infrahub/core/node/create.py +53 -49
- infrahub/core/node/lock_utils.py +124 -0
- infrahub/core/node/node_property_attribute.py +230 -0
- infrahub/core/node/resource_manager/ip_address_pool.py +2 -1
- infrahub/core/node/resource_manager/ip_prefix_pool.py +2 -1
- infrahub/core/node/resource_manager/number_pool.py +2 -1
- infrahub/core/node/standard.py +1 -1
- infrahub/core/property.py +11 -0
- infrahub/core/protocols.py +8 -1
- infrahub/core/query/attribute.py +82 -15
- infrahub/core/query/diff.py +61 -16
- infrahub/core/query/ipam.py +16 -4
- infrahub/core/query/node.py +92 -212
- infrahub/core/query/relationship.py +44 -26
- infrahub/core/query/subquery.py +0 -8
- infrahub/core/relationship/model.py +69 -24
- infrahub/core/schema/__init__.py +56 -0
- infrahub/core/schema/attribute_schema.py +4 -2
- infrahub/core/schema/basenode_schema.py +42 -2
- infrahub/core/schema/definitions/core/__init__.py +2 -0
- infrahub/core/schema/definitions/core/check.py +1 -1
- infrahub/core/schema/definitions/core/generator.py +2 -0
- infrahub/core/schema/definitions/core/group.py +16 -2
- infrahub/core/schema/definitions/core/repository.py +7 -0
- infrahub/core/schema/definitions/core/transform.py +1 -1
- infrahub/core/schema/definitions/internal.py +12 -3
- infrahub/core/schema/generated/attribute_schema.py +2 -2
- infrahub/core/schema/generated/base_node_schema.py +6 -1
- infrahub/core/schema/manager.py +3 -0
- infrahub/core/schema/node_schema.py +1 -0
- infrahub/core/schema/relationship_schema.py +0 -1
- infrahub/core/schema/schema_branch.py +295 -10
- infrahub/core/schema/schema_branch_display.py +135 -0
- infrahub/core/schema/schema_branch_hfid.py +120 -0
- infrahub/core/validators/aggregated_checker.py +1 -1
- infrahub/database/graph.py +21 -0
- infrahub/display_labels/__init__.py +0 -0
- infrahub/display_labels/gather.py +48 -0
- infrahub/display_labels/models.py +240 -0
- infrahub/display_labels/tasks.py +192 -0
- infrahub/display_labels/triggers.py +22 -0
- infrahub/events/branch_action.py +27 -1
- infrahub/events/group_action.py +1 -1
- infrahub/events/node_action.py +1 -1
- infrahub/generators/constants.py +7 -0
- infrahub/generators/models.py +38 -12
- infrahub/generators/tasks.py +34 -16
- infrahub/git/base.py +42 -2
- infrahub/git/integrator.py +22 -14
- infrahub/git/tasks.py +52 -2
- infrahub/graphql/analyzer.py +9 -0
- infrahub/graphql/api/dependencies.py +2 -4
- infrahub/graphql/api/endpoints.py +16 -6
- infrahub/graphql/app.py +2 -4
- infrahub/graphql/initialization.py +2 -3
- infrahub/graphql/manager.py +213 -137
- infrahub/graphql/middleware.py +12 -0
- infrahub/graphql/mutations/branch.py +16 -0
- infrahub/graphql/mutations/computed_attribute.py +110 -3
- infrahub/graphql/mutations/convert_object_type.py +44 -13
- infrahub/graphql/mutations/display_label.py +118 -0
- infrahub/graphql/mutations/generator.py +25 -7
- infrahub/graphql/mutations/hfid.py +125 -0
- infrahub/graphql/mutations/ipam.py +73 -41
- infrahub/graphql/mutations/main.py +61 -178
- infrahub/graphql/mutations/profile.py +195 -0
- infrahub/graphql/mutations/proposed_change.py +8 -1
- infrahub/graphql/mutations/relationship.py +2 -2
- infrahub/graphql/mutations/repository.py +22 -83
- infrahub/graphql/mutations/resource_manager.py +2 -2
- infrahub/graphql/mutations/webhook.py +1 -1
- infrahub/graphql/queries/resource_manager.py +1 -1
- infrahub/graphql/registry.py +173 -0
- infrahub/graphql/resolvers/resolver.py +2 -0
- infrahub/graphql/schema.py +8 -1
- infrahub/graphql/schema_sort.py +170 -0
- infrahub/graphql/types/branch.py +4 -1
- infrahub/graphql/types/enums.py +3 -0
- infrahub/groups/tasks.py +1 -1
- infrahub/hfid/__init__.py +0 -0
- infrahub/hfid/gather.py +48 -0
- infrahub/hfid/models.py +240 -0
- infrahub/hfid/tasks.py +191 -0
- infrahub/hfid/triggers.py +22 -0
- infrahub/lock.py +119 -42
- infrahub/locks/__init__.py +0 -0
- infrahub/locks/tasks.py +37 -0
- infrahub/message_bus/types.py +1 -0
- infrahub/patch/plan_writer.py +2 -2
- infrahub/permissions/constants.py +2 -0
- infrahub/profiles/__init__.py +0 -0
- infrahub/profiles/node_applier.py +101 -0
- infrahub/profiles/queries/__init__.py +0 -0
- infrahub/profiles/queries/get_profile_data.py +98 -0
- infrahub/profiles/tasks.py +63 -0
- infrahub/proposed_change/tasks.py +67 -14
- infrahub/repositories/__init__.py +0 -0
- infrahub/repositories/create_repository.py +113 -0
- infrahub/server.py +9 -1
- infrahub/services/__init__.py +8 -5
- infrahub/services/adapters/http/__init__.py +5 -0
- infrahub/services/adapters/workflow/worker.py +14 -3
- infrahub/task_manager/event.py +5 -0
- infrahub/task_manager/models.py +7 -0
- infrahub/task_manager/task.py +73 -0
- infrahub/tasks/registry.py +6 -4
- infrahub/trigger/catalogue.py +4 -0
- infrahub/trigger/models.py +2 -0
- infrahub/trigger/setup.py +13 -4
- infrahub/trigger/tasks.py +6 -0
- infrahub/webhook/models.py +1 -1
- infrahub/workers/dependencies.py +3 -1
- infrahub/workers/infrahub_async.py +10 -2
- infrahub/workflows/catalogue.py +118 -3
- infrahub/workflows/initialization.py +21 -0
- infrahub/workflows/models.py +17 -2
- infrahub/workflows/utils.py +2 -1
- infrahub_sdk/branch.py +17 -8
- infrahub_sdk/checks.py +1 -1
- infrahub_sdk/client.py +376 -95
- infrahub_sdk/config.py +29 -2
- infrahub_sdk/convert_object_type.py +61 -0
- infrahub_sdk/ctl/branch.py +3 -0
- infrahub_sdk/ctl/check.py +2 -3
- infrahub_sdk/ctl/cli_commands.py +20 -12
- infrahub_sdk/ctl/config.py +8 -2
- infrahub_sdk/ctl/generator.py +6 -3
- infrahub_sdk/ctl/graphql.py +184 -0
- infrahub_sdk/ctl/repository.py +39 -1
- infrahub_sdk/ctl/schema.py +40 -10
- infrahub_sdk/ctl/task.py +110 -0
- infrahub_sdk/ctl/utils.py +4 -0
- infrahub_sdk/ctl/validate.py +5 -3
- infrahub_sdk/diff.py +4 -5
- infrahub_sdk/exceptions.py +2 -0
- infrahub_sdk/generator.py +7 -1
- infrahub_sdk/graphql/__init__.py +12 -0
- infrahub_sdk/graphql/constants.py +1 -0
- infrahub_sdk/graphql/plugin.py +85 -0
- infrahub_sdk/graphql/query.py +77 -0
- infrahub_sdk/{graphql.py → graphql/renderers.py} +88 -75
- infrahub_sdk/graphql/utils.py +40 -0
- infrahub_sdk/node/attribute.py +2 -0
- infrahub_sdk/node/node.py +28 -20
- infrahub_sdk/node/relationship.py +1 -3
- infrahub_sdk/playback.py +1 -2
- infrahub_sdk/protocols.py +54 -6
- infrahub_sdk/pytest_plugin/plugin.py +7 -4
- infrahub_sdk/pytest_plugin/utils.py +40 -0
- infrahub_sdk/repository.py +1 -2
- infrahub_sdk/schema/__init__.py +70 -4
- infrahub_sdk/schema/main.py +1 -0
- infrahub_sdk/schema/repository.py +8 -0
- infrahub_sdk/spec/models.py +7 -0
- infrahub_sdk/spec/object.py +54 -6
- infrahub_sdk/spec/processors/__init__.py +0 -0
- infrahub_sdk/spec/processors/data_processor.py +10 -0
- infrahub_sdk/spec/processors/factory.py +34 -0
- infrahub_sdk/spec/processors/range_expand_processor.py +56 -0
- infrahub_sdk/spec/range_expansion.py +118 -0
- infrahub_sdk/task/models.py +6 -4
- infrahub_sdk/timestamp.py +18 -6
- infrahub_sdk/transforms.py +1 -1
- {infrahub_server-1.4.12.dist-info → infrahub_server-1.5.0.dist-info}/METADATA +9 -10
- {infrahub_server-1.4.12.dist-info → infrahub_server-1.5.0.dist-info}/RECORD +233 -176
- infrahub_testcontainers/container.py +114 -2
- infrahub_testcontainers/docker-compose-cluster.test.yml +5 -0
- infrahub_testcontainers/docker-compose.test.yml +5 -0
- infrahub_testcontainers/models.py +2 -2
- infrahub_testcontainers/performance_test.py +4 -4
- infrahub/core/convert_object_type/conversion.py +0 -134
- {infrahub_server-1.4.12.dist-info → infrahub_server-1.5.0.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.4.12.dist-info → infrahub_server-1.5.0.dist-info}/WHEEL +0 -0
- {infrahub_server-1.4.12.dist-info → infrahub_server-1.5.0.dist-info}/entry_points.txt +0 -0
infrahub/events/branch_action.py
CHANGED
|
@@ -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
|
|
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
|
infrahub/events/group_action.py
CHANGED
|
@@ -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
|
|
infrahub/events/node_action.py
CHANGED
|
@@ -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
|
|
infrahub/generators/models.py
CHANGED
|
@@ -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:
|
|
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
|
|
35
|
-
definition_id: str
|
|
36
|
-
definition_name: str
|
|
37
|
-
query_name: str
|
|
38
|
-
convert_query_response: bool
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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.")
|
infrahub/generators/tasks.py
CHANGED
|
@@ -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(
|
|
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
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
|
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
|
infrahub/git/integrator.py
CHANGED
|
@@ -226,7 +226,7 @@ class InfrahubRepositoryIntegrator(InfrahubRepositoryBase):
|
|
|
226
226
|
)
|
|
227
227
|
)
|
|
228
228
|
|
|
229
|
-
@task(name="import-jinja2-
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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
|
|
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
|
|
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", "")),
|
infrahub/graphql/analyzer.py
CHANGED
|
@@ -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(
|
|
40
|
-
return InfrahubGraphQLApp(build_graphql_query_permission_checker()
|
|
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.
|
|
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"
|
|
31
|
+
@router.get("/schema.graphql")
|
|
31
32
|
async def get_graphql_schema(
|
|
32
|
-
branch: Branch = Depends(get_branch_dep),
|
|
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 =
|
|
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=
|
|
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 =
|
|
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,
|