1P extensions: migrate to `azdext.NewExtensionRootCommand` and remove reserved flag conflicts
- Dominant language
- Go
- Stars
- 569
- Forks
- 364
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 136
Description
## Summary
Audit and migrate the remaining first-party extensions in `cli/azd/extensions/` to use `azdext.NewExtensionRootCommand` (introduced in #6856), and remove flags that conflict with azd's reserved global flag set (`internal/reserved_flags.go`). This is the same migration completed for `azure.ai.agents` in #7796 / PR #7950, generalized to the rest of the 1P fleet.
Reserved flags to remove: `--debug`, `--no-prompt`, `--cwd`, `--environment` (`-e`), `--output` (`-o`), `--help` (`-h`), `--docs`, `--trace-log-file`, `--trace-log-url`.
## Scope
This issue covers **all first-party extensions in one PR** except `microsoft.azd.extensions`, which has additional surface area (scaffolding templates, `--cwd` semantic collision) and is tracked separately in #7951.
### Conflicts to fix
| Extension | Conflicts | Notes |
|---|---|---|
| `azure.ai.finetune` | manual root `--debug`, `--no-prompt`; `init --environment` (long-name only, short is `-n`); `operations` `--output`/`-o` (×2) | uses `rootFlagsDefinition` global pattern |
| `azure.ai.models` | manual root `--debug`, `--no-prompt`; `init --environment` (long-name only, short is `-n`); `custom show --output`/`-o`; `custom list --output`/`-o` | uses `rootFlagsDefinition` global pattern |
| `azure.appservice` | manual root `--debug`, `--no-prompt` | uses `rootFlagsDefinition` global pattern |
| `azure.coding-agent` | manual root `--debug` | minimal extension |
| `microsoft.azd.concurx` | manual root `--debug`; `up --debug` (subcommand) | duplicate registration on `up` |
| `microsoft.azd.demo` | none directly, but custom root (no SDK) | should still adopt `NewExtensionRootCommand` for consistency |
### Already migrated
- `azure.ai.agents` — done in #7796 / PR #7950
### Tracked separately
- `microsoft.azd.extensions` — see #7951 (extension + scaffolding templates + `--cwd` rename)
### Stub / non-Go / dead — skip
- `azure.ai.customtraining` — binary-only stub (no Go source)
- `azd.internal.pack` — meta-package (no commands)
- `microsoft.azd.ai.builder` — dead extension, not maintained
## Migration template (per extension)
Mirror what was done for `azure.ai.agents` in #7796:
1. **Root**: replace bespoke `cobra.Command{}` + `rootFlagsDefinition` pattern with:
```go
rootCmd, extCtx := azdext.NewExtensionRootCommand(azdext.ExtensionCommandOptions{
Name: "",
Use: "",
Short: "",
})
```
Drop manual `--debug` / `--no-prompt` registrations and any `AZD_*` env-var fallback. Thread `*azdext.ExtensionContext` to subcommand constructors.
2. **`init --environment`**: drop the local flag where present (`azure.ai.finetune`, `azure.ai.models`). Read `extCtx.Environment` instead.
3. **`--output` / `-o`**: replace per-subcommand redeclarations with `azdext.RegisterFlagOptions` (#7826) and read `extCtx.OutputFormat` in `RunE`. Per-command default + allowed values are expressed declaratively.
4. **`PersistentPreRunE` chains**: remove any `cmd.PersistentPreRunE` that manually invokes `parent.PersistentPreRunE` / `root.PersistentPreRunE` — `NewExtensionRootCommand` sets `cobra.EnableTraverseRunHooks = true`, so the SDK pre-run already runs from root → leaf and double-invocation is wrong.
5. **`go.mod` bump**: extensions in their own modules (`azure.ai.finetune`, `azure.ai.models`, `azure.appservice`, `azure.coding-agent`, `microsoft.azd.concurx`) need a bump to the SDK version that includes `RegisterFlagOptions` (#7826) + `EnableTraverseRunHooks` + the reserved-flag registry (#7312). The monorepo extension (`microsoft.azd.demo`) follows the parent `cli/azd` module automatically.
6. **`requiredAzdVersion`** in `extension.yaml`: bump to a version that ships the SDK enforcement so users on older azd see a clear install-time error rather than a runtime conflict.
## Validation
Per extension touched:
```bash
cd cli/azd/extensions/
go build ./... && go test ./...
azd x build
azd --help
```
Plus `go test ./cli/azd/pkg/azdext/...` for `ValidateNoReservedFlagConflicts` coverage.
## Out of scope
- `azure.ai.agents` (already migrated via #7796 / PR #7950)
- `microsoft.azd.extensions` (tracked in #7951)
- `microsoft.azd.ai.builder` (dead extension)
- Changes to the reserved flag registry itself
- Changes to `NewExtensionRootCommand` API surface
## Related
- #7796 — `azure.ai.agents` migration (precedent + template)
- #7951 — `microsoft.azd.extensions` migration (separate due to scaffolding scope)
- #7826 — `azdext.RegisterFlagOptions`
- #7312 — reserved flag registry
- #6856 — `azdext.NewExtensionRootCommand`
- `cli/azd/docs/extensions/extensions-style-guide.md` — Reserved Global Flags section
- `cli/azd/docs/design/extension-flag-architecture.md`
Contributor guide
Assessment
This issue has not been assessed yet.