From e5f5427b97858bf1082fda2084b2119faf2599db Mon Sep 17 00:00:00 2001 From: William Martin Date: Wed, 13 May 2026 13:25:39 +0200 Subject: [PATCH] Simplify bump-go.sh toolchain logic Address review feedback: always set both go and toolchain directives via go mod edit, then let go mod tidy normalize. This eliminates complex conditional toolchain handling. Additional fixes: - Add go mod tidy after edits to reconcile dependencies - Commit go.sum alongside go.mod - Filter PR search to open PRs only (--state open) - Use GITHUB_REPOSITORY for repo instead of hardcoding - Use git diff to detect no-op bumps post-tidy - Read go.mod state via go mod edit -json instead of grep Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/scripts/bump-go.sh | 124 +++++++++++---------------- 1 file changed, 49 insertions(+), 75 deletions(-) diff --git a/.github/workflows/scripts/bump-go.sh b/.github/workflows/scripts/bump-go.sh index d67412499..16dd346e8 100755 --- a/.github/workflows/scripts/bump-go.sh +++ b/.github/workflows/scripts/bump-go.sh @@ -1,15 +1,15 @@ #!/usr/bin/env bash # -# bump-go.sh — Update go.mod `go` directive and toolchain to latest stable Go release. +# bump-go.sh -- Update go.mod `go` directive and toolchain to latest stable Go release. # # Usage: # ./bump-go.sh [--apply|-a] # -# By default the script runs in *dry‑run* mode: it creates a local branch, +# By default the script runs in *dry-run* mode: it creates a local branch, # commits the version bump, shows the exact patch, **checks for an existing PR** # with the same title, and exits. Nothing is pushed. The temporary branch is # deleted automatically on exit, so your working tree stays clean. Pass -# --apply (or -a) to push the branch and open a new PR *only if one doesn’t +# --apply (or -a) to push the branch and open a new PR *only if one doesn't # already exist*. # ----------------------------------------------------------------------------- set -euo pipefail @@ -35,29 +35,32 @@ done [[ -z "$GO_MOD" ]] && usage [[ -f "$GO_MOD" ]] || { echo "Error: '$GO_MOD' not found" >&2; exit 1; } +REPO="cli/cli" +MODULE_DIR=$(dirname "$GO_MOD") +GO_SUM="$MODULE_DIR/go.sum" + # ---- Discover latest stable Go release -------------------------------------- -echo "Fetching latest stable Go version…" +echo "Fetching latest stable Go version..." LATEST_JSON=$(curl -fsSL https://go.dev/dl/?mode=json | jq -c '[.[] | select(.stable==true)][0]') FULL_VERSION=$(jq -r '.version' <<< "$LATEST_JSON") # e.g. go1.23.4 TOOLCHAIN_VERSION="${FULL_VERSION#go}" # e.g. 1.23.4 +GO_DIRECTIVE_VERSION="$(cut -d. -f1-2 <<< "$TOOLCHAIN_VERSION").0" -# The go directive can be either X.Y.0 (minor version) or X.Y.Z (patch version) -# We accept both forms as "latest" if they match the toolchain's major.minor -LATEST_MAJOR_MINOR="$(cut -d. -f1-2 <<< "$TOOLCHAIN_VERSION")" - -echo " → latest toolchain : $TOOLCHAIN_VERSION" +echo " → go directive : $GO_DIRECTIVE_VERSION" +echo " → toolchain : go$TOOLCHAIN_VERSION" # ---- Read current go.mod state using go mod edit ---------------------------- GO_MOD_JSON=$(go mod edit -json "$GO_MOD") CURRENT_GO_DIRECTIVE=$(jq -r '.Go // ""' <<< "$GO_MOD_JSON") -CURRENT_TOOLCHAIN_DIRECTIVE=$(jq -r '.Toolchain // ""' <<< "$GO_MOD_JSON") +CURRENT_TOOLCHAIN=$(jq -r '.Toolchain // ""' <<< "$GO_MOD_JSON") -CURRENT_MAJOR_MINOR="$(cut -d. -f1-2 <<< "$CURRENT_GO_DIRECTIVE")" +echo " → current go : $CURRENT_GO_DIRECTIVE" +echo " → current tc : ${CURRENT_TOOLCHAIN:-(none)}" +# ---- Prepare Git branch ----------------------------------------------------- BRANCH="bump-go-$TOOLCHAIN_VERSION" BRANCH_CREATED=0 -# Set up cleanup trap early (before any potential exits) cleanup() { if [[ $BRANCH_CREATED -eq 1 ]]; then git checkout - >/dev/null 2>&1 || true @@ -66,58 +69,32 @@ cleanup() { } trap cleanup EXIT -# Check if we're already up to date -# Note: toolchain directive may be missing when go directive matches latest toolchain. -# This is expected behavior - `go mod tidy` removes the toolchain line when -# the minimum Go version matches the latest toolchain, as it's redundant. -if [[ "$CURRENT_MAJOR_MINOR" = "$LATEST_MAJOR_MINOR" ]]; then - # Current go directive is at the same major.minor as latest - if [[ -z "$CURRENT_TOOLCHAIN_DIRECTIVE" ]]; then - # No toolchain directive present - this is expected when go version matches latest - echo "Already on latest Go version: $CURRENT_GO_DIRECTIVE (latest toolchain: $TOOLCHAIN_VERSION)" - echo " → Note: No toolchain directive (expected when go version matches latest toolchain)" - exit 0 - elif [[ "$CURRENT_TOOLCHAIN_DIRECTIVE" = "go$TOOLCHAIN_VERSION" ]]; then - echo "Already on latest Go version: $CURRENT_GO_DIRECTIVE (toolchain: $CURRENT_TOOLCHAIN_DIRECTIVE)" - exit 0 - fi - # Current go directive is latest but toolchain is outdated - continue to update toolchain -fi - echo "Creating branch $BRANCH" git switch -c "$BRANCH" >/dev/null 2>&1 BRANCH_CREATED=1 -# ---- Patch go.mod using go mod edit ----------------------------------------- -# Only update go directive if we're not already at the latest major.minor version -if [[ "$CURRENT_MAJOR_MINOR" != "$LATEST_MAJOR_MINOR" ]]; then - # Bump to the latest major.minor.0 (preserves the convention of X.Y.0 for go directive) - NEW_GO_DIRECTIVE="$LATEST_MAJOR_MINOR.0" - go mod edit -go="$NEW_GO_DIRECTIVE" "$GO_MOD" - echo " • go directive $CURRENT_GO_DIRECTIVE → $NEW_GO_DIRECTIVE" - # After updating, the current go directive is now the new one for toolchain logic - CURRENT_GO_DIRECTIVE="$NEW_GO_DIRECTIVE" -fi +# ---- Patch go.mod ----------------------------------------------------------- +# Always set both directives and let `go mod tidy` normalize. +# When the go directive version matches the toolchain version, tidy will remove +# the toolchain line because it is redundant -- this is expected Go behavior. +go mod edit -go="$GO_DIRECTIVE_VERSION" -toolchain="go$TOOLCHAIN_VERSION" "$GO_MOD" +echo " • set go directive → $GO_DIRECTIVE_VERSION" +echo " • set toolchain → go$TOOLCHAIN_VERSION" -# Handle toolchain directive - may need to add, update, or skip -if [[ -z "$CURRENT_TOOLCHAIN_DIRECTIVE" ]]; then - # No toolchain directive exists - CURRENT_MAJOR_MINOR="$(cut -d. -f1-2 <<< "$CURRENT_GO_DIRECTIVE")" - if [[ "$CURRENT_MAJOR_MINOR" = "$LATEST_MAJOR_MINOR" ]]; then - # go directive is at latest major.minor - toolchain line is redundant - echo " • toolchain directive not needed (go version matches latest toolchain)" - else - # go directive is older than latest toolchain - add toolchain directive - go mod edit -toolchain="go$TOOLCHAIN_VERSION" "$GO_MOD" - echo " • toolchain directive added: go$TOOLCHAIN_VERSION" - fi -elif [[ "$CURRENT_TOOLCHAIN_DIRECTIVE" != "go$TOOLCHAIN_VERSION" ]]; then - # Toolchain directive exists but needs updating - go mod edit -toolchain="go$TOOLCHAIN_VERSION" "$GO_MOD" - echo " • toolchain $CURRENT_TOOLCHAIN_DIRECTIVE → go$TOOLCHAIN_VERSION" +# Let go mod tidy reconcile dependencies and normalize directives. +echo " • running go mod tidy..." +pushd "$MODULE_DIR" > /dev/null +go mod tidy +popd > /dev/null + +# ---- Check if anything actually changed ------------------------------------- +if git diff --quiet -- "$GO_MOD" "$GO_SUM" 2>/dev/null; then + echo "Already on latest Go version -- no changes needed." + exit 0 fi git add "$GO_MOD" +[[ -f "$GO_SUM" ]] && git add "$GO_SUM" # ---- Commit ----------------------------------------------------------------- COMMIT_MSG="Bump Go to $TOOLCHAIN_VERSION" @@ -127,48 +104,45 @@ COMMIT_HASH=$(git rev-parse --short HEAD) PR_TITLE="$COMMIT_MSG" # ---- Check for existing PR -------------------------------------------------- -existing_pr=$(gh search prs --repo cli/cli --match title "$PR_TITLE" --json title --jq "map(select(.title == \"$PR_TITLE\") | .title) | length > 0") +existing_pr=$(gh search prs --repo "$REPO" --state open --match title "$PR_TITLE" \ + --json title --jq "map(select(.title == \"$PR_TITLE\") | .title) | length > 0") if [[ "$existing_pr" == "true" ]]; then echo "Found an existing open PR titled '$PR_TITLE'. Skipping push/PR creation." if [[ $APPLY -eq 0 ]]; then - echo -e "\n=== DRY‑RUN DIFF (commit $COMMIT_HASH):\n" + echo -e "\n=== DRY-RUN DIFF (commit $COMMIT_HASH):\n" git --no-pager show --color "$COMMIT_HASH" fi exit 0 fi -# ---- Dry‑run handling ------------------------------------------------------- +# ---- Dry-run handling ------------------------------------------------------- if [[ $APPLY -eq 0 ]]; then - echo -e "\n=== DRY‑RUN DIFF (commit $COMMIT_HASH):\n" + echo -e "\n=== DRY-RUN DIFF (commit $COMMIT_HASH):\n" git --no-pager show --color "$COMMIT_HASH" echo -e "\nIf --apply were provided, script would continue with:\n git push -u origin $BRANCH\n gh pr create --title \"$PR_TITLE\" --body \n" exit 0 fi # ---- Push & PR -------------------------------------------------------------- -# Get the actual go directive from the updated go.mod using go mod edit FINAL_GO_MOD_JSON=$(go mod edit -json "$GO_MOD") -FINAL_GO_DIRECTIVE=$(jq -r '.Go // ""' <<< "$FINAL_GO_MOD_JSON") -FINAL_TOOLCHAIN_DIRECTIVE=$(jq -r '.Toolchain // ""' <<< "$FINAL_GO_MOD_JSON") +FINAL_GO=$(jq -r '.Go // ""' <<< "$FINAL_GO_MOD_JSON") +FINAL_TC=$(jq -r '.Toolchain // ""' <<< "$FINAL_GO_MOD_JSON") -if [[ -n "$FINAL_TOOLCHAIN_DIRECTIVE" ]]; then - PR_BODY=$(cat <