refactor: simplify pass (trekexecute)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
f6bdc2de59
commit
af90e82794
12 changed files with 303 additions and 186 deletions
|
|
@ -25,10 +25,10 @@
|
|||
// shell; a git call that fails is a stale review (fails closed), never ok.
|
||||
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { MARK_START, MARK_END, withPointer } from './recurrence.mjs';
|
||||
import { LESSONS_FILE_NAME, MARK_START, MARK_END, withPointer } from './recurrence.mjs';
|
||||
|
||||
const SHA_RE = /^[0-9a-f]{7,40}$/i;
|
||||
const LESSONS_REL = '.claude/rules/voyage-review-lessons.md';
|
||||
const LESSONS_REL = `.claude/rules/${LESSONS_FILE_NAME}`; // posix, as `git diff` prints it
|
||||
const CLAUDE_REL = 'CLAUDE.md';
|
||||
const SYMLINK_MODE = '120000';
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ export function reviewedSha(reviewText) {
|
|||
const m = fm && /^scope_sha_end:[ \t]*(["']?)([^"'\s#]*)\1[ \t]*(?:#.*)?$/m.exec(fm[1]);
|
||||
// A commit sha only: a ref name (HEAD, main, a tag) resolves to whatever it
|
||||
// points at now, and coverage would pass whatever was reviewed (round 4).
|
||||
return m && /^[0-9a-f]{7,40}$/i.test(m[2]) ? m[2] : '';
|
||||
return m && SHA_RE.test(m[2]) ? m[2] : '';
|
||||
}
|
||||
|
||||
function git(repo, args) {
|
||||
|
|
@ -53,10 +53,14 @@ function stale(reason) {
|
|||
return { ok: false, reason: `review-stale: ${reason}` };
|
||||
}
|
||||
|
||||
/** What a git call said: its spawn error, else the first line of its stderr. */
|
||||
function gitNote(r) {
|
||||
return r.error?.message ?? String(r.stderr ?? '').trim().split('\n')[0];
|
||||
}
|
||||
|
||||
/** A failed git call as a stale reason: fails closed. */
|
||||
function gitFailed(what, r) {
|
||||
const note = (r.error?.message ?? String(r.stderr ?? '').trim().split('\n')[0]) || `exit ${r.status}`;
|
||||
return stale(`git ${what} failed (${note})`);
|
||||
return stale(`git ${what} failed (${gitNote(r) || `exit ${r.status}`})`);
|
||||
}
|
||||
|
||||
const short = (c) => c.slice(0, 12);
|
||||
|
|
@ -74,18 +78,18 @@ function outsideBlock(text) {
|
|||
}
|
||||
|
||||
/**
|
||||
* One file in one tree: `{ ok, absent, mode, text }`; absent reads as ''.
|
||||
* One file in one tree: `{ ok, mode, text }`; absent reads as mode null, text ''.
|
||||
* `--full-tree`: the path is from the repo root, as `git diff` prints it.
|
||||
*/
|
||||
function blobAt(repo, rev, path) {
|
||||
const ls = git(repo, ['ls-tree', '--full-tree', '-z', rev, '--', path]);
|
||||
if (ls.status !== 0) return { ok: false, fail: gitFailed(`ls-tree ${rev}`, ls) };
|
||||
const entry = ls.stdout.split('\0').find(Boolean);
|
||||
if (!entry) return { ok: true, absent: true, mode: null, text: '' };
|
||||
if (!entry) return { ok: true, mode: null, text: '' };
|
||||
const mode = entry.split(' ')[0];
|
||||
const blob = git(repo, ['cat-file', 'blob', `${rev}:${path}`]);
|
||||
if (blob.status !== 0) return { ok: false, fail: gitFailed(`cat-file ${rev}:${path}`, blob) };
|
||||
return { ok: true, absent: false, mode, text: blob.stdout };
|
||||
return { ok: true, mode, text: blob.stdout };
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -101,7 +105,7 @@ export function checkReviewedCommit({ repo, sha } = {}) {
|
|||
if (!SHA_RE.test(given)) return stale(notCommit);
|
||||
const resolved = git(repo, ['rev-parse', '--verify', '--quiet', `${given}^{commit}`]);
|
||||
if (resolved.status !== 0) {
|
||||
const note = (resolved.error?.message ?? String(resolved.stderr ?? '').trim().split('\n')[0]);
|
||||
const note = gitNote(resolved);
|
||||
return stale(note ? `${notCommit} (${note})` : notCommit);
|
||||
}
|
||||
const full = resolved.stdout.trim();
|
||||
|
|
@ -123,14 +127,14 @@ export function checkReviewedCommit({ repo, sha } = {}) {
|
|||
const lessons = `${prefix}${LESSONS_REL}`;
|
||||
const claude = `${prefix}${CLAUDE_REL}`;
|
||||
|
||||
const roots = git(repo, ['rev-list', '--max-parents=0', `${full}..HEAD`]);
|
||||
if (roots.status !== 0) return gitFailed('rev-list --max-parents=0', roots);
|
||||
const root = roots.stdout.split('\n').find(Boolean);
|
||||
if (root) return stale(`commit ${short(root)} has no parent`);
|
||||
// One line per commit, `<commit> <parent>...`; a line with one field is a root.
|
||||
const list = git(repo, ['rev-list', '--parents', `${full}..HEAD`]);
|
||||
if (list.status !== 0) return gitFailed('rev-list --parents', list);
|
||||
const lines = list.stdout.split('\n').filter(Boolean).map((l) => l.split(' '));
|
||||
const root = lines.find((f) => f.length === 1);
|
||||
if (root) return stale(`commit ${short(root[0])} has no parent`);
|
||||
|
||||
const list = git(repo, ['rev-list', `${full}..HEAD`]);
|
||||
if (list.status !== 0) return gitFailed('rev-list', list);
|
||||
for (const c of list.stdout.split('\n').filter(Boolean)) {
|
||||
for (const [c] of lines) {
|
||||
// `--no-relative` and `--ignore-submodules=none`: neither `diff.relative`
|
||||
// nor an `ignore =` setting (config or .gitmodules) may hide a changed path.
|
||||
const names = git(repo, ['diff', '--no-relative', '--ignore-submodules=none', '--name-only', '-z', '--no-renames', `${c}^1`, c]);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue