Skip to content
Merged
Show file tree
Hide file tree
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
4 changes: 2 additions & 2 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ test/integration/attestation-cmd @cli/package-security @cli/code-reviewers

pkg/cmd/attestation/verification/embed/tuf-repo.github.com/ @cli/tuf-root-reviewers @cli/code-reviewers

pkg/cmd/skills/ @cli/skill-reviewers @cli/code-reviewers
internal/skills/ @cli/skill-reviewers @cli/code-reviewers
pkg/cmd/skills/ @cli/skills @cli/code-reviewers
internal/skills/ @cli/skills @cli/code-reviewers
94 changes: 60 additions & 34 deletions .github/workflows/scripts/bump-go.sh
Original file line number Diff line number Diff line change
@@ -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] <path/to/go.mod>
#
# By default the script runs in *dryrun* 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 doesnt
# --apply (or -a) to push the branch and open a new PR *only if one doesn't
# already exist*.
# -----------------------------------------------------------------------------
set -euo pipefail
Expand All @@ -35,52 +35,66 @@ 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 mod tidy` will always add `.0` if there is no minor version
# so let's just ensure .0 is suffixed to the go directive.
GO_DIRECTIVE_VERSION="$(cut -d. -f1-2 <<< "$TOOLCHAIN_VERSION").0"

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

# ---- Prepare Git branch ---------------------------------------------------
CURRENT_GO_DIRECTIVE=$(grep -E '^go ' "$GO_MOD" | cut -d ' ' -f2)
CURRENT_TOOLCHAIN_DIRECTIVE=$(grep -E '^toolchain ' "$GO_MOD" | cut -d ' ' -f2)
# ---- 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=$(jq -r '.Toolchain // ""' <<< "$GO_MOD_JSON")

if [[ "$CURRENT_GO_DIRECTIVE" = "$GO_DIRECTIVE_VERSION" && \
"$CURRENT_TOOLCHAIN_DIRECTIVE" = "go$TOOLCHAIN_VERSION" ]]; then
echo "Already on latest Go version: $CURRENT_GO_DIRECTIVE (toolchain: $CURRENT_TOOLCHAIN_DIRECTIVE)"
exit 0
fi
echo " → current go : $CURRENT_GO_DIRECTIVE"
echo " → current tc : ${CURRENT_TOOLCHAIN:-(none)}"

# ---- Prepare Git branch -----------------------------------------------------
BRANCH="bump-go-$TOOLCHAIN_VERSION"
BRANCH_CREATED=0

cleanup() {
git checkout - >/dev/null 2>&1 || true
git branch -D "$BRANCH" >/dev/null 2>&1 || true
if [[ $BRANCH_CREATED -eq 1 ]]; then
git checkout - >/dev/null 2>&1 || true
git branch -D "$BRANCH" >/dev/null 2>&1 || true
fi
}
trap cleanup EXIT

echo "Creating branch $BRANCH"
git switch -c "$BRANCH" >/dev/null 2>&1
BRANCH_CREATED=1

# ---- Patch go.mod -----------------------------------------------------------
if [[ "$CURRENT_GO_DIRECTIVE" != "$GO_DIRECTIVE_VERSION" ]]; then
sed -Ei.bak "s/^go [0-9]+\.[0-9]+.*$/go $GO_DIRECTIVE_VERSION/" "$GO_MOD"
echo " • go directive $CURRENT_GO_DIRECTIVE → $GO_DIRECTIVE_VERSION"
fi

if [[ "$CURRENT_TOOLCHAIN_DIRECTIVE" != "go$TOOLCHAIN_VERSION" ]]; then
sed -Ei.bak "s/^toolchain go[0-9]+\.[0-9]+\.[0-9]+.*$/toolchain go$TOOLCHAIN_VERSION/" "$GO_MOD"
echo " • toolchain $CURRENT_TOOLCHAIN_DIRECTIVE → go$TOOLCHAIN_VERSION"
# 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"

# 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

rm -f "$GO_MOD.bak"

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

# ---- Commit -----------------------------------------------------------------
COMMIT_MSG="Bump Go to $TOOLCHAIN_VERSION"
Expand All @@ -90,31 +104,43 @@ 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=== DRYRUN 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

# ---- Dryrun handling -------------------------------------------------------
# ---- Dry-run handling -------------------------------------------------------
if [[ $APPLY -eq 0 ]]; then
echo -e "\n=== DRYRUN 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 <body>\n"
exit 0
fi

# ---- Push & PR --------------------------------------------------------------
FINAL_GO_MOD_JSON=$(go mod edit -json "$GO_MOD")
FINAL_GO=$(jq -r '.Go // ""' <<< "$FINAL_GO_MOD_JSON")
FINAL_TC=$(jq -r '.Toolchain // ""' <<< "$FINAL_GO_MOD_JSON")

# Build PR body reflecting final state after tidy
if [[ -n "$FINAL_TC" ]]; then
TC_LINE="* **toolchain:** \`$FINAL_TC\`"
else
TC_LINE="* **toolchain:** _(none -- \`go mod tidy\` removed it because the go directive already implies go$TOOLCHAIN_VERSION)_"
fi

PR_BODY=$(cat <<EOF
This PR updates Go to the latest stable release.

* **go directive:** \`$GO_DIRECTIVE_VERSION\`
* **toolchain:** \`$TOOLCHAIN_VERSION\`
* **go directive:** \`$FINAL_GO\`
$TC_LINE
EOF
)

Expand Down
12 changes: 10 additions & 2 deletions internal/telemetry/detach_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,15 @@ import (

// detachAttrs returns SysProcAttr configured to place the child in its own
// process group so that console signals (Ctrl+C) delivered to the parent's
// group are not forwarded to the child.
// group are not forwarded to the child, and to suppress any console window
// for the child and its descendants.
//
// CREATE_NO_WINDOW is preferred over DETACHED_PROCESS here: DETACHED_PROCESS
// removes the console entirely, which causes any console-subsystem descendant
// (e.g. tzutil.exe invoked transitively to resolve the local IANA timezone)
// to allocate a fresh conhost window, producing a visible flash on every gh
// invocation. CREATE_NO_WINDOW gives the child a non-visible console that
// descendants can inherit, avoiding the flash.
func detachAttrs() *syscall.SysProcAttr {
return &syscall.SysProcAttr{CreationFlags: windows.CREATE_NEW_PROCESS_GROUP | windows.DETACHED_PROCESS}
return &syscall.SysProcAttr{CreationFlags: windows.CREATE_NEW_PROCESS_GROUP | windows.CREATE_NO_WINDOW}
}
Loading