Skip to content
11 changes: 9 additions & 2 deletions .github/workflows/bump-go.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,9 +14,16 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Set up Go
id: setup-go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: 'go.mod'
go-version: 'stable'

- name: Install golangci-lint
uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0
with:
version: latest
install-only: true

- name: Bump Go version
env:
Expand All@@ -26,4 +33,4 @@ jobs:
GIT_AUTHOR_EMAIL: noreply@github.com
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
bash .github/workflows/scripts/bump-go.sh --apply go.mod
bash .github/workflows/scripts/bump-go.sh --apply --version "${{ steps.setup-go.outputs.go-version }}" go.mod
79 changes: 67 additions & 12 deletions .github/workflows/scripts/bump-go.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@
# bump-go.sh -- Update go.mod `go` directive and toolchain to latest stable Go release.
#
# Usage:
# ./bump-go.sh [--apply|-a] <path/to/go.mod>
# ./bump-go.sh [--apply|-a] [--version <version>] <path/to/go.mod>
#
# 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**
Expand All@@ -15,17 +15,23 @@
set -euo pipefail

usage() {
echo "Usage: $0 [--apply|-a] <path/to/go.mod>" >&2
echo "Usage: $0 [--apply|-a] [--version <version>] <path/to/go.mod>" >&2
exit 1
}

# ---- Argument parsing -------------------------------------------------------
APPLY=0
GO_MOD=""
TARGET_GO_VERSION=""

while [[ $# -gt 0 ]]; do
case "$1" in
--apply|-a) APPLY=1 ;;
--version)
shift
[[ $# -gt 0 ]] || usage
TARGET_GO_VERSION="${1#go}"
;;
-h|--help) usage ;;
*) [[ -z "$GO_MOD" ]] && GO_MOD="$1" || usage ;;
esac
Expand All@@ -35,20 +41,45 @@ done
[[ -z "$GO_MOD" ]] && usage
[[ -f "$GO_MOD" ]] || { echo "Error: '$GO_MOD' not found" >&2; exit 1; }

REPO_ROOT=$(git rev-parse --show-toplevel)
if ! git -C "$REPO_ROOT" diff --quiet || ! git -C "$REPO_ROOT" diff --cached --quiet; then
echo "Error: tracked changes must be committed or stashed before running this script" >&2
exit 1
fi

REPO="cli/cli"
MODULE_DIR=$(dirname "$GO_MOD")
GO_SUM="$MODULE_DIR/go.sum"
LINT_WORKFLOW="$REPO_ROOT/.github/workflows/lint.yml"

# ---- Discover latest stable Go release --------------------------------------
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
if [[ -n "$TARGET_GO_VERSION" ]]; then
TOOLCHAIN_VERSION="$TARGET_GO_VERSION"
echo "Using selected Go version..."
else
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
fi
if [[ ! "$TOOLCHAIN_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Error: unexpected Go version '$TOOLCHAIN_VERSION'" >&2
exit 1
fi
GO_DIRECTIVE_VERSION="$(cut -d. -f1-2 <<< "$TOOLCHAIN_VERSION").0"

echo " → go directive : $GO_DIRECTIVE_VERSION"
echo " → toolchain : go$TOOLCHAIN_VERSION"

# Keep regular CI reproducibly pinned to the linter release used to validate
# this bump.
LINTER_VERSION=$(golangci-lint version --short)
if [[ ! "$LINTER_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Error: unexpected golangci-lint version '$LINTER_VERSION'" >&2
exit 1
fi
echo " → golangci-lint: v$LINTER_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")
Expand All@@ -63,8 +94,9 @@ BRANCH_CREATED=0

cleanup() {
if [[ $BRANCH_CREATED -eq 1 ]]; then
git checkout - >/dev/null 2>&1 || true
git branch -D "$BRANCH" >/dev/null 2>&1 || true
git -C "$REPO_ROOT" restore --source=HEAD --staged --worktree -- :/ >/dev/null 2>&1 || true
git -C "$REPO_ROOT" checkout - >/dev/null 2>&1 || true
git -C "$REPO_ROOT" branch -D "$BRANCH" >/dev/null 2>&1 || true
fi
}
trap cleanup EXIT
Expand All@@ -81,20 +113,42 @@ go mod edit -go="$GO_DIRECTIVE_VERSION" -toolchain="go$TOOLCHAIN_VERSION" "$GO_M
echo " • set go directive → $GO_DIRECTIVE_VERSION"
echo " • set toolchain → go$TOOLCHAIN_VERSION"

# Let go mod tidy reconcile dependencies and normalize directives.
# Reconcile the module, apply source migrations, and verify the result before
# creating a pull request.
echo " • running go mod tidy..."
pushd "$MODULE_DIR" > /dev/null
go mod tidy
if ! git -C "$REPO_ROOT" diff --quiet -- "$GO_MOD"; then
lint_version_lines=$(grep -Ec '^[[:space:]]+version: v[0-9]+\.[0-9]+\.[0-9]+$' "$LINT_WORKFLOW" || true)
if [[ $lint_version_lines -ne 1 ]]; then
echo "Error: expected exactly one pinned golangci-lint version in '$LINT_WORKFLOW'" >&2
exit 1
fi
sed -i.bak -E "s/^([[:space:]]+version: )v[0-9]+\.[0-9]+\.[0-9]+$/\1v$LINTER_VERSION/" "$LINT_WORKFLOW"
rm -f "$LINT_WORKFLOW.bak"
echo " • set golangci-lint → v$LINTER_VERSION"
else
echo " • Go version unchanged; keeping the existing golangci-lint pin"
fi
echo " • running go fix..."
go fix ./...
status=0
echo " • running tests..."
go test ./... || status=$?
echo " • running golangci-lint..."
golangci-lint run ./... || status=$?
if [[ $status -ne 0 ]]; then
exit "$status"
fi
popd > /dev/null

# ---- Check if anything actually changed -------------------------------------
if git diff --quiet -- "$GO_MOD" "$GO_SUM" 2>/dev/null; then
if git diff --quiet; then
echo "Already on latest Go version -- no changes needed."
exit 0
fi

git add "$GO_MOD"
[[ -f "$GO_SUM" ]] && git add "$GO_SUM"
git add -u

# ---- Commit -----------------------------------------------------------------
COMMIT_MSG="Bump Go to $TOOLCHAIN_VERSION"
Expand DownExpand Up@@ -141,6 +195,7 @@ This PR updates Go to the latest stable release.

* **go directive:** \`$FINAL_GO\`
$TC_LINE
* **golangci-lint:** \`v$LINTER_VERSION\`
EOF
)

Expand Down
2 changes: 1 addition & 1 deletion docs/primer/foundations/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -54,7 +54,7 @@ _Tip: To get a better sense of what feels right, try writing out the commands in

**When designing your command’s language system:**

- Use [GitHub language](/getting-started/principles#make-it-feel-like-github)
- Use [GitHub language](/docs/primer/getting-started#make-it-feel-like-github)
- Use unambiguous language that can’t be confused for something else
- Use shorter phrases if possible and appropriate

Expand Down
Loading