-
Notifications
You must be signed in to change notification settings - Fork 311
Description
Problem
When running gh aw upgrade to update the CLI extension (e.g., from v0.56.0 to v0.57.0), the lock files generated by the upgrade (or subsequent compile) continue to reference the previous (old) CLI version in metadata and workflow headers (e.g., v0.56.0) even though the CLI itself was upgraded to v0.57.0 during this operation.
This results in .lock.yml files and generated YAML referencing the wrong (stale) version, causing confusion and potential future automation or compatibility issues.
Root Cause Analysis
- The upgrade process is performed by a single running
gh-awprocess. gh aw upgrade(andcompile, etc.) propagates the version number from Go build-time linker flags and from variables initialized at the start of process execution.- When the command runs, it first checks for upgrades/advises to upgrade, but even after the user upgrades the CLI extension, the currently running process is still the old binary until the next execution.
- Compilation/lockfile-rebuild is therefore performed by the old binary with the old version string baked in.
- There is no re-execution or post-upgrade detection that would cause the new version to be used for lock file regeneration.
Direct Code References
1. The build-time version is only set at process start:
// Build-time variables set by GoReleaser
var (
version = "dev"
isRelease = "false" // Set to "true" during release builds
)2. The main() entrypoint populates global version variables ONCE:
func main() {
// Set version information in the CLI package
cli.SetVersionInfo(version)
// Set version information in the workflow package for generated file headers
workflow.SetVersion(version)
// Set release flag in the workflow package
workflow.SetIsRelease(isRelease == "true")
...
}3. The upgrade command only prints a warning, doesn't switch process:
// Step 0b: Ensure gh-aw extension is on the latest version
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)
return err
}
// -- ensureLatestExtensionVersion only prints:
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"))4. The compiler is created with the stale version:
compiler := createAndConfigureCompiler(CompileConfig{
Verbose: verbose,
WorkflowDir: workflowDir,
})
// ...
func NewCompiler(opts ...CompilerOption) *Compiler {
// Get default version
version := defaultVersion
...
c := &Compiler{
...
version: version,5. The old version is written to lock file headers and metadata:
if IsReleasedVersion(c.version) {
fmt.Fprintf(yaml, " GH_AW_INFO_CLI_VERSION: \"%s\"\n", c.version)
}
// And in comments:
if IsReleasedVersion(GetVersion()) {
fmt.Fprintf(&header, "# This file was automatically generated by %s (%s). DO NOT EDIT.\n", generatedBy, GetVersion())
}Steps to Reproduce
- Install
gh-awv0.56.0. - Run
gh aw upgrade(or use the automatic PR/CI upgrade workflow). - Lock files generated after the upgrade still reference v0.56.0, even if
gh aw versionnow reports v0.57.0 in a new terminal.
Expected Behavior
- After upgrading to a new
gh-awversion, any lock files (and other files with metadata) generated as part of that upgrade should reference the new version, not the previous one.
Actual Behavior
- The files are generated with the version string corresponding to the binary that started the upgrade, not the current version after upgrade.
Root Cause Summary
The Go binary loads the version string once at process startup via linker flags. gh aw upgrade does not re-exec itself after extension upgrade, so all regeneration in that invocation uses the old version. The new version is picked up only in subsequent invocations of the CLI. There are also two version variables (compilerVersion, defaultVersion) in play which are not always synchronized.
Remediation Plan
- Refactor the
gh aw upgrade(and related) workflows so that after a successful extension upgrade, the process re-executes itself to continue further operations (regeneration, lock files etc.) under the correct binary.- Consider a pattern where, upon detecting and completing a successful extension update, the
gh awprocess either stops with a clear message ("upgrade complete, please re-run the command") or, if possible, auto-spawns the new binary and continues.
- Consider a pattern where, upon detecting and completing a successful extension update, the
- Ensure that both
compilerVersionanddefaultVersionare kept in sync. - Consider adding smoke-tests or post-upgrade checks to validate the version in lock files matches the current CLI version used.
- Document in upgrade and contributing docs that lockfile regeneration with the new version only occurs after fresh process invocation.
Context
- Observed in v0.56.0→v0.57.0 but likely affects all versions.
- See CONTRIBUTING.md
Root Cause supplied below (for best-practice agentic debugging):
The bug is that
gh aw upgradeperforms lock file compilation inside the same process that started with the old binary's baked-in version, and nothing in the upgrade flow updatesworkflow.compilerVersion(orworkflow.defaultVersion) to reflect the new version. The extension binary on disk may be v0.57.0 aftergh extension upgraderuns, but the currently executing Go process has no mechanism to discover or apply that new version string to subsequent compilation steps.