fix(cli): skip rebuild when git install is already on latest version (#1585)

* fix(cli): skip rebuild when git install is already on latest version

After `git fetch`, compare local HEAD to remote HEAD. If they match,
print "Already on latest version." and exit without running pnpm install,
clean, build, or npm link.

Without this check, `ao update` re-ran the full rebuild on every
invocation even when nothing had changed, because the git path in
`handleGitUpdate` (unlike the npm path) never called `checkForUpdate()`
to short-circuit before delegating to the shell script.

Fixes #1584

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(cli): keep running smoke tests when already on latest version

The previous fix exited 0 immediately on the "already on latest" path,
which silently skipped smoke tests that would otherwise verify the
install. Restructure with an else-branch so the rebuild block is
skipped but execution continues to the smoke-test gate, preserving
the prior smoke-test behavior for the no-update case.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Harshit Singh Bhandari 2026-05-01 01:04:29 +05:30 committed by GitHub
parent 818f11f987
commit 64f67f3425
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 104 additions and 22 deletions

View File

@ -36,6 +36,8 @@ describe("ao-update.sh", () => {
"status --porcelain") ;;
"branch --show-current") printf 'main\\n' ;;
"fetch origin main") ;;
"rev-parse HEAD") printf 'oldsha000\\n' ;;
"rev-parse origin/main") printf 'newsha111\\n' ;;
"pull --ff-only origin main") ;;
*) ;;
esac\nexit 0`,
@ -96,6 +98,8 @@ esac\nexit 0`,
"status --porcelain") ;;
"branch --show-current") printf 'main\\n' ;;
"fetch upstream main") ;;
"rev-parse HEAD") printf 'oldsha000\\n' ;;
"rev-parse upstream/main") printf 'newsha111\\n' ;;
"pull --ff-only upstream main") ;;
*) ;;
esac\nexit 0`,
@ -232,6 +236,75 @@ exit 0`,
expect(result.stderr).toContain("commit or stash");
});
it("skips rebuild but still runs smoke tests when local HEAD matches remote HEAD", () => {
const tempRoot = mkdtempSync(join(tmpdir(), "ao-update-already-latest-"));
const fakeRepo = join(tempRoot, "repo");
mkdirSync(join(fakeRepo, "packages", "cli"), { recursive: true });
mkdirSync(join(fakeRepo, "packages", "ao", "bin"), { recursive: true });
writeFileSync(join(fakeRepo, "packages", "ao", "bin", "ao.js"), "#!/usr/bin/env node\n");
const binDir = join(tempRoot, "bin");
mkdirSync(binDir, { recursive: true });
const commandLog = join(tempRoot, "commands.log");
const sha = "abc123def456abc123def456abc123def456abc123";
createFakeBinary(
binDir,
"git",
`printf 'git %s\\n' "$*" >> ${JSON.stringify(commandLog)}
case "$*" in
"remote get-url upstream") exit 1 ;;
"rev-parse --is-inside-work-tree") printf 'true\\n' ;;
"status --porcelain") ;;
"branch --show-current") printf 'main\\n' ;;
"fetch origin main") ;;
"rev-parse HEAD") printf '${sha}\\n' ;;
"rev-parse origin/main") printf '${sha}\\n' ;;
*) ;;
esac
exit 0`,
);
createFakeBinary(
binDir,
"pnpm",
`printf 'pnpm %s\\n' "$*" >> ${JSON.stringify(commandLog)}\nif [ "$1" = "--version" ]; then\n printf '9.15.4\\n'\nfi\nexit 0`,
);
createFakeBinary(binDir, "npm", `printf 'npm %s\\n' "$*" >> ${JSON.stringify(commandLog)}\nexit 0`);
createFakeBinary(
binDir,
"node",
`printf 'node %s\\n' "$*" >> ${JSON.stringify(commandLog)}\nif [ "$1" = "--version" ]; then\n printf 'v20.11.1\\n'\nfi\nexit 0`,
);
const result = spawnSync("bash", [scriptPath], {
env: {
...process.env,
PATH: `${binDir}:${process.env.PATH || ""}`,
AO_REPO_ROOT: fakeRepo,
},
encoding: "utf8",
});
const commands = readFileSync(commandLog, "utf8");
rmSync(tempRoot, { recursive: true, force: true });
expect(result.status).toBe(0);
expect(result.stdout).toContain("Already on latest version");
// Rebuild commands should NOT have run
expect(commands).not.toContain("pnpm install");
expect(commands).not.toContain("pnpm --filter @aoagents/ao-core build");
expect(commands).not.toContain("npm link");
expect(commands).not.toContain("git pull --ff-only origin main");
// Smoke tests SHOULD still have run
expect(commands).toContain(
`node ${join(fakeRepo, "packages", "ao", "bin", "ao.js")} --version`,
);
expect(commands).toContain(
`node ${join(fakeRepo, "packages", "ao", "bin", "ao.js")} doctor --help`,
);
});
it("rejects conflicting smoke flags in the script", () => {
const result = spawnSync("bash", [scriptPath, "--skip-smoke", "--smoke-only"], {
encoding: "utf8",
@ -262,6 +335,8 @@ exit 0`,
fi
;;
"branch --show-current") printf "main\\n" ;;
"rev-parse HEAD") printf "oldsha000\\n" ;;
"rev-parse origin/main") printf "newsha111\\n" ;;
"pull --ff-only origin main") touch ${JSON.stringify(join(tempRoot, "post-dirty"))} ;;
esac
exit 0`,

View File

@ -177,32 +177,39 @@ if [ "$SMOKE_ONLY" = false ]; then
maybe_sync_origin_with_upstream
run_cmd git fetch "$UPDATE_REMOTE" "$TARGET_BRANCH"
run_cmd git pull --ff-only "$UPDATE_REMOTE" "$TARGET_BRANCH"
run_cmd pnpm install
run_cmd pnpm --filter @aoagents/ao-core clean
run_cmd pnpm --filter @aoagents/ao-cli clean
run_cmd pnpm --filter @aoagents/ao-web clean
local_sha="$(git rev-parse HEAD)"
remote_sha="$(git rev-parse "$UPDATE_REMOTE/$TARGET_BRANCH")"
if [ "$local_sha" = "$remote_sha" ]; then
printf '\nAlready on latest version.\n'
else
run_cmd git pull --ff-only "$UPDATE_REMOTE" "$TARGET_BRANCH"
run_cmd pnpm install
run_cmd pnpm --filter @aoagents/ao-core build
run_cmd pnpm --filter @aoagents/ao-cli build
run_cmd pnpm --filter @aoagents/ao-web build
run_cmd pnpm --filter @aoagents/ao-core clean
run_cmd pnpm --filter @aoagents/ao-cli clean
run_cmd pnpm --filter @aoagents/ao-web clean
printf '\nRefreshing ao launcher...\n'
(
cd "$REPO_ROOT/packages/ao"
if npm link 2>/dev/null; then
:
elif [ -t 0 ]; then
printf ' Permission denied. Retrying with sudo...\n'
sudo npm link
else
printf 'ERROR: Permission denied. Run manually: cd %s/packages/ao && sudo npm link\n' "$REPO_ROOT"
exit 1
fi
)
run_cmd pnpm --filter @aoagents/ao-core build
run_cmd pnpm --filter @aoagents/ao-cli build
run_cmd pnpm --filter @aoagents/ao-web build
ensure_repo_clean "Update modified tracked files. Inspect git status, review the changes, and rerun after restoring a clean checkout if needed."
printf '\nRefreshing ao launcher...\n'
(
cd "$REPO_ROOT/packages/ao"
if npm link 2>/dev/null; then
:
elif [ -t 0 ]; then
printf ' Permission denied. Retrying with sudo...\n'
sudo npm link
else
printf 'ERROR: Permission denied. Run manually: cd %s/packages/ao && sudo npm link\n' "$REPO_ROOT"
exit 1
fi
)
ensure_repo_clean "Update modified tracked files. Inspect git status, review the changes, and rerun after restoring a clean checkout if needed."
fi
fi
if [ "$SKIP_SMOKE" = false ]; then