From 7069a8003ce311fe291cbd7e48033c40aace1220 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 10 Mar 2026 02:17:41 +0000 Subject: [PATCH 1/5] Initial plan From 1294d0e71bbb221476440e385b965a89b917215b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 10 Mar 2026 02:35:47 +0000 Subject: [PATCH 2/5] fix: auto-upgrade gh-aw extension in upgrade command and stop for re-run with new version Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/cli/update_extension_check.go | 89 ++++++++++++++++++++++++++ pkg/cli/update_extension_check_test.go | 34 ++++++++++ pkg/cli/upgrade_command.go | 16 ++++- 3 files changed, 136 insertions(+), 3 deletions(-) diff --git a/pkg/cli/update_extension_check.go b/pkg/cli/update_extension_check.go index 67ddc1cc1a0..d787273733e 100644 --- a/pkg/cli/update_extension_check.go +++ b/pkg/cli/update_extension_check.go @@ -3,8 +3,11 @@ package cli import ( "fmt" "os" + "os/exec" "strings" + "golang.org/x/mod/semver" + "github.com/github/gh-aw/pkg/console" "github.com/github/gh-aw/pkg/logger" "github.com/github/gh-aw/pkg/workflow" @@ -82,3 +85,89 @@ func ensureLatestExtensionVersion(verbose bool) error { return nil } + +// upgradeExtensionIfOutdated checks if a newer version of the gh-aw extension is available +// and, if so, upgrades it automatically. Returns true if an upgrade was performed. +// +// When true is returned the CURRENTLY RUNNING PROCESS still has the old version baked in. +// The caller must stop all further work that would embed version strings (e.g. lock-file +// compilation) and ask the user to re-run the command so the freshly-installed binary is +// used instead. +func upgradeExtensionIfOutdated(verbose bool) (bool, error) { + currentVersion := GetVersion() + updateExtensionCheckLog.Printf("Checking if extension needs upgrade (current: %s)", currentVersion) + + // Skip for non-release versions (dev builds) + if !workflow.IsReleasedVersion(currentVersion) { + updateExtensionCheckLog.Print("Not a released version, skipping upgrade check") + if verbose { + fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Skipping extension upgrade check (development build)")) + } + return false, nil + } + + // Query GitHub API for latest release + latestVersion, err := getLatestRelease() + if err != nil { + // Fail silently - don't block the upgrade command if we can't reach GitHub + updateExtensionCheckLog.Printf("Failed to check for latest release (silently ignoring): %v", err) + if verbose { + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Could not check for extension updates: %v", err))) + } + return false, nil + } + + if latestVersion == "" { + updateExtensionCheckLog.Print("Could not determine latest version, skipping upgrade") + return false, nil + } + + updateExtensionCheckLog.Printf("Latest version: %s", latestVersion) + + // Ensure both versions have the 'v' prefix required by the semver package. + currentSV := currentVersion + if !strings.HasPrefix(currentSV, "v") { + currentSV = "v" + currentSV + } + latestSV := latestVersion + if !strings.HasPrefix(latestSV, "v") { + latestSV = "v" + latestSV + } + + // Already on the latest (or newer) version – use proper semver comparison so + // that e.g. "0.10.0" is correctly treated as newer than "0.9.0". + if semver.IsValid(currentSV) && semver.IsValid(latestSV) { + if semver.Compare(currentSV, latestSV) >= 0 { + updateExtensionCheckLog.Print("Extension is already up to date") + if verbose { + fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("✓ gh-aw extension is up to date")) + } + return false, nil + } + } else { + // Fall back to normalised string comparison when versions are not valid semver. + currentNorm := strings.TrimPrefix(currentVersion, "v") + latestNorm := strings.TrimPrefix(latestVersion, "v") + if currentNorm >= latestNorm { + updateExtensionCheckLog.Print("Extension is already up to date (string comparison fallback)") + if verbose { + fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("✓ gh-aw extension is up to date")) + } + return false, nil + } + } + + // A newer version is available – upgrade automatically + updateExtensionCheckLog.Printf("Upgrading extension from %s to %s", currentVersion, latestVersion) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Upgrading gh-aw extension from %s to %s...", currentVersion, latestVersion))) + + cmd := exec.Command("gh", "extension", "upgrade", "github/gh-aw") + cmd.Stdout = os.Stderr + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return false, fmt.Errorf("failed to upgrade gh-aw extension: %w", err) + } + + fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("✓ gh-aw extension upgraded to "+latestVersion)) + return true, nil +} diff --git a/pkg/cli/update_extension_check_test.go b/pkg/cli/update_extension_check_test.go index 951faa95c52..69e4c350898 100644 --- a/pkg/cli/update_extension_check_test.go +++ b/pkg/cli/update_extension_check_test.go @@ -5,6 +5,7 @@ package cli import ( "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -36,3 +37,36 @@ func TestEnsureLatestExtensionVersion_SilentFailure(t *testing.T) { err := ensureLatestExtensionVersion(false) require.NoError(t, err, "Should fail silently on API errors") } + +func TestUpgradeExtensionIfOutdated_DevBuild(t *testing.T) { + // Save original version and restore after test + originalVersion := GetVersion() + defer SetVersionInfo(originalVersion) + + // Set a dev version – upgrade check must be skipped for dev builds because + // workflow.IsReleasedVersion returns false for non-release builds. + SetVersionInfo("dev") + + // Verify the function exits before making any API calls. + // If it did make API calls we'd see a network error in test environments, + // but the function must return (false, nil) immediately. + upgraded, err := upgradeExtensionIfOutdated(false) + require.NoError(t, err, "Should not return error for dev builds") + assert.False(t, upgraded, "Should not report upgrade for dev builds") +} + +func TestUpgradeExtensionIfOutdated_SilentFailureOnAPIError(t *testing.T) { + // When the GitHub API is unreachable the function must fail silently and + // must NOT report an upgrade so that the rest of the upgrade command + // continues unaffected. + + originalVersion := GetVersion() + defer SetVersionInfo(originalVersion) + + // Use a release version so the API call is attempted + SetVersionInfo("v0.1.0") + + upgraded, err := upgradeExtensionIfOutdated(false) + require.NoError(t, err, "Should fail silently on API errors") + assert.False(t, upgraded, "Should not report upgrade when API is unreachable") +} diff --git a/pkg/cli/upgrade_command.go b/pkg/cli/upgrade_command.go index 0da8be32079..2e99d6ddf1f 100644 --- a/pkg/cli/upgrade_command.go +++ b/pkg/cli/upgrade_command.go @@ -144,12 +144,22 @@ func runUpgradeCommand(verbose bool, workflowDir string, noFix bool, noCompile b upgradeLog.Printf("Running upgrade command: verbose=%v, workflowDir=%s, noFix=%v, noCompile=%v, noActions=%v", verbose, workflowDir, noFix, noCompile, noActions) - // Step 0b: Ensure gh-aw extension is on the latest version + // Step 0b: Ensure gh-aw extension is on the latest version. + // If the extension was just upgraded, stop here and ask the user to re-run so + // that the freshly-installed binary (with the correct version string) is used for + // all subsequent steps such as lock-file compilation. fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Checking gh-aw extension version...")) - if err := ensureLatestExtensionVersion(verbose); err != nil { - upgradeLog.Printf("Extension version check failed: %v", err) + upgraded, err := upgradeExtensionIfOutdated(verbose) + if err != nil { + upgradeLog.Printf("Extension upgrade failed: %v", err) return err } + if upgraded { + upgradeLog.Print("Extension was upgraded; stopping current invocation so new binary is used on re-run") + fmt.Fprintln(os.Stderr, "") + fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Please re-run 'gh aw upgrade' to complete the upgrade with the new version.")) + return nil + } // Step 1: Update dispatcher agent file (like init command) fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Updating agent file...")) From be37b31f3644477640558aab42fff3ba24a61ea7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 10 Mar 2026 02:45:10 +0000 Subject: [PATCH 3/5] fix: relaunch with same flags after extension upgrade to prevent stale version in lock files Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/cli/update_extension_check.go | 5 +- pkg/cli/upgrade_command.go | 86 ++++++++++++++++++++++++------- 2 files changed, 70 insertions(+), 21 deletions(-) diff --git a/pkg/cli/update_extension_check.go b/pkg/cli/update_extension_check.go index d787273733e..17bd80102cd 100644 --- a/pkg/cli/update_extension_check.go +++ b/pkg/cli/update_extension_check.go @@ -90,9 +90,8 @@ func ensureLatestExtensionVersion(verbose bool) error { // and, if so, upgrades it automatically. Returns true if an upgrade was performed. // // When true is returned the CURRENTLY RUNNING PROCESS still has the old version baked in. -// The caller must stop all further work that would embed version strings (e.g. lock-file -// compilation) and ask the user to re-run the command so the freshly-installed binary is -// used instead. +// The caller should re-launch the freshly-installed binary so that subsequent work +// (e.g. lock-file compilation) uses the correct new version string. func upgradeExtensionIfOutdated(verbose bool) (bool, error) { currentVersion := GetVersion() updateExtensionCheckLog.Printf("Checking if extension needs upgrade (current: %s)", currentVersion) diff --git a/pkg/cli/upgrade_command.go b/pkg/cli/upgrade_command.go index 2e99d6ddf1f..fa494a9f7f3 100644 --- a/pkg/cli/upgrade_command.go +++ b/pkg/cli/upgrade_command.go @@ -1,8 +1,11 @@ package cli import ( + "errors" "fmt" "os" + "os/exec" + "path/filepath" "github.com/github/gh-aw/pkg/console" "github.com/github/gh-aw/pkg/constants" @@ -77,6 +80,7 @@ Examples: noCompile, _ := cmd.Flags().GetBool("no-compile") auditFlag, _ := cmd.Flags().GetBool("audit") jsonOutput, _ := cmd.Flags().GetBool("json") + skipExtensionUpgrade, _ := cmd.Flags().GetBool("skip-extension-upgrade") // Handle audit mode if auditFlag { @@ -89,7 +93,7 @@ Examples: } } - if err := runUpgradeCommand(verbose, dir, noFix, noCompile, noActions); err != nil { + if err := runUpgradeCommand(verbose, dir, noFix, noCompile, noActions, skipExtensionUpgrade); err != nil { return err } @@ -112,6 +116,8 @@ Examples: cmd.Flags().Bool("pr", false, "Alias for --create-pull-request") _ = cmd.Flags().MarkHidden("pr") // Hide the short alias from help output cmd.Flags().Bool("audit", false, "Check dependency health without performing upgrades") + cmd.Flags().Bool("skip-extension-upgrade", false, "Skip automatic extension upgrade (used internally to prevent recursion after upgrade)") + _ = cmd.Flags().MarkHidden("skip-extension-upgrade") addJSONFlag(cmd) // Register completions @@ -140,25 +146,27 @@ func runDependencyAudit(verbose bool, jsonOutput bool) error { } // runUpgradeCommand executes the upgrade process -func runUpgradeCommand(verbose bool, workflowDir string, noFix bool, noCompile bool, noActions bool) error { - upgradeLog.Printf("Running upgrade command: verbose=%v, workflowDir=%s, noFix=%v, noCompile=%v, noActions=%v", - verbose, workflowDir, noFix, noCompile, noActions) +func runUpgradeCommand(verbose bool, workflowDir string, noFix bool, noCompile bool, noActions bool, skipExtensionUpgrade bool) error { + upgradeLog.Printf("Running upgrade command: verbose=%v, workflowDir=%s, noFix=%v, noCompile=%v, noActions=%v, skipExtensionUpgrade=%v", + verbose, workflowDir, noFix, noCompile, noActions, skipExtensionUpgrade) // Step 0b: Ensure gh-aw extension is on the latest version. - // If the extension was just upgraded, stop here and ask the user to re-run so - // that the freshly-installed binary (with the correct version string) is used for - // all subsequent steps such as lock-file compilation. - fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Checking gh-aw extension version...")) - upgraded, err := upgradeExtensionIfOutdated(verbose) - if err != nil { - upgradeLog.Printf("Extension upgrade failed: %v", err) - return err - } - if upgraded { - upgradeLog.Print("Extension was upgraded; stopping current invocation so new binary is used on re-run") - fmt.Fprintln(os.Stderr, "") - fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Please re-run 'gh aw upgrade' to complete the upgrade with the new version.")) - return nil + // If the extension was just upgraded, re-launch the freshly-installed binary + // with the same flags so that all subsequent steps (e.g. lock-file compilation) + // use the correct new version string. The hidden --skip-extension-upgrade flag + // prevents the re-launched process from entering this branch again. + if !skipExtensionUpgrade { + fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Checking gh-aw extension version...")) + upgraded, err := upgradeExtensionIfOutdated(verbose) + if err != nil { + upgradeLog.Printf("Extension upgrade failed: %v", err) + return err + } + if upgraded { + upgradeLog.Print("Extension was upgraded; re-launching with new binary") + fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Continuing upgrade with newly installed version...")) + return relaunchWithSameArgs("--skip-extension-upgrade") + } } // Step 1: Update dispatcher agent file (like init command) @@ -295,3 +303,45 @@ func updateAgentFiles(verbose bool) error { return nil } + +// relaunchWithSameArgs re-executes the current binary with the original command-line +// arguments plus the provided extraFlag. stdin/stdout/stderr are forwarded to the child +// process. The function blocks until the child exits and returns its error. +// It is used after a successful extension upgrade so that the freshly-installed binary +// (which carries the new version string) handles all subsequent work. +func relaunchWithSameArgs(extraFlag string) error { + exe, err := os.Executable() + if err != nil { + return fmt.Errorf("failed to determine executable path: %w", err) + } + + // Resolve symlinks to ensure we exec the real binary, not a wrapper. + if resolved, err := filepath.EvalSymlinks(exe); err == nil { + exe = resolved + } else { + upgradeLog.Printf("Failed to resolve symlink for executable %s (using as-is): %v", exe, err) + } + + // Explicitly copy os.Args[1:] so appending the extra flag does not modify + // the original slice backing array. + origArgs := os.Args[1:] + newArgs := make([]string, len(origArgs), len(origArgs)+1) + copy(newArgs, origArgs) + newArgs = append(newArgs, extraFlag) + upgradeLog.Printf("Re-launching with new binary: %s %v", exe, newArgs) + + cmd := exec.Command(exe, newArgs...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + if err := cmd.Run(); err != nil { + var exitErr *exec.ExitError + if errors.As(err, &exitErr) { + // Preserve the child's exit code so the caller sees the real failure. + os.Exit(exitErr.ExitCode()) + } + return err + } + return nil +} From 011edeaaae18b51ad78aa0f501f173a61e7f1371 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 10 Mar 2026 04:50:13 +0000 Subject: [PATCH 4/5] fix: exit parent after relaunch to prevent duplicate PR creation; remove broken string-comparison fallback Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/cli/update_extension_check.go | 14 ++++---------- pkg/cli/upgrade_command.go | 7 ++++++- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/pkg/cli/update_extension_check.go b/pkg/cli/update_extension_check.go index 17bd80102cd..9796d2c0bec 100644 --- a/pkg/cli/update_extension_check.go +++ b/pkg/cli/update_extension_check.go @@ -144,16 +144,10 @@ func upgradeExtensionIfOutdated(verbose bool) (bool, error) { return false, nil } } else { - // Fall back to normalised string comparison when versions are not valid semver. - currentNorm := strings.TrimPrefix(currentVersion, "v") - latestNorm := strings.TrimPrefix(latestVersion, "v") - if currentNorm >= latestNorm { - updateExtensionCheckLog.Print("Extension is already up to date (string comparison fallback)") - if verbose { - fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("✓ gh-aw extension is up to date")) - } - return false, nil - } + // Versions are not valid semver; skip unreliable string comparison and + // proceed with the upgrade to avoid incorrectly treating an outdated + // version as up to date (lexicographic comparison breaks for e.g. "0.9.0" vs "0.10.0"). + updateExtensionCheckLog.Printf("Non-semver versions detected (current=%q, latest=%q); proceeding with upgrade", currentVersion, latestVersion) } // A newer version is available – upgrade automatically diff --git a/pkg/cli/upgrade_command.go b/pkg/cli/upgrade_command.go index fa494a9f7f3..2ff94750422 100644 --- a/pkg/cli/upgrade_command.go +++ b/pkg/cli/upgrade_command.go @@ -165,7 +165,12 @@ func runUpgradeCommand(verbose bool, workflowDir string, noFix bool, noCompile b if upgraded { upgradeLog.Print("Extension was upgraded; re-launching with new binary") fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Continuing upgrade with newly installed version...")) - return relaunchWithSameArgs("--skip-extension-upgrade") + if err := relaunchWithSameArgs("--skip-extension-upgrade"); err != nil { + return err + } + // The child process completed all upgrade steps (including any PR creation). + // Exit the parent so we do not repeat those steps. + os.Exit(0) } } From 518c7e47de75055649755624fcfc78051b5d66a6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 10 Mar 2026 05:01:38 +0000 Subject: [PATCH 5/5] refactor: simplify version prefix normalization, arg copy, and remove dead ensureLatestExtensionVersion Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/cli/update_extension_check.go | 81 +------------------------- pkg/cli/update_extension_check_test.go | 29 --------- pkg/cli/upgrade_command.go | 5 +- 3 files changed, 3 insertions(+), 112 deletions(-) diff --git a/pkg/cli/update_extension_check.go b/pkg/cli/update_extension_check.go index 9796d2c0bec..540c8104187 100644 --- a/pkg/cli/update_extension_check.go +++ b/pkg/cli/update_extension_check.go @@ -15,77 +15,6 @@ import ( var updateExtensionCheckLog = logger.New("cli:update_extension_check") -// ensureLatestExtensionVersion checks if the current release matches the latest release -// and issues a warning if an update is needed. This function fails silently if the -// release URL is not available or blocked. -func ensureLatestExtensionVersion(verbose bool) error { - if verbose { - fmt.Fprintln(os.Stderr, console.FormatVerboseMessage("Checking for gh-aw extension updates...")) - } - - // Get current version - currentVersion := GetVersion() - updateExtensionCheckLog.Printf("Current version: %s", currentVersion) - - // Skip check for non-release versions (dev builds) - if !workflow.IsReleasedVersion(currentVersion) { - updateExtensionCheckLog.Print("Not a released version, skipping update check") - if verbose { - fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Skipping version check (development build)")) - } - return nil - } - - // Query GitHub API for latest release - latestVersion, err := getLatestRelease() - if err != nil { - // Fail silently - don't block upgrade if we can't check for updates - updateExtensionCheckLog.Printf("Failed to check for updates (silently ignoring): %v", err) - if verbose { - fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Could not check for updates: %v", err))) - } - return nil - } - - if latestVersion == "" { - updateExtensionCheckLog.Print("Could not determine latest version") - return nil - } - - updateExtensionCheckLog.Printf("Latest version: %s", latestVersion) - - // Normalize versions for comparison (remove 'v' prefix) - currentVersionNormalized := strings.TrimPrefix(currentVersion, "v") - latestVersionNormalized := strings.TrimPrefix(latestVersion, "v") - - // Compare versions - if currentVersionNormalized == latestVersionNormalized { - if verbose { - fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("✓ gh-aw extension is up to date")) - } - updateExtensionCheckLog.Print("Extension is up to date") - return nil - } - - // Check if we're on a newer version (development/prerelease) - if currentVersionNormalized > latestVersionNormalized { - updateExtensionCheckLog.Printf("Current version (%s) appears newer than latest release (%s)", currentVersion, latestVersion) - if verbose { - fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Running a development or pre-release version")) - } - return nil - } - - // A newer version is available - display warning message (not error) - updateExtensionCheckLog.Printf("Newer version available: %s (current: %s)", latestVersion, currentVersion) - fmt.Fprintln(os.Stderr, "") - fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("A newer version of gh-aw is available: %s (current: %s)", latestVersion, currentVersion))) - fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Consider upgrading with: gh extension upgrade github/gh-aw")) - fmt.Fprintln(os.Stderr, "") - - return nil -} - // upgradeExtensionIfOutdated checks if a newer version of the gh-aw extension is available // and, if so, upgrades it automatically. Returns true if an upgrade was performed. // @@ -124,14 +53,8 @@ func upgradeExtensionIfOutdated(verbose bool) (bool, error) { updateExtensionCheckLog.Printf("Latest version: %s", latestVersion) // Ensure both versions have the 'v' prefix required by the semver package. - currentSV := currentVersion - if !strings.HasPrefix(currentSV, "v") { - currentSV = "v" + currentSV - } - latestSV := latestVersion - if !strings.HasPrefix(latestSV, "v") { - latestSV = "v" + latestSV - } + currentSV := "v" + strings.TrimPrefix(currentVersion, "v") + latestSV := "v" + strings.TrimPrefix(latestVersion, "v") // Already on the latest (or newer) version – use proper semver comparison so // that e.g. "0.10.0" is correctly treated as newer than "0.9.0". diff --git a/pkg/cli/update_extension_check_test.go b/pkg/cli/update_extension_check_test.go index 69e4c350898..6c5e192518c 100644 --- a/pkg/cli/update_extension_check_test.go +++ b/pkg/cli/update_extension_check_test.go @@ -9,35 +9,6 @@ import ( "github.com/stretchr/testify/require" ) -func TestEnsureLatestExtensionVersion_DevBuild(t *testing.T) { - // Save original version and restore after test - originalVersion := GetVersion() - defer SetVersionInfo(originalVersion) - - // Set a dev version - SetVersionInfo("dev") - - // Should return nil without error for dev builds - err := ensureLatestExtensionVersion(false) - require.NoError(t, err, "Should not return error for dev builds") -} - -func TestEnsureLatestExtensionVersion_SilentFailure(t *testing.T) { - // This test verifies that network/API errors are handled silently - // The actual API call will fail in the test environment but should not return an error - - // Save original version and restore after test - originalVersion := GetVersion() - defer SetVersionInfo(originalVersion) - - // Set a valid release version - SetVersionInfo("v0.1.0") - - // Should return nil even if API call fails (fails silently) - err := ensureLatestExtensionVersion(false) - require.NoError(t, err, "Should fail silently on API errors") -} - func TestUpgradeExtensionIfOutdated_DevBuild(t *testing.T) { // Save original version and restore after test originalVersion := GetVersion() diff --git a/pkg/cli/upgrade_command.go b/pkg/cli/upgrade_command.go index 2ff94750422..54b78e9bf68 100644 --- a/pkg/cli/upgrade_command.go +++ b/pkg/cli/upgrade_command.go @@ -329,10 +329,7 @@ func relaunchWithSameArgs(extraFlag string) error { // Explicitly copy os.Args[1:] so appending the extra flag does not modify // the original slice backing array. - origArgs := os.Args[1:] - newArgs := make([]string, len(origArgs), len(origArgs)+1) - copy(newArgs, origArgs) - newArgs = append(newArgs, extraFlag) + newArgs := append(append([]string(nil), os.Args[1:]...), extraFlag) upgradeLog.Printf("Re-launching with new binary: %s %v", exe, newArgs) cmd := exec.Command(exe, newArgs...)