v1.94.3.0 fix(ship-preflight): stop when origin's default branch can't be read (#3718 follow-up) (#3913)

* fix(ship-preflight): stop when ls-remote origin HEAD fails instead of guessing the default branch

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix(ship-preflight): a remote HEAD with no branch falls back to the default-base order; docs name the whole order

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* changelog: say when the default-base order still reads the local origin/HEAD

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
Garry Tanandcapy-ai[bot] authored and GitHub committed 2026-11-03 04:31:44 +00:00
1 parent 7d475a4ea4
commit ad51cef58a
8 files changed
+69 -8

No files matched your search

+6 -3
View File
@@ -8,6 +8,7 @@
import * as fs from 'node:fs';
import * as os from 'node:os';
import * as path from 'node:path';
import { defaultBaseBranch } from './default-base';
import { classifyDiff } from './review-depth';
import { audit } from './ship-audit';
import { bin, carryNoneLine, firstLine, flagReader, gh, git, hostedOrigin, laneConcurrency, laneLine, lanes, Report, runLanes, shipPolicy, short } from './ship-bin-common';
@@ -33,14 +34,16 @@ const DIST = /(^|\/)(cmd\/[^/]+\/main\.go|bin\/[^/]+|Cargo\.toml|setup\.py|packa
function integrate(cwd: string, base: string, r: Report): boolean {
const branch = git(cwd, ['branch', '--show-current']).stdout.trim();
const remote = /^ref: refs\/heads\/(\S+)\s+HEAD$/m.exec(git(cwd, ['ls-remote', '--symref', 'origin', 'HEAD'], 60_000).stdout)?.[1];
const head = remote ?? git(cwd, ['symbolic-ref', '--short', 'refs/remotes/origin/HEAD']).stdout.trim().replace(/^origin\//, '');
r.add(`BRANCH: ${branch || '(detached)'} base=${base}`);
if (!branch || branch === base || branch === head) { r.stop(`on the base branch (${branch || 'detached HEAD'}): ship from a feature branch`); return false; }
if (!branch || branch === base) { r.stop(`on the base branch (${branch || 'detached HEAD'}): ship from a feature branch`); return false; }
const status = git(cwd, ['status', '--porcelain']).stdout.split('\n').filter(Boolean);
r.add(`STATUS: modified=${status.filter(l => !l.startsWith('??')).length} untracked=${status.filter(l => l.startsWith('??')).length} (uncommitted changes ship with this run)`);
const fetch = git(cwd, ['fetch', 'origin', `+refs/heads/${base}:refs/remotes/origin/${base}`], 300_000);
if (fetch.status !== 0) { r.stop(`git fetch origin ${base} failed: ${firstLine(fetch.stderr)}; restore access first`); return false; }
const remoteHead = git(cwd, ['ls-remote', '--symref', 'origin', 'HEAD'], 60_000);
if (remoteHead.status !== 0) { r.stop(`git ls-remote origin HEAD failed: ${firstLine(remoteHead.stderr)}; restore access first`); return false; }
const head = /^ref: refs\/heads\/(\S+)\s+HEAD$/m.exec(remoteHead.stdout)?.[1] ?? defaultBaseBranch(cwd).branch;
if (branch === head) { r.stop(`on the base branch (${branch}): ship from a feature branch`); return false; }
const stat = git(cwd, ['diff', forkPoint(cwd, base), '--shortstat']).stdout.trim();
const lines = [...stat.matchAll(/(\d+) (insertion|deletion)/g)].reduce((n, m) => n + Number(m[1]), 0);
const commits = git(cwd, ['rev-list', '--count', `origin/${base}..HEAD`]).stdout.trim();