Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions .github/workflows/bump-go-toolchain.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
name: Bump Go toolchain

on:
schedule:
# Run daily at 05:00 UTC.
- cron: "0 5 * * *"
workflow_dispatch:
inputs:
version:
description: >
Go toolchain version to use (e.g. "go1.25.9").
If empty, the latest patch release is detected automatically.
required: false

permissions:
contents: write
pull-requests: write

jobs:
bump-go-toolchain:
runs-on:
group: databricks-protected-runner-group-large
labels: linux-ubuntu-latest-large

steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Determine current toolchain version
id: current
run: |
toolchain=$(grep '^toolchain' go.mod | awk '{print $2}')
Comment on lines +31 to +32
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Nit] No empty guard on grep result (Found by: Isaac, cross-review)

If the toolchain directive is ever removed from go.mod, grep '^toolchain' returns empty, minor becomes empty, and the jq filter would match all Go releases across all minors, potentially triggering an unintended minor version upgrade PR. Consider failing fast if toolchain is empty.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't fix. If the toolchain directive is removed from go.mod, the workflow failing is the correct behavior.

minor=$(echo "$toolchain" | sed 's/^go//' | cut -d. -f1,2)
echo "toolchain=$toolchain" >> "$GITHUB_OUTPUT"
echo "minor=$minor" >> "$GITHUB_OUTPUT"

- name: Determine latest patch release
id: latest
env:
INPUT_VERSION: ${{ inputs.version }}
run: |
if [ -n "$INPUT_VERSION" ]; then
if ! echo "$INPUT_VERSION" | grep -qE '^go[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "Invalid version format: $INPUT_VERSION"
exit 1
fi
toolchain="$INPUT_VERSION"
else
minor=${{ steps.current.outputs.minor }}
toolchain=$(
curl -fsSL 'https://go.dev/dl/?mode=json' |
jq -r --arg minor "go${minor}." '[.[] | select(.version | startswith($minor))][0].version // empty'
)
Comment on lines +50 to +53
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Major] No guard when jq returns null for EOL'd minor series (Found by: Both reviewers independently)

If the current minor is dropped from go.dev/dl/?mode=json (Go only keeps the two most recent minors), jq returns null. This flows into GITHUB_OUTPUT, the check step sees go1.25.7 != null, declares an update needed, and go mod edit -toolchain=null fails with a misleading error. Scheduled runs become recurring failures.

Suggestion: use // empty and guard:

toolchain=$(curl -fsSL 'https://go.dev/dl/?mode=json' | \
  jq -r --arg minor "go${minor}." \
  '[.[] | select(.version | startswith($minor))][0].version // empty')
if [ -z "$toolchain" ]; then
  echo "No release found for go${minor}.x - minor series may be EOL."
  exit 1
fi

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Added // empty to the jq filter and an explicit guard that fails the step if no release is found.

if [ -z "$toolchain" ]; then
echo "No release found for go${minor}.x"
exit 1
fi
fi
echo "toolchain=$toolchain" >> "$GITHUB_OUTPUT"

- name: Check if update is needed
id: check
run: |
if [ "${{ steps.current.outputs.toolchain }}" = "${{ steps.latest.outputs.toolchain }}" ]; then
echo "Up to date: ${{ steps.current.outputs.toolchain }}"
echo "needed=false" >> "$GITHUB_OUTPUT"
else
echo "Update available: ${{ steps.current.outputs.toolchain }} -> ${{ steps.latest.outputs.toolchain }}"
echo "needed=true" >> "$GITHUB_OUTPUT"
fi

- name: Setup Go
if: steps.check.outputs.needed == 'true'
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod

- name: Update go.mod files
if: steps.check.outputs.needed == 'true'
env:
TOOLCHAIN: ${{ steps.latest.outputs.toolchain }}
run: |
while IFS= read -r modfile; do
dir=$(dirname "$modfile")
if grep -q '^toolchain' "$modfile"; then
(cd "$dir" && go mod edit -toolchain="$TOOLCHAIN")
fi
done < <(git ls-files '**/go.mod' 'go.mod')

- name: Show diff
if: steps.check.outputs.needed == 'true'
run: git diff

- name: Create pull request
if: steps.check.outputs.needed == 'true' && inputs.version == ''
Comment on lines +94 to +95
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Major] Auto-created PR will not trigger CI (Found by: Isaac, Confirmed by: Cursor)

peter-evans/create-pull-request with the default GITHUB_TOKEN will not trigger downstream workflows on the created PR (GitHub's safeguard against recursive triggers). Every auto-generated toolchain-bump PR lands with zero CI signal, so reviewers merge blind or have to close/reopen manually.

Suggestion: supply a token: input from a GitHub App installation token or PAT with repo scope:

with:
  token: ${{ steps.app-token.outputs.token }}
  branch: auto/bump-go-toolchain
  ...

If not available, at minimum note in the PR body that CI did not run.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acknowledged. This is a known limitation of GITHUB_TOKEN. Fixing it requires a GitHub App or PAT, which is out of scope for this PR. Reviewers can push an empty commit to trigger CI.

uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
with:
branch: auto/bump-go-toolchain
commit-message: "Bump Go toolchain to ${{ steps.latest.outputs.toolchain }}"
title: "Bump Go toolchain to ${{ steps.latest.outputs.toolchain }}"
body: |
Bump Go toolchain from `${{ steps.current.outputs.toolchain }}` to `${{ steps.latest.outputs.toolchain }}`.

Release notes: https://go.dev/doc/devel/release#${{ steps.latest.outputs.toolchain }}
reviewers: simonfaltum,andrewnester,anton-107,denik,janniklasrose,pietern,shreyas-goenka
labels: dependencies
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Nit] Hardcoded individual reviewers (Found by: Isaac, Confirmed by: Cursor)

Pinning seven usernames means every team change requires a workflow edit. Consider using team-reviewers: <org>/<team-slug> (supported by peter-evans/create-pull-request), or rely on CODEOWNERS + branch protection.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intentional. team-reviewers requires org-level token access which the default GITHUB_TOKEN doesn't have.

Loading