feat: add repository git credential fixer
This commit is contained in:
1 parent
25cea75eb5
commit
c6e042db86
7 files changed
+120
-10
No files matched your search
@@ -297,9 +297,13 @@ export async function listRepos(account, { query, owner, max = 300, signal } = {
|
||||
|
||||
// ---- git operations ---------------------------------------------------------
|
||||
|
||||
export function credentialHelperCmd() {
|
||||
return `!'${process.execPath.replace(/'/g, "'\\''")}' '${HELPER_PATH.replace(/'/g, "'\\''")}'`
|
||||
}
|
||||
|
||||
/** git -c options that make git ask our helper for credentials of known accounts. */
|
||||
export function credentialArgs() {
|
||||
const helper = `!'${process.execPath.replace(/'/g, "'\\''")}' '${HELPER_PATH.replace(/'/g, "'\\''")}'`
|
||||
const helper = credentialHelperCmd()
|
||||
return ['-c', 'credential.helper=', '-c', `credential.helper=${helper}`]
|
||||
}
|
||||
|
||||
@@ -347,8 +351,7 @@ export async function cloneRepo({ url, parent, name, branch, depth, signal }) {
|
||||
}
|
||||
// Keep the repo's own pushes/fetches authenticated through the helper.
|
||||
if (account) {
|
||||
await run('git', ['-C', target, 'config', '--local', '--add', 'credential.helper', ''])
|
||||
await run('git', ['-C', target, 'config', '--local', '--add', 'credential.helper', credentialArgs()[3].slice('credential.helper='.length)])
|
||||
await fixRepoConfig(target)
|
||||
}
|
||||
return { path: target, url: effective, account: account ? account.id : null }
|
||||
}
|
||||
@@ -421,3 +424,43 @@ export async function resolveRepo({ repo, account: accountId, cwd, remote = 'ori
|
||||
if (!account) throw new ForgeError(`no authorized account for host ${parsed.host}; available: ${accounts.map((a) => `${a.id} (${a.host})`).join(', ')}`, 400)
|
||||
return { account, owner: parsed.owner, name: parsed.name }
|
||||
}
|
||||
|
||||
/** Configure or update a local repository to use the git-forge credential helper. */
|
||||
export async function fixRepoConfig(repoPath) {
|
||||
const top = await gitIn(repoPath, ['rev-parse', '--show-toplevel'])
|
||||
if (top.code !== 0) throw new ForgeError(`not a git repository: ${repoPath}`, 400)
|
||||
const root = top.stdout.trim()
|
||||
|
||||
const values = (result) => {
|
||||
if (!result || result.code !== 0 || result.stdout === '') return []
|
||||
const text = String(result.stdout)
|
||||
return (text.endsWith('\n') ? text.slice(0, -1) : text).split('\n')
|
||||
}
|
||||
const existing = await gitIn(root, ['config', '--local', '--get-all', 'credential.helper'])
|
||||
const previous = values(existing)
|
||||
const cmd = credentialHelperCmd()
|
||||
|
||||
const unset = await gitIn(root, ['config', '--local', '--unset-all', 'credential.helper'])
|
||||
// git config exits with 5 when there was no value to unset; that is expected.
|
||||
if (unset.code !== 0 && unset.code !== 5) {
|
||||
throw new ForgeError(`could not update local git credentials in ${root}: ${unset.stderr || 'failed to clear credential.helper'}`, 422)
|
||||
}
|
||||
const reset = await gitIn(root, ['config', '--local', '--add', 'credential.helper', ''])
|
||||
if (reset.code !== 0) {
|
||||
throw new ForgeError(`could not update local git credentials in ${root}: ${reset.stderr || 'failed to reset credential.helper'}`, 422)
|
||||
}
|
||||
const add = await gitIn(root, ['config', '--local', '--add', 'credential.helper', cmd])
|
||||
if (add.code !== 0) {
|
||||
throw new ForgeError(`could not update local git credentials in ${root}: ${add.stderr || 'failed to install credential.helper'}`, 422)
|
||||
}
|
||||
|
||||
const check = await gitIn(root, ['config', '--local', '--get-all', 'credential.helper'])
|
||||
if (check.code !== 0) throw new ForgeError(`could not verify local git credentials in ${root}`, 422)
|
||||
return {
|
||||
path: root,
|
||||
fixed: true,
|
||||
helper: cmd,
|
||||
previous,
|
||||
current: values(check),
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user