Landing precondition 0: no file in the commit, public/ included, may hold a merge-conflict marker
d6bf410a(a merge) committed conflict markers into 10 built files under public/ (big-picture, dashboard-plus-grid, research-map, research-dashboard, both manifests) and every precondition passed: a built bundle with markers throws on load while its SRI hash still matches. Step 0 now scans the COMMIT's tree with git grep (1.3 s, every file, whatever the working tree holds) and refuses. Run ond6bf410ait names exactly those 10 files; --markers-self-test builds a throwaway commit object holding a textbook conflict under public/ and requires the scan to refuse it (PASS).
This commit is contained in:
parent
c9b3d62111
commit
20c29442e8
1 changed files with 28 additions and 0 deletions
|
|
@ -11,6 +11,9 @@
|
|||
* Every one of those landings passed its own checks. Nothing refused them.
|
||||
*
|
||||
* PRECONDITIONS, in order (cheap first):
|
||||
* 0. NO MERGE MARKERS no file in the COMMIT (public/ included) holds a conflict marker. d6bf410a put them
|
||||
* into 10 built files under public/ and every other precondition passed; a built bundle with
|
||||
* markers throws on load while its SRI still matches. --markers-self-test proves the scan refuses.
|
||||
* 1. CLEAN the working tree equals HEAD for everything the checks read — otherwise they would judge
|
||||
* files that are not in the commit.
|
||||
* 2. ONE FOLDER public/ holds exactly the configured tree (vite.doxa-maps-build-config.json "name") and
|
||||
|
|
@ -20,6 +23,7 @@
|
|||
* 4. FRESH every composite rebuilds to exactly its committed bytes (check:composite-freshness).
|
||||
*
|
||||
* USAGE node internal/landing-preconditions.mjs exit 0 = may land · 1 = refused
|
||||
* node internal/landing-preconditions.mjs --markers-self-test proves step 0 refuses a conflict
|
||||
* DOXA_SKIP_FRESHNESS=1 skips (4) — for a DRY check only; main-capture scan never sets it.
|
||||
*/
|
||||
import { spawnSync } from 'node:child_process'
|
||||
|
|
@ -36,6 +40,30 @@ const refuse = (why, detail = '') => {
|
|||
}
|
||||
const run = (cmd, args) => spawnSync(cmd, args, { cwd: ROOT, encoding: 'utf8', env: process.env })
|
||||
|
||||
// 0. NO MERGE MARKERS — scanned in the COMMIT's tree (git grep), so public/ and every file is covered,
|
||||
// whatever the working tree holds. Markers are built from char codes so this file never contains one.
|
||||
const OPEN = String.fromCharCode(60).repeat(7), MID = String.fromCharCode(61).repeat(7), CLOSE = String.fromCharCode(62).repeat(7)
|
||||
function markerFiles(ref) {
|
||||
const g = run('git', ['grep', '-I', '-l', '-E', '-e', `^(${OPEN}( |$)|${MID}$|${CLOSE}( |$))`, ref, '--'])
|
||||
if (g.status > 1) refuse('could not scan the commit for merge markers', g.stderr.trim())
|
||||
return g.stdout.split('\n').filter(Boolean).map((l) => l.replace(new RegExp('^' + ref + ':'), ''))
|
||||
}
|
||||
if (process.argv.includes('--markers-self-test')) {
|
||||
// A throwaway commit object (no branch, no working-tree change) holding one built file with a textbook
|
||||
// conflict; the scan must name it.
|
||||
const blob = spawnSync('git', ['hash-object', '-w', '--stdin'], { cwd: ROOT, encoding: 'utf8', input: `a\n${OPEN} HEAD\nmine\n${MID}\ntheirs\n${CLOSE} other\n` }).stdout.trim()
|
||||
const tree = spawnSync('git', ['mktree'], { cwd: ROOT, encoding: 'utf8', input: `100644 blob ${blob}\tpoison.js\n` }).stdout.trim()
|
||||
const pub = spawnSync('git', ['mktree'], { cwd: ROOT, encoding: 'utf8', input: `040000 tree ${tree}\tpublic\n` }).stdout.trim()
|
||||
const commit = spawnSync('git', ['commit-tree', pub, '-m', 'marker self-test'], { cwd: ROOT, encoding: 'utf8' }).stdout.trim()
|
||||
const hits = markerFiles(commit)
|
||||
if (hits.includes('public/poison.js')) { console.log('LANDING-PRECONDITIONS: markers self-test PASS — a conflict in a public/ file is refused.'); process.exit(0) }
|
||||
console.error('LANDING-PRECONDITIONS: markers self-test FAIL — a textbook conflict under public/ was not found.'); process.exit(1)
|
||||
}
|
||||
const markers = markerFiles('HEAD')
|
||||
if (markers.length) refuse(`${markers.length} file(s) in this commit hold merge-conflict markers`,
|
||||
markers.slice(0, 10).join('\n') + '\nFor a BUILT file: take either side, REBUILD it, commit the rebuild. Never `git add -A public` mid-merge.')
|
||||
console.log('LANDING-PRECONDITIONS: 0 markers — no file in the commit holds a merge-conflict marker')
|
||||
|
||||
// 1. CLEAN
|
||||
const dirty = run('git', ['status', '--porcelain', '--', 'public', 'plugin-designs', 'library', 'internal', 'vite.config.js', 'vite.doxa-maps-build-config.json', 'package.json'])
|
||||
if (dirty.status !== 0) refuse('could not read git status')
|
||||
|
|
|
|||
Loading…
Reference in a new issue