Skip to content

microsoft.azd.extensions: refresh Go scaffolding templates (azd x init --language go) #7954

Description

@JeffreyCA

Sub-issue of #7951 (Part 2 — Go subset). Closes #7925.

Problem

azd x init --language go generates Go extensions that are stale on day one:

  • go.mod.tmpl pins github.com/azure/azure-dev/cli/azd v0.0.0-20260116183934-428498d0f124 (pseudo-version from January 2026 — months out of date).
  • go.mod.tmpl declares go 1.25; the rest of the repo is on go 1.26.
  • root.go.tmpl emits the legacy cobra.Command{} + manual --debug pattern that the umbrella migration (1P extensions: migrate to azdext.NewExtensionRootCommand and remove reserved flag conflicts #7950) is removing across the 1P fleet.
  • main.go.tmpl calls rootCmd.ExecuteContext(ctx) directly instead of azdext.Run(...), missing the SDK's signal handling, reserved-flag validation, and process token wiring.

Net effect: every newly-scaffolded Go extension reproduces the same problems #7950 / #7796 are eliminating, and #7925 was filed against this directly.

Files

cli/azd/extensions/microsoft.azd.extensions/internal/resources/languages/go/

  • go.mod.tmpl
  • main.go.tmpl
  • internal/cmd/root.go.tmpl
  • internal/cmd/listen.go.tmpl, metadata.go.tmpl, version.go.tmpl, prompt.go.tmpl, context.go.tmpl — review for any pattern updates (e.g., RunE signatures, accepting *azdext.ExtensionContext)
  • go.sum — regenerate alongside go.mod bump
  • README.md, CHANGELOG.md — note SDK requirements

Required changes

go.mod.tmpl

go 1.26

require (
    // ... existing azure-sdk-for-go entries ...
    github.com/azure/azure-dev/cli/azd v<current released minor>
    // ...
)

Pick a real released minor version (e.g., v1.24.x once that's tagged) instead of a pseudo-version, so the scaffold doesn't keep silently aging. Decide on a refresh policy: bump on every azd CLI release, or on every SDK feature that scaffolded extensions should adopt by default.

main.go.tmpl

package main

import (
    "{{.Metadata.Id}}/internal/cmd"
    "github.com/azure/azure-dev/cli/azd/pkg/azdext"
)

func main() {
    azdext.Run(cmd.NewRootCommand())
}

The FORCE_COLOR init() block becomes unnecessary — azdext.Run handles process setup.

internal/cmd/root.go.tmpl

package cmd

import (
    "github.com/azure/azure-dev/cli/azd/pkg/azdext"
)

func NewRootCommand() *cobra.Command {
    rootCmd, extCtx := azdext.NewExtensionRootCommand(azdext.ExtensionCommandOptions{
        Name:  "{{.Metadata.Namespace}}",
        Use:   "{{.Metadata.Namespace}} <command> [options]",
        Short: "{{.Metadata.Description}}",
    })
    rootCmd.SilenceUsage = true
    rootCmd.SilenceErrors = true
    rootCmd.CompletionOptions.DisableDefaultCmd = true
    rootCmd.SetHelpCommand(&cobra.Command{Hidden: true})

    rootCmd.AddCommand(newListenCommand())
    rootCmd.AddCommand(newContextCommand(extCtx))
    rootCmd.AddCommand(newPromptCommand(extCtx))
    rootCmd.AddCommand(newVersionCommand())
    rootCmd.AddCommand(newMetadataCommand())

    return rootCmd
}

Drop the --debug registration. Thread extCtx only into subcommands that demonstrably benefit (e.g., context.go.tmpl if it shows env/output usage); leave listen, version, metadata alone.

Subcommand templates

  • context.go.tmpl is the natural place to demonstrate reading from extCtx (e.g., print extCtx.Environment, extCtx.OutputFormat). Update the example to show idiomatic usage.
  • prompt.go.tmpl — adjust if it currently demonstrates --no-prompt handling via the legacy rootFlags pattern.

Test coverage

Add an integration test (or document a manual smoke step in microsoft.azd.extensions/README.md):

mkdir -p /tmp/scaffold-test && cd /tmp/scaffold-test
azd x init --language go --namespace foo --id foo.bar
cd foo.bar
go build ./...
go test ./...

A CI smoke test would catch template drift early; if too expensive, at minimum a go build + golangci-lint run against the generated tree on PRs that touch internal/resources/languages/go/.

Validation

cd cli/azd/extensions/microsoft.azd.extensions
go build ./... && go test ./...
azd x build
# Then run the scaffold-test snippet above.

Out of scope

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions