fix(release): wall-entry commits under an explicit git identity
git commit in the cache clone relied on ambient user.name/user.email, which the box has neither globally nor per-repo — every push-side test failed there with "unable to auto-detect email address" while passing on a laptop with a global identity configured. Resolve the identity from the repository the rail is actually running in (process.cwd(), the developer's own checkout release.sh invokes this from) and pass it explicitly via -c user.name/-c user.email on the commit; refuse by name if neither is set. Give the test fixtures a repo-local identity the same way seedRemote already does for the seed clone, so the suite is deterministic on any host.
This commit is contained in:
parent
1882532cb7
commit
aac853d3e8
2 changed files with 44 additions and 1 deletions
|
|
@ -337,6 +337,36 @@ function git(args, cwd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the git identity for the wall commit from the repository the rail
|
||||||
|
* is actually running in — the developer's own checkout (`process.cwd()`;
|
||||||
|
* `release.sh` invokes this script from the repo root with no `cd`), via
|
||||||
|
* git's normal config precedence (repo-local, then global, then system).
|
||||||
|
* Never guessed and never left to git's own "who are you?" prompt: a host
|
||||||
|
* with no configured identity anywhere (a bare CI box, say) must refuse
|
||||||
|
* loudly rather than have git manufacture a placeholder identity or hang.
|
||||||
|
* @returns {{name: string, email: string}}
|
||||||
|
*/
|
||||||
|
function resolveWallCommitIdentity() {
|
||||||
|
const repo = process.cwd()
|
||||||
|
let name = ''
|
||||||
|
let email = ''
|
||||||
|
try {
|
||||||
|
name = git(['config', 'user.name'], repo)
|
||||||
|
} catch {
|
||||||
|
name = ''
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
email = git(['config', 'user.email'], repo)
|
||||||
|
} catch {
|
||||||
|
email = ''
|
||||||
|
}
|
||||||
|
if (!name || !email) {
|
||||||
|
fail('no git identity for the wall commit — set user.name/user.email')
|
||||||
|
}
|
||||||
|
return { name, email }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure a clean, up-to-date local clone of the releases repo at
|
* Ensure a clean, up-to-date local clone of the releases repo at
|
||||||
* `cacheDir`, checked out on `main` — cloning fresh if `cacheDir` has no
|
* `cacheDir`, checked out on `main` — cloning fresh if `cacheDir` has no
|
||||||
|
|
@ -423,9 +453,14 @@ function publishEntry(entry, product, remote, cacheDir) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const identity = resolveWallCommitIdentity()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
git(['add', `${product}.json`], cacheDir)
|
git(['add', `${product}.json`], cacheDir)
|
||||||
git(['commit', '-m', `chore(wall): ${product} ${entry.version}`], cacheDir)
|
git(
|
||||||
|
['-c', `user.name=${identity.name}`, '-c', `user.email=${identity.email}`, 'commit', '-m', `chore(wall): ${product} ${entry.version}`],
|
||||||
|
cacheDir,
|
||||||
|
)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
fail(`cannot commit the wall entry in "${cacheDir}" — ${/** @type {Error} */ (err).message}\n cure: inspect "${cacheDir}" by hand and re-run once its git state is clean`)
|
fail(`cannot commit the wall entry in "${cacheDir}" — ${/** @type {Error} */ (err).message}\n cure: inspect "${cacheDir}" by hand and re-run once its git state is clean`)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,14 @@ let cacheDir: string
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
dir = mkdtempSync(join(tmpdir(), 'wall-entry-test-'))
|
dir = mkdtempSync(join(tmpdir(), 'wall-entry-test-'))
|
||||||
|
// wall-entry.mjs is run with this dir as its cwd, standing in for the real
|
||||||
|
// developer checkout it reads its commit identity from (process.cwd()) —
|
||||||
|
// give it a repo-local identity the same way seedRemote gives one to the
|
||||||
|
// seed clone, so the suite is deterministic on a host with no global git
|
||||||
|
// config (a bare CI box) as much as one with a developer's own.
|
||||||
|
execFileSync('git', ['init', '-q', dir])
|
||||||
|
git(['config', 'user.name', 'Wall Entry Test'], dir)
|
||||||
|
git(['config', 'user.email', 'wall-entry-test@example.com'], dir)
|
||||||
remoteDir = initBareRemote()
|
remoteDir = initBareRemote()
|
||||||
cacheDir = join(mkdtempSync(join(tmpdir(), 'wall-cache-')), 'soulcraft-releases')
|
cacheDir = join(mkdtempSync(join(tmpdir(), 'wall-cache-')), 'soulcraft-releases')
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Reference in a new issue