fix(update): show skipped status with warning indicator for dirty repo

This commit is contained in:
Benjamin Jesuiter
2026-01-11 01:06:34 +01:00
committed by Peter Steinberger
parent 6a2b8328df
commit 35d42be828
2 changed files with 76 additions and 44 deletions

View File

@@ -61,11 +61,14 @@ 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)})`);
if (step.exitCode === 0) { const icon =
currentSpinner.stop(`${theme.success("\u2713")} ${label} ${duration}`); step.status === "success"
} else { ? theme.success("\u2713")
currentSpinner.stop(`${theme.error("\u2717")} ${label} ${duration}`); : step.status === "skipped"
} ? theme.warn("\u25CB")
: theme.error("\u2717");
currentSpinner.stop(`${icon} ${label} ${duration}`);
currentSpinner = null; currentSpinner = null;
}, },
}; };

View File

@@ -37,11 +37,17 @@ export type UpdateStepInfo = {
total: number; total: number;
}; };
export type StepStatus = "success" | "error" | "skipped";
export type UpdateStepCompletion = UpdateStepInfo & {
durationMs: number;
exitCode: number | null;
status: StepStatus;
};
export type UpdateStepProgress = { export type UpdateStepProgress = {
onStepStart?: (step: UpdateStepInfo) => void; onStepStart?: (step: UpdateStepInfo) => void;
onStepComplete?: ( onStepComplete?: (step: UpdateStepCompletion) => void;
step: UpdateStepInfo & { durationMs: number; exitCode: number | null },
) => void;
}; };
type UpdateRunnerOptions = { type UpdateRunnerOptions = {
@@ -169,7 +175,11 @@ type RunStepOptions = {
totalSteps: number; totalSteps: number;
}; };
async function runStep(opts: RunStepOptions): Promise<UpdateStepResult> { type StepResultWithReport = UpdateStepResult & {
reportComplete: (status: StepStatus) => void;
};
async function runStep(opts: RunStepOptions): Promise<StepResultWithReport> {
const { const {
runCommand, runCommand,
name, name,
@@ -196,11 +206,14 @@ async function runStep(opts: RunStepOptions): Promise<UpdateStepResult> {
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;
progress?.onStepComplete?.({ const reportComplete = (status: StepStatus) => {
...stepInfo, progress?.onStepComplete?.({
durationMs, ...stepInfo,
exitCode: result.code, durationMs,
}); exitCode: result.code,
status,
});
};
return { return {
name, name,
@@ -210,6 +223,7 @@ async function runStep(opts: RunStepOptions): Promise<UpdateStepResult> {
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,
}; };
} }
@@ -305,8 +319,10 @@ export async function runGatewayUpdate(
gitRoot, gitRoot,
), ),
); );
const isDirty = (statusStep.stdoutTail ?? "").trim().length > 0;
statusStep.reportComplete(isDirty ? "skipped" : "success");
steps.push(statusStep); steps.push(statusStep);
if ((statusStep.stdoutTail ?? "").trim()) { if (isDirty) {
return { return {
status: "skipped", status: "skipped",
mode: "git", mode: "git",
@@ -333,8 +349,10 @@ export async function runGatewayUpdate(
gitRoot, gitRoot,
), ),
); );
const hasUpstream = upstreamStep.exitCode === 0;
upstreamStep.reportComplete(hasUpstream ? "success" : "skipped");
steps.push(upstreamStep); steps.push(upstreamStep);
if (upstreamStep.exitCode !== 0) { if (!hasUpstream) {
return { return {
status: "skipped", status: "skipped",
mode: "git", mode: "git",
@@ -346,15 +364,15 @@ export async function runGatewayUpdate(
}; };
} }
steps.push( const fetchStep = await runStep(
await runStep( step(
step( "git fetch",
"git fetch", ["git", "-C", gitRoot, "fetch", "--all", "--prune"],
["git", "-C", gitRoot, "fetch", "--all", "--prune"], gitRoot,
gitRoot,
),
), ),
); );
fetchStep.reportComplete(fetchStep.exitCode === 0 ? "success" : "error");
steps.push(fetchStep);
const rebaseStep = await runStep( const rebaseStep = await runStep(
step( step(
@@ -363,9 +381,9 @@ 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) {
// Abort rebase (error recovery, not counted in total)
const abortResult = await runCommand( const abortResult = await runCommand(
["git", "-C", gitRoot, "rebase", "--abort"], ["git", "-C", gitRoot, "rebase", "--abort"],
{ cwd: gitRoot, timeoutMs }, { cwd: gitRoot, timeoutMs },
@@ -391,29 +409,37 @@ export async function runGatewayUpdate(
} }
const manager = await detectPackageManager(gitRoot); const manager = await detectPackageManager(gitRoot);
steps.push(
await runStep(step("deps install", managerInstallArgs(manager), gitRoot)), const depsStep = await runStep(
step("deps install", managerInstallArgs(manager), gitRoot),
); );
steps.push( depsStep.reportComplete(depsStep.exitCode === 0 ? "success" : "error");
await runStep( steps.push(depsStep);
step("build", managerScriptArgs(manager, "build"), gitRoot),
), const buildStep = await runStep(
); step("build", managerScriptArgs(manager, "build"), gitRoot),
steps.push( );
await runStep( buildStep.reportComplete(buildStep.exitCode === 0 ? "success" : "error");
step("ui:build", managerScriptArgs(manager, "ui:build"), gitRoot), steps.push(buildStep);
),
); const uiBuildStep = await runStep(
steps.push( step("ui:build", managerScriptArgs(manager, "ui:build"), gitRoot),
await runStep( );
step( uiBuildStep.reportComplete(
"clawdbot doctor", uiBuildStep.exitCode === 0 ? "success" : "error",
managerScriptArgs(manager, "clawdbot", ["doctor"]), );
gitRoot, steps.push(uiBuildStep);
{ CLAWDBOT_UPDATE_IN_PROGRESS: "1" },
), const doctorStep = await runStep(
step(
"clawdbot doctor",
managerScriptArgs(manager, "clawdbot", ["doctor"]),
gitRoot,
{ CLAWDBOT_UPDATE_IN_PROGRESS: "1" },
), ),
); );
doctorStep.reportComplete(doctorStep.exitCode === 0 ? "success" : "error");
steps.push(doctorStep);
const failedStep = steps.find((s) => s.exitCode !== 0); const failedStep = steps.find((s) => s.exitCode !== 0);
const afterShaStep = await runStep( const afterShaStep = await runStep(
@@ -423,6 +449,9 @@ 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);