feat(project): add infrastructure layer model - #9913
feat(project): add infrastructure layer model#9913Richard Park (richardpark-msft) wants to merge 4 commits into
Conversation
|
Azure Pipelines: Successfully started running 1 pipeline(s). 21 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
🔗 Linked Issue RequiredThanks for the contribution! Please link a GitHub issue to this PR by adding |
|
Azure Pipelines: Successfully started running 1 pipeline(s). 21 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Layered services remain absent from key gRPC paths, persistence can write invalid mixed formats, and the referenced schema lacks the new structure.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review tier: Balanced
Findings: 2
New issues introduced by this change (3)
| Severity | Finding |
|---|---|
cli/azd/pkg/project/layer_config.go — Layered services are still omitted from the project gRPC read path: the `ProjectConfig ->… |
|
cli/azd/pkg/project/project.go — Validate is only called while parsing, so mutations can still persist a configuration that this… |
|
cli/azd/pkg/project/project_config.go — The alpha schema referenced when these projects are saved does not define a top-level layers… |
What changed in this PR
Adds initial support for top-level infrastructure and service layers while flattening them for existing deployment workflows.
Changes:
- Adds layered project models, validation, parsing, and persistence.
- Exposes flattened service and infrastructure collections to existing consumers.
- Adds dependency-graph validation and layer-focused tests.
| File | Description |
|---|---|
cli/azd/pkg/project/validate.go |
Validates layered configurations. |
cli/azd/pkg/project/validate_test.go |
Tests layer validation errors. |
cli/azd/pkg/project/project.go |
Parses, loads, and saves layered projects. |
cli/azd/pkg/project/project_config.go |
Adds layers and runtime-state copying. |
cli/azd/pkg/project/layer.go |
Validates layer dependency graphs. |
cli/azd/pkg/project/layer_test.go |
Tests parsing, persistence, and dependencies. |
cli/azd/pkg/project/layer_config.go |
Defines layer models and flattened accessors. |
cli/azd/pkg/project/importer.go |
Flattens layered infrastructure and services. |
cli/azd/pkg/project/importer_test.go |
Tests flattened infrastructure imports. |
cli/azd/pkg/infra/provisioning/provider.go |
Adds layer ownership and validation updates. |
cli/azd/pkg/infra/provisioning/options_test.go |
Tests revised provider options behavior. |
cli/azd/internal/grpcserver/event_service.go |
Includes layered services in subscriptions. |
cli/azd/internal/grpcserver/container_service.go |
Resolves layered services for container operations. |
cli/azd/cmd/project_extension_auto_install.go |
Detects providers across layered projects. |
cli/azd/cmd/container.go |
Checks custom languages across all services. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
b331f8f to
7889902
Compare
Azure Dev CLI Install InstructionsInstall scriptsMacOS/Linux
bash: pwsh: WindowsPowerShell install MSI install Standalone Binary
MSI
Documentationlearn.microsoft.com documentationtitle: Azure Developer CLI reference
|
Represent top-level project layers and named infrastructure entries in azure.yaml. Add format detection, validation, traversal helpers, and compatibility updates for existing service and infrastructure consumers.
…t, TBH, wasn't really pulling it's weight and was just making things seem more complicated than it was.
…ices. It's still just a small workaround (services are still treated as global), _but_ it'll let us get by for a bit until we get the full thing in. - Use map.Copy(), like all the cool kids do.
…r Flat azure.yaml customers.
88bcc89 to
19a0acc
Compare
|
Azure Pipelines: Successfully started running 1 pipeline(s). 21 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Layer graph validation, infrastructure generation, schema alignment, and hook handling contain unresolved behavioral issues.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review tier: Balanced
Findings: 2
New issues introduced by this change (5)
| Severity | Finding |
|---|---|
cli/azd/pkg/project/importer.go — Preserve generated infrastructure for resource-backed services |
|
cli/azd/pkg/project/layer.go — Do not reject acyclic flattened infrastructure graphs |
|
cli/azd/pkg/infra/provisioning/provider.go — Reject root infra fields with explicitly empty layers |
|
cli/azd/pkg/infra/provisioning/provider.go — Keep pathless provider layers consistent with schemas |
|
schemas/alpha/azure.yaml.json — Wire v2 infrastructure hooks into azd hooks run |
Issues resolved since last review (3)
| Severity | Finding |
|---|---|
cli/azd/pkg/project/project_config.go — The alpha schema referenced when these projects are saved does not define a top-level layers… View resolved comment |
|
cli/azd/pkg/project/project.go — Validate is only called while parsing, so mutations can still persist a configuration that this… View resolved comment |
|
cli/azd/pkg/project/layer_config.go — Layered services are still omitted from the project gRPC read path: the `ProjectConfig ->… View resolved comment |
| // The configuration can be explicitly defined on azure.yaml using path and module, or in case these values | ||
| // are not explicitly defined, the project importer uses default values to find the infrastructure. | ||
| func (im *ImportManager) ProjectInfrastructure(ctx context.Context, projectConfig *ProjectConfig) (*Infra, error) { | ||
| if projectConfig.Format() == ProjectFormatLayersV2 { |
| if err := validateDependencyGraph(dependencySets, "layer"); err != nil { | ||
| return err | ||
| } |
| if len(o.Layers) > 0 { | ||
| anyIncompatibleFieldsSet := func() bool { | ||
| return o.Name != "" || o.Module != "" || o.Path != "" || o.DeploymentStacks != nil | ||
| return o.Name != "" || o.Layer != "" || o.Module != "" || o.Path != "" || o.DeploymentStacks != nil || | ||
| len(o.Config) > 0 |
| // NOTE: I'm treating 'NotSpecified' as 'bicep' - there's some downstream code that does that in | ||
| // 'provisioning/manager'. | ||
| // It might be nice to think about doing this earlier, or having that validation occurring in the providers instead. | ||
| if layer.Path == "" && (layer.Provider == NotSpecified || slices.Contains(builtInProviderKinds, layer.Provider)) { |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Layer hooks remain inaccessible, schema validation diverges from runtime validation, and saves can broaden existing file permissions.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review tier: Balanced
Findings: 3
New issues introduced by this change (3)
| Severity | Finding |
|---|---|
cli/azd/pkg/project/project.go — Preserve existing azure.yaml permissions |
|
cli/azd/pkg/project/layer_config.go — Include v2 infrastructure in the hooks command |
|
schemas/alpha/azure.yaml.json — Require non-empty layer contents in the schema |
Pre-existing issues (5)
| Severity | Finding |
|---|---|
cli/azd/pkg/project/layer.go — Do not reject acyclic flattened infrastructure graphs View comment |
|
cli/azd/pkg/project/importer.go — Preserve generated infrastructure for resource-backed services View comment |
|
schemas/alpha/azure.yaml.json — Wire v2 infrastructure hooks into azd hooks run View comment |
|
cli/azd/pkg/infra/provisioning/provider.go — Keep pathless provider layers consistent with schemas View comment |
|
cli/azd/pkg/infra/provisioning/provider.go — Reject root infra fields with explicitly empty layers View comment |
|
|
||
| err = os.WriteFile(projectFilePath, projectFileContents.Bytes(), osutil.PermissionFile) | ||
| // Atomic write so readers never observe a partially written azure.yaml. | ||
| err = azdext.WriteFileAtomic(projectFilePath, projectFileContents.Bytes(), osutil.PermissionFile) |
| // InfrastructureConfigs returns all provisioning entries in declaration order. | ||
| func (pc *ProjectConfig) InfrastructureConfigs() []provisioning.Options { | ||
| if pc.Format() != ProjectFormatLayersV2 { | ||
| return pc.Infra.GetLayers() |
| "anyOf": [ | ||
| { | ||
| "required": [ | ||
| "infra" | ||
| ] | ||
| }, | ||
| { | ||
| "required": [ | ||
| "services" | ||
| ] | ||
| } | ||
| ], |


This is a small step towards handling the new "layers v2" format, where layers can contain multiple infra entries, and service entries:
This PR does the smallest change to handle the format, and just converts this into a flat infra list, and deploys services the same as before. We have more features planned, but incremental steps are easiest to test and digest.
Part of #9767