diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 44e18446edc..7d09288fcfe 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -3,7 +3,7 @@ "image": "mcr.microsoft.com/devcontainers/base:ubuntu", "features": { "ghcr.io/devcontainers/features/go:1": { - "version": "1.26" + "version": "1.26.1" }, "ghcr.io/devcontainers/features/docker-in-docker:2.11.0": { "version": "latest", diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 9aeecbe1ea3..2bb9b7b795e 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -38,7 +38,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v6 with: - go-version: "^1.26" + go-version-file: cli/azd/go.mod - name: Set up Node.js uses: actions/setup-node@v4 diff --git a/.github/workflows/ext-registry-ci.yml b/.github/workflows/ext-registry-ci.yml index 09ffc3159bb..ad26d9aaad2 100644 --- a/.github/workflows/ext-registry-ci.yml +++ b/.github/workflows/ext-registry-ci.yml @@ -27,7 +27,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v6 with: - go-version: "^1.26" + go-version-file: cli/azd/go.mod cache-dependency-path: | cli/azd/go.sum diff --git a/.github/workflows/lint-go.yml b/.github/workflows/lint-go.yml index 348bb2a5518..ed96fe8a993 100644 --- a/.github/workflows/lint-go.yml +++ b/.github/workflows/lint-go.yml @@ -7,11 +7,11 @@ on: description: "Path to the Go module directory to lint" required: true type: string - go-version: - description: "Go version to use" + go-version-file: + description: "Path to go.mod to read Go version from" required: false type: string - default: "^1.26" + default: "cli/azd/go.mod" golangci-lint-version: description: "GolangCI-Lint version to use" required: false @@ -29,10 +29,10 @@ jobs: matrix: os: [ubuntu-latest, windows-latest] steps: + - uses: actions/checkout@v4 - uses: actions/setup-go@v6 with: - go-version: ${{ inputs.go-version }} - - uses: actions/checkout@v4 + go-version-file: ${{ inputs.go-version-file }} - name: golangci-lint uses: golangci/golangci-lint-action@v8 with: @@ -43,10 +43,10 @@ jobs: go-fix: runs-on: ubuntu-latest steps: + - uses: actions/checkout@v4 - uses: actions/setup-go@v6 with: - go-version: ${{ inputs.go-version }} - - uses: actions/checkout@v4 + go-version-file: ${{ inputs.go-version-file }} - name: Check for go fix suggestions working-directory: ${{ inputs.working-directory }} run: | diff --git a/.github/workflows/validate-go-version.yml b/.github/workflows/validate-go-version.yml new file mode 100644 index 00000000000..4a0888937f9 --- /dev/null +++ b/.github/workflows/validate-go-version.yml @@ -0,0 +1,89 @@ +name: validate-go-version + +on: + pull_request: + paths: + - "**/go.mod" + - "**/Dockerfile" + - ".devcontainer/devcontainer.json" + - "eng/pipelines/templates/steps/setup-go.yml" + - ".github/workflows/validate-go-version.yml" + branches: [main] + +permissions: + contents: read + +jobs: + check-go-version-consistency: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Validate Go version consistency + run: | + # Source of truth: cli/azd/go.mod + EXPECTED=$(grep -m1 '^go ' cli/azd/go.mod | awk '{print $2}') + echo "Expected Go version (from cli/azd/go.mod): $EXPECTED" + + ERRORS=0 + + # Check all go.mod files + echo "" + echo "Checking go.mod files..." + for f in $(find cli/azd -name 'go.mod'); do + VERSION=$(grep -m1 '^go ' "$f" | awk '{print $2}') + if [ "$VERSION" != "$EXPECTED" ]; then + echo "::error file=$f::Go version mismatch: found '$VERSION', expected '$EXPECTED'" + ERRORS=$((ERRORS + 1)) + else + echo " OK: $f ($VERSION)" + fi + done + + # Check ADO pipeline template + echo "" + echo "Checking ADO pipeline template..." + ADO_FILE="eng/pipelines/templates/steps/setup-go.yml" + if [ -f "$ADO_FILE" ]; then + ADO_VERSION=$(grep -m1 'GoVersion:' "$ADO_FILE" | awk '{print $2}') + if [ "$ADO_VERSION" != "$EXPECTED" ]; then + echo "::error file=$ADO_FILE::GoVersion mismatch: found '$ADO_VERSION', expected '$EXPECTED'" + ERRORS=$((ERRORS + 1)) + else + echo " OK: $ADO_FILE ($ADO_VERSION)" + fi + fi + + # Check Dockerfiles referencing golang: base images + echo "" + echo "Checking Dockerfiles..." + for f in $(find cli/azd -name 'Dockerfile'); do + DOCKER_VERSION=$(grep -oP 'golang:\K[\d.]+' "$f" | head -1) + if [ -n "$DOCKER_VERSION" ] && [ "$DOCKER_VERSION" != "$EXPECTED" ]; then + echo "::error file=$f::Dockerfile golang version mismatch: found '$DOCKER_VERSION', expected '$EXPECTED'" + ERRORS=$((ERRORS + 1)) + elif [ -n "$DOCKER_VERSION" ]; then + echo " OK: $f (golang:$DOCKER_VERSION)" + fi + done + + # Check devcontainer.json Go feature version + echo "" + echo "Checking devcontainer.json..." + DEVCONTAINER=".devcontainer/devcontainer.json" + if [ -f "$DEVCONTAINER" ]; then + DC_VERSION=$(grep -A1 'devcontainers/features/go' "$DEVCONTAINER" | grep -oP '"version":\s*"\K[\d.]+') + if [ -n "$DC_VERSION" ] && [ "$DC_VERSION" != "$EXPECTED" ]; then + echo "::error file=$DEVCONTAINER::devcontainer Go version mismatch: found '$DC_VERSION', expected '$EXPECTED'" + ERRORS=$((ERRORS + 1)) + elif [ -n "$DC_VERSION" ]; then + echo " OK: $DEVCONTAINER ($DC_VERSION)" + fi + fi + + echo "" + if [ "$ERRORS" -gt 0 ]; then + echo "::error::$ERRORS Go version mismatch(es) found. Run 'pwsh eng/scripts/Update-GoVersion.ps1 -NewVersion $EXPECTED' to fix." + exit 1 + fi + echo "All Go versions are consistent ($EXPECTED)." diff --git a/cli/azd/CONTRIBUTING.md b/cli/azd/CONTRIBUTING.md index c255779c175..00bc15d25e4 100644 --- a/cli/azd/CONTRIBUTING.md +++ b/cli/azd/CONTRIBUTING.md @@ -20,7 +20,7 @@ In general, to make contributions a smooth and easy experience, we encourage the Prerequisites: -- [Go](https://go.dev/dl/) 1.26 +- [Go](https://go.dev/dl/) 1.26.1 Build: diff --git a/cli/azd/extensions/azure.ai.agents/go.mod b/cli/azd/extensions/azure.ai.agents/go.mod index a1a92ddf2b4..07f57f70fda 100644 --- a/cli/azd/extensions/azure.ai.agents/go.mod +++ b/cli/azd/extensions/azure.ai.agents/go.mod @@ -1,6 +1,6 @@ module azureaiagent -go 1.26.0 +go 1.26.1 require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 diff --git a/cli/azd/extensions/azure.ai.finetune/go.mod b/cli/azd/extensions/azure.ai.finetune/go.mod index be71311b760..fd73a316ba5 100644 --- a/cli/azd/extensions/azure.ai.finetune/go.mod +++ b/cli/azd/extensions/azure.ai.finetune/go.mod @@ -1,6 +1,6 @@ module azure.ai.finetune -go 1.26.0 +go 1.26.1 require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 diff --git a/cli/azd/extensions/azure.ai.models/go.mod b/cli/azd/extensions/azure.ai.models/go.mod index ec1b0e6f97d..66ed0c8ff4d 100644 --- a/cli/azd/extensions/azure.ai.models/go.mod +++ b/cli/azd/extensions/azure.ai.models/go.mod @@ -1,6 +1,6 @@ module azure.ai.models -go 1.26.0 +go 1.26.1 require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 diff --git a/cli/azd/extensions/azure.appservice/go.mod b/cli/azd/extensions/azure.appservice/go.mod index 01ea0ca28de..3f518b3f275 100644 --- a/cli/azd/extensions/azure.appservice/go.mod +++ b/cli/azd/extensions/azure.appservice/go.mod @@ -1,6 +1,6 @@ module azureappservice -go 1.26.0 +go 1.26.1 require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 diff --git a/cli/azd/extensions/azure.coding-agent/go.mod b/cli/azd/extensions/azure.coding-agent/go.mod index 4e84c636ece..fd839c0772e 100644 --- a/cli/azd/extensions/azure.coding-agent/go.mod +++ b/cli/azd/extensions/azure.coding-agent/go.mod @@ -1,6 +1,6 @@ module azurecodingagent -go 1.26.0 +go 1.26.1 require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 diff --git a/cli/azd/extensions/microsoft.azd.concurx/go.mod b/cli/azd/extensions/microsoft.azd.concurx/go.mod index 2be9bd23f2a..03d2f4b2692 100644 --- a/cli/azd/extensions/microsoft.azd.concurx/go.mod +++ b/cli/azd/extensions/microsoft.azd.concurx/go.mod @@ -1,6 +1,6 @@ module concurx -go 1.26.0 +go 1.26.1 require ( github.com/azure/azure-dev/cli/azd v1.23.13 diff --git a/cli/azd/go.mod b/cli/azd/go.mod index 6414505dd78..4ae352b07ee 100644 --- a/cli/azd/go.mod +++ b/cli/azd/go.mod @@ -1,6 +1,6 @@ module github.com/azure/azure-dev/cli/azd -go 1.26.0 +go 1.26.1 require ( dario.cat/mergo v1.0.2 diff --git a/cli/azd/test/functional/testdata/samples/containerappjob/src/job/Dockerfile b/cli/azd/test/functional/testdata/samples/containerappjob/src/job/Dockerfile index 87d88e49336..e8a55d5072f 100644 --- a/cli/azd/test/functional/testdata/samples/containerappjob/src/job/Dockerfile +++ b/cli/azd/test/functional/testdata/samples/containerappjob/src/job/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.23-alpine AS build +FROM golang:1.26.1-alpine AS build WORKDIR /app COPY . . RUN go build -o /job . diff --git a/cli/azd/test/functional/testdata/samples/containerappjob/src/job/go.mod b/cli/azd/test/functional/testdata/samples/containerappjob/src/job/go.mod index 55c1cbe7dda..2f82c270e14 100644 --- a/cli/azd/test/functional/testdata/samples/containerappjob/src/job/go.mod +++ b/cli/azd/test/functional/testdata/samples/containerappjob/src/job/go.mod @@ -1,3 +1,3 @@ module containerappjob -go 1.23 +go 1.26.1 diff --git a/eng/pipelines/templates/steps/setup-go.yml b/eng/pipelines/templates/steps/setup-go.yml index 7e7bef39d4a..f4bd4aa1673 100644 --- a/eng/pipelines/templates/steps/setup-go.yml +++ b/eng/pipelines/templates/steps/setup-go.yml @@ -1,5 +1,5 @@ parameters: - GoVersion: 1.26.0 + GoVersion: 1.26.1 Condition: succeeded() steps: diff --git a/eng/scripts/Update-GoVersion.ps1 b/eng/scripts/Update-GoVersion.ps1 new file mode 100644 index 00000000000..a97976e8647 --- /dev/null +++ b/eng/scripts/Update-GoVersion.ps1 @@ -0,0 +1,94 @@ +param( + [Parameter(Mandatory = $true)] + [string] $NewVersion +) + +Set-StrictMode -Version 4 +$ErrorActionPreference = 'Stop' + +$repoRoot = Resolve-Path "$PSScriptRoot/../../" + +# Canonical source of truth +$coreGoMod = Join-Path $repoRoot 'cli/azd/go.mod' + +# All go.mod files that should track the same Go version (including testdata samples). +$goModFiles = Get-ChildItem -Path (Join-Path $repoRoot 'cli/azd') -Recurse -Filter 'go.mod' + +# ADO pipeline template that pins the Go toolchain version +$adoSetupGo = Join-Path $repoRoot 'eng/pipelines/templates/steps/setup-go.yml' + +$updated = @() +$skipped = @() + +# --- Update go.mod files --- +foreach ($file in $goModFiles) { + $content = Get-Content $file.FullName -Raw + if ($content -match '(?m)^go\s+\S+') { + $newContent = $content -replace '(?m)^go\s+\S+', "go $NewVersion" + if ($newContent -ne $content) { + Set-Content -Path $file.FullName -Value $newContent -NoNewline -Encoding utf8NoBOM + $updated += $file.FullName.Substring($repoRoot.Path.Length) + } else { + $skipped += $file.FullName.Substring($repoRoot.Path.Length) + } + } +} + +# --- Update ADO pipeline template --- +if (Test-Path $adoSetupGo) { + $content = Get-Content $adoSetupGo -Raw + $newContent = $content -replace '(?m)^(\s+GoVersion:\s+)\S+', "`${1}$NewVersion" + if ($newContent -ne $content) { + Set-Content -Path $adoSetupGo -Value $newContent -NoNewline -Encoding utf8NoBOM + $updated += $adoSetupGo.Substring($repoRoot.Path.Length) + } else { + $skipped += $adoSetupGo.Substring($repoRoot.Path.Length) + } +} + +# --- Update Dockerfiles referencing golang: base images --- +$dockerfiles = Get-ChildItem -Path (Join-Path $repoRoot 'cli/azd') -Recurse -Filter 'Dockerfile' +foreach ($file in $dockerfiles) { + $content = Get-Content $file.FullName -Raw + if ($content -match 'golang:\d+\.\d+') { + $newContent = $content -replace 'golang:\d+[\d.]*', "golang:$NewVersion" + if ($newContent -ne $content) { + Set-Content -Path $file.FullName -Value $newContent -NoNewline -Encoding utf8NoBOM + $updated += $file.FullName.Substring($repoRoot.Path.Length) + } else { + $skipped += $file.FullName.Substring($repoRoot.Path.Length) + } + } +} + +# --- Update devcontainer.json Go feature version --- +$devcontainer = Join-Path $repoRoot '.devcontainer/devcontainer.json' +if (Test-Path $devcontainer) { + $content = Get-Content $devcontainer -Raw + $newContent = $content -replace '("ghcr\.io/devcontainers/features/go:\d+":\s*\{\s*"version":\s*")[\d.]+(")', "`${1}$NewVersion`${2}" + if ($newContent -ne $content) { + Set-Content -Path $devcontainer -Value $newContent -NoNewline -Encoding utf8NoBOM + $updated += $devcontainer.Substring($repoRoot.Path.Length) + } else { + $skipped += $devcontainer.Substring($repoRoot.Path.Length) + } +} + +# --- Report --- +Write-Host "" +if ($updated.Count -gt 0) { + Write-Host "Updated $($updated.Count) file(s) to Go $NewVersion`:" -ForegroundColor Green + $updated | ForEach-Object { Write-Host " $_" } +} else { + Write-Host "No files needed updating." -ForegroundColor Yellow +} + +if ($skipped.Count -gt 0) { + Write-Host "" + Write-Host "Already at Go $NewVersion ($($skipped.Count) file(s)):" -ForegroundColor Cyan + $skipped | ForEach-Object { Write-Host " $_" } +} + +Write-Host "" +Write-Host "Done. GitHub Actions workflows read the version from cli/azd/go.mod automatically." -ForegroundColor Green +Write-Host "Run 'git diff' to review changes before committing." -ForegroundColor Gray