azd env refresh with extension-provided hosts and provisioning providers#9017
azd env refresh with extension-provided hosts and provisioning providers#9017JeffreyCA wants to merge 3 commits into
azd env refresh with extension-provided hosts and provisioning providers#9017Conversation
env refresh now initializes only framework services (best-effort, never service targets) and starts an extension-provided provisioning provider on demand, so projects using hosts/providers like azure.ai.agent and microsoft.foundry can refresh outputs. Missing deployments are reported informationally instead of failing.
There was a problem hiding this comment.
Pull request overview
This PR makes azd env refresh work in projects whose service host or provisioning provider is supplied by an extension (e.g. the azure.ai.agents extension providing the azure.ai.agent host and the microsoft.foundry provider), resolving issue #7195. Refresh is a read-only "pull latest deployment outputs into .env" operation, but it was coupled to service-target resolution and never started extensions, so it failed with unsupported host / failed resolving IaC provider errors. The change decouples refresh from service targets and starts the owning extension on demand only when its provider is needed.
Changes:
- Splits
serviceManager.Initializeinto a reusable framework-onlyInitializeFrameworkService, and adds a best-effort, per-serviceprojectManager.InitializeFrameworksused by both the CLI and VS RPC refresh paths (dropping the up-frontEnsureAllTools). - Introduces
ExtensionActivatorthat starts only the installed extension(s) declaring the configured provisioning provider(s), idempotently, with deterministic selection and graceful install/upgrade suggestions; extracts the shared per-extensionstartAndWaitExtensionhelper from the extensions middleware. - Makes
env refreshtreat "no deployment yet" / empty provider state as informational (success) rather than an error, while keeping an explicit mismatched--hinta hard error.
Show a summary per file
| File | Description |
|---|---|
cli/azd/pkg/project/service_manager.go |
Extracts InitializeFrameworkService; Initialize now delegates to it then resolves/initializes the target. |
cli/azd/pkg/project/service_manager_test.go |
Adds test that framework-only init succeeds under an unsupported host while full init fails. |
cli/azd/pkg/project/project_manager.go |
Adds best-effort InitializeFrameworks returning initialized + skipped services. |
cli/azd/pkg/project/project_manager_test.go |
Adds fake-manager wiring and tests for all-init and skip-on-failure cases. |
cli/azd/internal/vsrpc/environment_service_refresh.go |
Switches VS refresh path to framework-only init. |
cli/azd/internal/cmd/service_graph_test.go |
Adds InitializeFrameworkService to the stub service manager. |
cli/azd/internal/cmd/provision_test.go / deploy_test.go |
Adds new interface methods to mocks. |
cli/azd/docs/extensions/extension-framework.md |
Documents the provisioning-provider capability and refresh behavior. |
cli/azd/cmd/util_test.go |
Adds InitializeFrameworks to the mock project manager. |
cli/azd/cmd/middleware/extensions.go |
Extracts shared startAndWaitExtension and extensionStartOptions. |
cli/azd/cmd/middleware/extension_activator.go |
New on-demand extension activator for provisioning providers. |
cli/azd/cmd/middleware/extension_activator_test.go |
Unit tests for provider matching/selection helpers. |
cli/azd/cmd/env.go |
Rewrites refresh to skip targets, activate provider extensions, and handle empty/no-deployment state. |
cli/azd/cmd/env_test.go |
Adds refresh action tests (no-deployment, nil state, successful refresh, suggestion gating). |
cli/azd/cmd/container.go |
Registers ExtensionActivator in the IoC container. |
cli/azd/cmd/container_test.go |
Verifies ExtensionActivator resolves from the container. |
Review details
- Files reviewed: 17/17 changed files
- Comments generated: 2
- Review effort level: Medium
jongio
left a comment
There was a problem hiding this comment.
Clean decomposition that unblocks �zd env refresh for extension-provided hosts and provisioning providers.
Highlights:
- Framework-only init path is a clean separation, correctly preserving the original init order (framework then target) while making the framework-only path independently callable.
- ExtensionActivator is properly idempotent (checks providerResolvable before starting anything), handles concurrent startup, and cleans up deterministically.
- Extracted startAndWaitExtension avoids duplicating the middleware's startup logic.
- Edge-case handling is thorough: nil state, no deployment (informational exit), provider-resolution failures surface actionable install/upgrade suggestions.
- VS RPC refresh path gets parity treatment via InitializeFrameworks.
- Tests cover the key scenarios well (no-deployment, nil state, successful refresh, suggestion gating, framework-only init under unsupported host, best-effort skipping, activator helpers).
jongio
left a comment
There was a problem hiding this comment.
New commit since my prior approval adds solid test coverage for the ExtensionActivator: construction, provider resolution, no-match path, already-resolvable (no-op) path, and SuggestExtensionForProvider with subtests for empty name, installed-declares-provider, registry match, and no-match. Tests are well-structured, use t.Parallel()/t.Context(), and follow the codebase's mock patterns. No concerns.
Azure Dev CLI Install InstructionsInstall scriptsMacOS/Linux
bash: pwsh: WindowsPowerShell install MSI install Standalone Binary
MSI
Documentationlearn.microsoft.com documentationtitle: Azure Developer CLI reference
|
Fixes #7195
This PR makes
azd env refreshwork in projects whose service host or provisioning provider is supplied by an extension (for example theazure.ai.agentsextension, which provides theazure.ai.agenthost and themicrosoft.foundryprovisioning provider). Refresh previously failed outright; it now pulls the latest deployment outputs into the local.envlike any other project, and reports informationally when there is nothing to refresh yet.Issue
env refreshis a lightweight, read-only operation: it finds the last deployment, pulls its outputs, and writes them into.azure/<env>/.env. It does not build, package, or deploy, but it was coupled to machinery it does not need, and it never starts extensions, so two failures occurred.projectManager.InitializeandEnsureAllToolsup front, which resolve a service target for every service. An extension-provided host likeazure.ai.agentfails withservice host 'azure.ai.agent' for service 'agent' is unsupported.provision/deploy/up, refresh does not attach the extensions middleware, so an extension-provided provisioning provider likemicrosoft.foundryis never registered and fails withfailed resolving IaC provider 'microsoft.foundry'.These pull in opposite directions: refresh does not need service targets, but it does need the provisioning provider, since reading deployment state is the provider's
State()call.Decouple refresh from service targets
Refresh now initializes only framework services, never service targets, so an extension-provided host cannot block it.
ServiceEventEnvUpdatedstill fires for the services that did initialize (keeping the .NET/Aspire user-secrets sync working), and only when a layer actually produced state.EnsureAllToolscall, since refresh never builds, packages, or deploys.Start extension-provided provisioning providers on demand
Rather than starting every installed extension (as the full middleware does), refresh activates only the extension that declares the configured provider, and only when needed.
bicep/terraformare a no-op.azd extension upgrade <id>suggestion.State()already reads outputs from the persisted subscription-scoped deployment (no on-disk template), which is exactly what refresh needs.Graceful handling and suggestions
azd provisionand exits successfully; an extension provider returning empty state is treated the same way. An explicit--hintthat matches nothing stays a hard error.azd extension install <id>suggestion when a match exists; other errors are returned as-is.Shared helper and VS parity
listenand wait for ready" logic into a shared helper used by both the middleware and the new activator.EnsureAllTools) to the Visual Studio RPC refresh path.Behavior at a glance
azure.ai.agent)ERROR: service host '...' is unsupported.envmicrosoft.foundry)ERROR: failed resolving IaC provider '...'azd extension install <id>suggestionazd extension upgrade <id>suggestion--hint)ERROR: no deployments found--hintmatches no deploymentbicep/terraformprojectTesting
env refreshaction over the no-deployment, empty-state, and successful-refresh cases plus suggestion gating and IoC resolution.go build ./...,go testacross the affected packages (including-race), andgolangci-lint run.