Files
tea-sdlc/test/helpers/temp-repo.js
T
jiantw83andClaude Opus 5 e1897f2d33 test(helpers): 加上「有遠端」的臨時 repo,並收掉三份重複的 git 執行器
branch-prep 的重點行為都繞著遠端打轉——來源分支在遠端已存在時要 pull 而不是重建、
目標分支已存在時不能覆蓋他人進度。這些事沒有遠端就驗不出來,所以補一個 bare origin
加工作用 clone,並附 pushFromElsewhere 模擬「別人推了東西上去」。

順手把 makeTempRepo 與新 helper 各自重寫一次的 git 執行器與 seed 收成共用的兩支。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 07:07:01 +00:00

90 lines
3.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 在 .tmp/ 底下開一個真的 git repo。
* git 操作不做 mock:在臨時 repo 上跑真的 git 比假的 git 可信,成本也低。
*/
import { execFileSync } from 'node:child_process';
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
import { join } from 'node:path';
import { tmpRoot } from './run-script.js';
/**
* @returns {{dir: string, cleanup: Function}} dir 為已有一顆 commit 的 git repo
*/
export function makeTempRepo() {
mkdirSync(tmpRoot, { recursive: true });
const dir = mkdtempSync(join(tmpRoot, 'repo-'));
const git = gitIn(dir);
git('init', '-q', '-b', 'master');
seed(git, dir, 'tester', 'tester@example.com');
return { dir, cleanup: () => rmSync(dir, { recursive: true, force: true }) };
}
/**
* 綁在某個目錄上的 git 執行器。
* 全域與系統設定一律切掉:測試的結果不該隨開發者機器上的 git 設定而變。
*/
function gitIn(cwd) {
return (...args) =>
execFileSync('git', args, {
cwd,
encoding: 'utf8',
env: { ...process.env, GIT_CONFIG_GLOBAL: '/dev/null', GIT_CONFIG_SYSTEM: '/dev/null' },
}).trim();
}
/** 設好身分並放一顆起始 commit,讓 repo 有東西可以長分支 */
function seed(git, dir, name, email) {
git('config', 'user.name', name);
git('config', 'user.email', email);
writeFileSync(join(dir, 'README.md'), '# temp\n');
git('add', '-A');
git('commit', '-qm', 'initial');
}
/**
* 開一個「有遠端」的臨時 repo:一個 bare 當 origin,一個工作用的 clone。
*
* branch-prep 的重點行為都繞著遠端打轉——來源分支在遠端已存在時要 pull 而不是重建、
* 目標分支已存在時不能覆蓋他人進度。這些事沒有遠端就驗不出來。
* git 不做 mock:在臨時 repo 上跑真的 git 比假的 git 可信,成本也低。
*
* @returns {{dir: string, origin: string, git: Function, pushFromElsewhere: Function, cleanup: Function}}
* dir 為工作用 clone,origin 為 bare repo,pushFromElsewhere 用來模擬別人推東西上去
*/
export function makeTempRepoWithRemote() {
mkdirSync(tmpRoot, { recursive: true });
const base = mkdtempSync(join(tmpRoot, 'remote-'));
const origin = join(base, 'origin.git');
const dir = join(base, 'work');
execFileSync('git', ['init', '-q', '--bare', '-b', 'master', origin]);
execFileSync('git', ['clone', '-q', origin, dir]);
const git = gitIn(dir);
seed(git, dir, 'tester', 'tester@example.com');
git('push', '-q', 'origin', 'master');
return {
dir,
origin,
git,
/** 模擬「別人推了東西上去」:在 origin 上直接造一顆 commit */
pushFromElsewhere: (branch, filename, content) => {
const other = join(base, `other-${filename}`);
execFileSync('git', ['clone', '-q', origin, other]);
const otherGit = gitIn(other);
otherGit('config', 'user.name', 'someone-else');
otherGit('config', 'user.email', 'other@example.com');
otherGit('checkout', '-q', '-B', branch);
writeFileSync(join(other, filename), content);
otherGit('add', '-A');
otherGit('commit', '-qm', `別人的進度:${filename}`);
otherGit('push', '-q', 'origin', branch);
rmSync(other, { recursive: true, force: true });
},
cleanup: () => rmSync(base, { recursive: true, force: true }),
};
}