Wire "nothing to ship" skip into runMrStage #255
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Make
runMrStage(src/mr/services/runMrStage.ts) detect "nothing to ship" and short-circuit into a skipped result — writingmr-skipped.jsonand never committing, pushing, or creating an MR/PR — instead of always proceeding to MR creation.Background
Depends on: Add git-native "nothing to ship" helper
Depends on: Add mr-skipped.json artifact type + validator
runMrStagecurrently always runs its git orchestration (ensureBranchCheckedOut→ensureCommitted→ensurePushed) and then creates an MR/PR via REST, even when the combined implement + remediate + docs changes produced no net diff.ensureCommittedalready has a defensive empty-check that skips just thegit commitcall, but the branch is still pushed and an MR is still opened.This step generalizes that check into a full stage-level skip, using the
hasNothingToShiphelper (from the git-helper step) at the right point in the git orchestration — before any push or MR/PR creation happens, so no empty/pointless branch is ever pushed to origin and no empty MR is ever opened.Per the design record for this feature (see this repo's
docs/adr/017-mr-skip-when-no-changes.mdanddocs/implementation-plan-mr-skip.mdfor the full rationale): the local branch is not deleted on skip — it stays checked out locally (harmless, since nothing was pushed), which keeps resume simple (a later resume attempt finds the branch already there rather than needing to recreate it).Implementation Details
src/mr/types/mr.ts— changeRunMrStageResultfrom its current single-shape interface to a discriminated union: This is a breaking change to the exported type — every caller/test that currently destructures{ resultPath, result, degraded }directly offRunMrStageResultneeds updating to narrow onskippedfirst (see the follow-up "Wire MR-skip outcome into runPipeline" step for therunPipelinecaller-side change; this step should also update any existing tests inrunMrStage.test.tsthat construct/consume the old shape).src/mr/services/runMrStage.ts:resolveMrResult's git-orchestration call site (currentlyawait runGitCommands({...})followed unconditionally bycreateMr), afterensureBranchCheckedOutruns (the branch must exist locally to checkhasCommitsOnBranchagainst a real branch name) and beforeensureCommitted/ensurePushed/MR creation, call thehasNothingToShiphelper with the resolvedsourceBranchandtargetBranch.hasNothingToShipreturnstrue:ensureCommitted,ensurePushed, orcreateMr/auto-merge at all.MrSkippedArtifact({ reason: 'no-changes', jiraKey: context.key, checkedAt: now() }) and write it viawriteMrSkippedSignal(runDir, artifact).{ skipped: true, reason: 'no-changes', resultPath }fromrunMrStage(whereresultPathis whatwriteMrSkippedSignalreturned).hasNothingToShipreturnsfalse: proceed with the existing flow completely unchanged (ensureCommitted→ensurePushed→createMr→ optional auto-merge →writeMrResult), but wrap the final return in{ skipped: false, resultPath, result, degraded: false }instead of today's bare{ resultPath, result, degraded: false }.runMrStage's top-level function body and/orresolveMrResult's signature slightly to thread the skip check in betweenensureBranchCheckedOutand the rest ofrunGitCommands— consider splittingrunGitCommandsso the branch-checkout step is separated from commit/push, or inlining the check directly. Keep the change as small and readable as possible; do not restructure unrelated parts of the file.git branch -Dor branch-deletion call on the skip path.Acceptance Criteria
hasNothingToShip),runMrStagenever callscommit,push, or the MR-client'screateMr.runMrStagereturns{ skipped: true, reason: 'no-changes', resultPath }andmr-skipped.jsonis written atresultPathwith the expected shape (reason,jiraKey,checkedAt).runMrStagebehaves exactly as before (commit/push/create MR unchanged) and returns{ skipped: false, resultPath, result, degraded: false }.hasCommitsOnBranchistrue(prior stage commits exist from stages 1/3/4) but the working tree is clean does not trigger a skip — there IS something to ship (it's already committed), so the normal push/MR-creation path runs.runMrStagetests are updated to the new discriminated-union shape and pass; new skip-path tests pass.npm run buildandnpm run lintpass with no new errors/warnings.Test Plan
Extend
src/mr/services/runMrStage.test.ts(or wherever the existing suite lives):commit,push, and the MR-client'screateMrare never invoked; assert the returned result is{ skipped: true, reason: 'no-changes', resultPath }; assertmr-skipped.jsonwas written with the expected fields.skipped: falseon the result and thatresult/resultPath/degradedare present and correct (no behavior change otherwise — same commit/push/create-MR calls as before).hasCommitsOnBranchreturnstrue, working tree is clean → confirm the skip does not trigger, and the branch proceeds to push + MR creation as normal.Run
npm test -- runMrStageto confirm the updated/new suite passes, thennpm testfor the full suite (this is a breaking type change toRunMrStageResult, so expect and fix compile errors in any other file that destructures the old shape).pi-loop opened and merged a pull request for this issue: #262