refactor(update): simplify progress with proper exit codes

This commit is contained in:
Benjamin Jesuiter
2026-01-11 01:14:59 +01:00
committed by Peter Steinberger
parent 35d42be828
commit 4102e2f1b8
2 changed files with 16 additions and 47 deletions

View File

@@ -19,8 +19,8 @@ export type UpdateCommandOptions = {
}; };
const STEP_LABELS: Record<string, string> = { const STEP_LABELS: Record<string, string> = {
"git status": "Checking for uncommitted changes", "clean check": "Working directory is clean",
"git upstream": "Checking upstream branch", "upstream check": "Upstream branch exists",
"git fetch": "Fetching latest changes", "git fetch": "Fetching latest changes",
"git rebase": "Rebasing onto upstream", "git rebase": "Rebasing onto upstream",
"deps install": "Installing dependencies", "deps install": "Installing dependencies",
@@ -60,13 +60,8 @@ function createUpdateProgress(enabled: boolean): ProgressController {
const label = getStepLabel(step); const label = getStepLabel(step);
const duration = theme.muted(`(${formatDuration(step.durationMs)})`); const duration = theme.muted(`(${formatDuration(step.durationMs)})`);
const icon = const icon =
step.status === "success" step.exitCode === 0 ? theme.success("\u2713") : theme.error("\u2717");
? theme.success("\u2713")
: step.status === "skipped"
? theme.warn("\u25CB")
: theme.error("\u2717");
currentSpinner.stop(`${icon} ${label} ${duration}`); currentSpinner.stop(`${icon} ${label} ${duration}`);
currentSpinner = null; currentSpinner = null;

View File

@@ -37,12 +37,9 @@ export type UpdateStepInfo = {
total: number; total: number;
}; };
export type StepStatus = "success" | "error" | "skipped";
export type UpdateStepCompletion = UpdateStepInfo & { export type UpdateStepCompletion = UpdateStepInfo & {
durationMs: number; durationMs: number;
exitCode: number | null; exitCode: number | null;
status: StepStatus;
}; };
export type UpdateStepProgress = { export type UpdateStepProgress = {
@@ -175,11 +172,7 @@ type RunStepOptions = {
totalSteps: number; totalSteps: number;
}; };
type StepResultWithReport = UpdateStepResult & { async function runStep(opts: RunStepOptions): Promise<UpdateStepResult> {
reportComplete: (status: StepStatus) => void;
};
async function runStep(opts: RunStepOptions): Promise<StepResultWithReport> {
const { const {
runCommand, runCommand,
name, name,
@@ -206,14 +199,11 @@ async function runStep(opts: RunStepOptions): Promise<StepResultWithReport> {
const result = await runCommand(argv, { cwd, timeoutMs, env }); const result = await runCommand(argv, { cwd, timeoutMs, env });
const durationMs = Date.now() - started; const durationMs = Date.now() - started;
const reportComplete = (status: StepStatus) => { progress?.onStepComplete?.({
progress?.onStepComplete?.({ ...stepInfo,
...stepInfo, durationMs,
durationMs, exitCode: result.code,
exitCode: result.code, });
status,
});
};
return { return {
name, name,
@@ -223,7 +213,6 @@ async function runStep(opts: RunStepOptions): Promise<StepResultWithReport> {
exitCode: result.code, exitCode: result.code,
stdoutTail: trimLogTail(result.stdout, MAX_LOG_CHARS), stdoutTail: trimLogTail(result.stdout, MAX_LOG_CHARS),
stderrTail: trimLogTail(result.stderr, MAX_LOG_CHARS), stderrTail: trimLogTail(result.stderr, MAX_LOG_CHARS),
reportComplete,
}; };
} }
@@ -312,17 +301,15 @@ export async function runGatewayUpdate(
const beforeSha = beforeShaResult.stdout.trim() || null; const beforeSha = beforeShaResult.stdout.trim() || null;
const beforeVersion = await readPackageVersion(gitRoot); const beforeVersion = await readPackageVersion(gitRoot);
const statusStep = await runStep( const cleanCheck = await runStep(
step( step(
"git status", "clean check",
["git", "-C", gitRoot, "status", "--porcelain"], ["sh", "-c", `test -z "$(git -C '${gitRoot}' status --porcelain)"`],
gitRoot, gitRoot,
), ),
); );
const isDirty = (statusStep.stdoutTail ?? "").trim().length > 0; steps.push(cleanCheck);
statusStep.reportComplete(isDirty ? "skipped" : "success"); if (cleanCheck.exitCode !== 0) {
steps.push(statusStep);
if (isDirty) {
return { return {
status: "skipped", status: "skipped",
mode: "git", mode: "git",
@@ -336,7 +323,7 @@ export async function runGatewayUpdate(
const upstreamStep = await runStep( const upstreamStep = await runStep(
step( step(
"git upstream", "upstream check",
[ [
"git", "git",
"-C", "-C",
@@ -349,10 +336,8 @@ export async function runGatewayUpdate(
gitRoot, gitRoot,
), ),
); );
const hasUpstream = upstreamStep.exitCode === 0;
upstreamStep.reportComplete(hasUpstream ? "success" : "skipped");
steps.push(upstreamStep); steps.push(upstreamStep);
if (!hasUpstream) { if (upstreamStep.exitCode !== 0) {
return { return {
status: "skipped", status: "skipped",
mode: "git", mode: "git",
@@ -371,7 +356,6 @@ export async function runGatewayUpdate(
gitRoot, gitRoot,
), ),
); );
fetchStep.reportComplete(fetchStep.exitCode === 0 ? "success" : "error");
steps.push(fetchStep); steps.push(fetchStep);
const rebaseStep = await runStep( const rebaseStep = await runStep(
@@ -381,7 +365,6 @@ export async function runGatewayUpdate(
gitRoot, gitRoot,
), ),
); );
rebaseStep.reportComplete(rebaseStep.exitCode === 0 ? "success" : "error");
steps.push(rebaseStep); steps.push(rebaseStep);
if (rebaseStep.exitCode !== 0) { if (rebaseStep.exitCode !== 0) {
const abortResult = await runCommand( const abortResult = await runCommand(
@@ -413,21 +396,16 @@ export async function runGatewayUpdate(
const depsStep = await runStep( const depsStep = await runStep(
step("deps install", managerInstallArgs(manager), gitRoot), step("deps install", managerInstallArgs(manager), gitRoot),
); );
depsStep.reportComplete(depsStep.exitCode === 0 ? "success" : "error");
steps.push(depsStep); steps.push(depsStep);
const buildStep = await runStep( const buildStep = await runStep(
step("build", managerScriptArgs(manager, "build"), gitRoot), step("build", managerScriptArgs(manager, "build"), gitRoot),
); );
buildStep.reportComplete(buildStep.exitCode === 0 ? "success" : "error");
steps.push(buildStep); steps.push(buildStep);
const uiBuildStep = await runStep( const uiBuildStep = await runStep(
step("ui:build", managerScriptArgs(manager, "ui:build"), gitRoot), step("ui:build", managerScriptArgs(manager, "ui:build"), gitRoot),
); );
uiBuildStep.reportComplete(
uiBuildStep.exitCode === 0 ? "success" : "error",
);
steps.push(uiBuildStep); steps.push(uiBuildStep);
const doctorStep = await runStep( const doctorStep = await runStep(
@@ -438,7 +416,6 @@ export async function runGatewayUpdate(
{ CLAWDBOT_UPDATE_IN_PROGRESS: "1" }, { CLAWDBOT_UPDATE_IN_PROGRESS: "1" },
), ),
); );
doctorStep.reportComplete(doctorStep.exitCode === 0 ? "success" : "error");
steps.push(doctorStep); steps.push(doctorStep);
const failedStep = steps.find((s) => s.exitCode !== 0); const failedStep = steps.find((s) => s.exitCode !== 0);
@@ -449,9 +426,6 @@ export async function runGatewayUpdate(
gitRoot, gitRoot,
), ),
); );
afterShaStep.reportComplete(
afterShaStep.exitCode === 0 ? "success" : "error",
);
steps.push(afterShaStep); steps.push(afterShaStep);
const afterVersion = await readPackageVersion(gitRoot); const afterVersion = await readPackageVersion(gitRoot);