mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-04-08 10:23:30 +08:00
fix: harden windows CI tests and markdown lint
This commit is contained in:
@@ -71,7 +71,7 @@
|
|||||||
|
|
||||||
## 归属
|
## 归属
|
||||||
|
|
||||||
本行为准则改编自 \[贡献者公约]\[homepage] 2.0 版本,可访问
|
本行为准则改编自 [贡献者公约][homepage] 2.0 版本,可访问
|
||||||
<https://www.contributor-covenant.org/version/2/0/code_of_conduct.html> 获取。
|
<https://www.contributor-covenant.org/version/2/0/code_of_conduct.html> 获取。
|
||||||
|
|
||||||
社区影响指南的灵感来源于 [Mozilla 的行为准则执行阶梯](https://github.com/mozilla/diversity)。
|
社区影响指南的灵感来源于 [Mozilla 的行为准则执行阶梯](https://github.com/mozilla/diversity)。
|
||||||
|
|||||||
@@ -315,6 +315,6 @@ result = "".join(str(item) for item in items)
|
|||||||
| 海象运算符 (`:=`) | 3.8+ |
|
| 海象运算符 (`:=`) | 3.8+ |
|
||||||
| 仅限位置参数 | 3.8+ |
|
| 仅限位置参数 | 3.8+ |
|
||||||
| Match 语句 | 3.10+ |
|
| Match 语句 | 3.10+ |
|
||||||
| 类型联合 (\`x | None\`) | 3.10+ |
|
| 类型联合 (`x \| None`) | 3.10+ |
|
||||||
|
|
||||||
确保你的项目 `pyproject.toml` 或 `setup.py` 指定了正确的最低 Python 版本。
|
确保你的项目 `pyproject.toml` 或 `setup.py` 指定了正确的最低 Python 版本。
|
||||||
|
|||||||
@@ -28,6 +28,13 @@ function makeTempDir() {
|
|||||||
return fs.mkdtempSync(path.join(os.tmpdir(), 'cost-tracker-test-'));
|
return fs.mkdtempSync(path.join(os.tmpdir(), 'cost-tracker-test-'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function withTempHome(homeDir) {
|
||||||
|
return {
|
||||||
|
HOME: homeDir,
|
||||||
|
USERPROFILE: homeDir,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function runScript(input, envOverrides = {}) {
|
function runScript(input, envOverrides = {}) {
|
||||||
const inputStr = typeof input === 'string' ? input : JSON.stringify(input);
|
const inputStr = typeof input === 'string' ? input : JSON.stringify(input);
|
||||||
const result = spawnSync('node', [script], {
|
const result = spawnSync('node', [script], {
|
||||||
@@ -64,7 +71,7 @@ function runTests() {
|
|||||||
model: 'claude-sonnet-4-20250514',
|
model: 'claude-sonnet-4-20250514',
|
||||||
usage: { input_tokens: 1000, output_tokens: 500 },
|
usage: { input_tokens: 1000, output_tokens: 500 },
|
||||||
};
|
};
|
||||||
const result = runScript(input, { HOME: tmpHome });
|
const result = runScript(input, withTempHome(tmpHome));
|
||||||
assert.strictEqual(result.code, 0, `Expected exit code 0, got ${result.code}`);
|
assert.strictEqual(result.code, 0, `Expected exit code 0, got ${result.code}`);
|
||||||
|
|
||||||
const metricsFile = path.join(tmpHome, '.claude', 'metrics', 'costs.jsonl');
|
const metricsFile = path.join(tmpHome, '.claude', 'metrics', 'costs.jsonl');
|
||||||
@@ -84,7 +91,7 @@ function runTests() {
|
|||||||
// 3. Handles empty input gracefully
|
// 3. Handles empty input gracefully
|
||||||
(test('handles empty input gracefully', () => {
|
(test('handles empty input gracefully', () => {
|
||||||
const tmpHome = makeTempDir();
|
const tmpHome = makeTempDir();
|
||||||
const result = runScript('', { HOME: tmpHome });
|
const result = runScript('', withTempHome(tmpHome));
|
||||||
assert.strictEqual(result.code, 0, `Expected exit code 0, got ${result.code}`);
|
assert.strictEqual(result.code, 0, `Expected exit code 0, got ${result.code}`);
|
||||||
// stdout should be empty since input was empty
|
// stdout should be empty since input was empty
|
||||||
assert.strictEqual(result.stdout, '', 'Expected empty stdout for empty input');
|
assert.strictEqual(result.stdout, '', 'Expected empty stdout for empty input');
|
||||||
@@ -96,7 +103,7 @@ function runTests() {
|
|||||||
(test('handles invalid JSON gracefully', () => {
|
(test('handles invalid JSON gracefully', () => {
|
||||||
const tmpHome = makeTempDir();
|
const tmpHome = makeTempDir();
|
||||||
const invalidInput = 'not valid json {{{';
|
const invalidInput = 'not valid json {{{';
|
||||||
const result = runScript(invalidInput, { HOME: tmpHome });
|
const result = runScript(invalidInput, withTempHome(tmpHome));
|
||||||
assert.strictEqual(result.code, 0, `Expected exit code 0, got ${result.code}`);
|
assert.strictEqual(result.code, 0, `Expected exit code 0, got ${result.code}`);
|
||||||
// Should still pass through the raw input on stdout
|
// Should still pass through the raw input on stdout
|
||||||
assert.strictEqual(result.stdout, invalidInput, 'Expected stdout to contain original invalid input');
|
assert.strictEqual(result.stdout, invalidInput, 'Expected stdout to contain original invalid input');
|
||||||
@@ -109,7 +116,7 @@ function runTests() {
|
|||||||
const tmpHome = makeTempDir();
|
const tmpHome = makeTempDir();
|
||||||
const input = { model: 'claude-sonnet-4-20250514' };
|
const input = { model: 'claude-sonnet-4-20250514' };
|
||||||
const inputStr = JSON.stringify(input);
|
const inputStr = JSON.stringify(input);
|
||||||
const result = runScript(input, { HOME: tmpHome });
|
const result = runScript(input, withTempHome(tmpHome));
|
||||||
assert.strictEqual(result.code, 0, `Expected exit code 0, got ${result.code}`);
|
assert.strictEqual(result.code, 0, `Expected exit code 0, got ${result.code}`);
|
||||||
assert.strictEqual(result.stdout, inputStr, 'Expected stdout to match original input');
|
assert.strictEqual(result.stdout, inputStr, 'Expected stdout to match original input');
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,20 @@ function cleanupDir(dir) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toBashPath(filePath) {
|
||||||
|
if (process.platform !== 'win32') {
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return String(filePath)
|
||||||
|
.replace(/^([A-Za-z]):/, (_, driveLetter) => `/${driveLetter.toLowerCase()}`)
|
||||||
|
.replace(/\\/g, '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
function runBash(command, options = {}) {
|
||||||
|
return execSync(`bash -lc '${command.replace(/'/g, "'\\''")}'`, options).toString().trim();
|
||||||
|
}
|
||||||
|
|
||||||
const repoRoot = path.resolve(__dirname, '..', '..');
|
const repoRoot = path.resolve(__dirname, '..', '..');
|
||||||
const detectProjectPath = path.join(
|
const detectProjectPath = path.join(
|
||||||
repoRoot,
|
repoRoot,
|
||||||
@@ -98,7 +112,7 @@ test('[ -d ] returns true for .git directory', () => {
|
|||||||
const dir = path.join(behaviorDir, 'test-d-dir');
|
const dir = path.join(behaviorDir, 'test-d-dir');
|
||||||
fs.mkdirSync(dir, { recursive: true });
|
fs.mkdirSync(dir, { recursive: true });
|
||||||
fs.mkdirSync(path.join(dir, '.git'));
|
fs.mkdirSync(path.join(dir, '.git'));
|
||||||
const result = execSync(`bash -c '[ -d "${dir}/.git" ] && echo yes || echo no'`).toString().trim();
|
const result = runBash(`[ -d "${toBashPath(path.join(dir, '.git'))}" ] && echo yes || echo no`);
|
||||||
assert.strictEqual(result, 'yes');
|
assert.strictEqual(result, 'yes');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -106,7 +120,7 @@ test('[ -d ] returns false for .git file', () => {
|
|||||||
const dir = path.join(behaviorDir, 'test-d-file');
|
const dir = path.join(behaviorDir, 'test-d-file');
|
||||||
fs.mkdirSync(dir, { recursive: true });
|
fs.mkdirSync(dir, { recursive: true });
|
||||||
fs.writeFileSync(path.join(dir, '.git'), 'gitdir: /some/path\n');
|
fs.writeFileSync(path.join(dir, '.git'), 'gitdir: /some/path\n');
|
||||||
const result = execSync(`bash -c '[ -d "${dir}/.git" ] && echo yes || echo no'`).toString().trim();
|
const result = runBash(`[ -d "${toBashPath(path.join(dir, '.git'))}" ] && echo yes || echo no`);
|
||||||
assert.strictEqual(result, 'no');
|
assert.strictEqual(result, 'no');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -114,7 +128,7 @@ test('[ -e ] returns true for .git directory', () => {
|
|||||||
const dir = path.join(behaviorDir, 'test-e-dir');
|
const dir = path.join(behaviorDir, 'test-e-dir');
|
||||||
fs.mkdirSync(dir, { recursive: true });
|
fs.mkdirSync(dir, { recursive: true });
|
||||||
fs.mkdirSync(path.join(dir, '.git'));
|
fs.mkdirSync(path.join(dir, '.git'));
|
||||||
const result = execSync(`bash -c '[ -e "${dir}/.git" ] && echo yes || echo no'`).toString().trim();
|
const result = runBash(`[ -e "${toBashPath(path.join(dir, '.git'))}" ] && echo yes || echo no`);
|
||||||
assert.strictEqual(result, 'yes');
|
assert.strictEqual(result, 'yes');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -122,14 +136,14 @@ test('[ -e ] returns true for .git file', () => {
|
|||||||
const dir = path.join(behaviorDir, 'test-e-file');
|
const dir = path.join(behaviorDir, 'test-e-file');
|
||||||
fs.mkdirSync(dir, { recursive: true });
|
fs.mkdirSync(dir, { recursive: true });
|
||||||
fs.writeFileSync(path.join(dir, '.git'), 'gitdir: /some/path\n');
|
fs.writeFileSync(path.join(dir, '.git'), 'gitdir: /some/path\n');
|
||||||
const result = execSync(`bash -c '[ -e "${dir}/.git" ] && echo yes || echo no'`).toString().trim();
|
const result = runBash(`[ -e "${toBashPath(path.join(dir, '.git'))}" ] && echo yes || echo no`);
|
||||||
assert.strictEqual(result, 'yes');
|
assert.strictEqual(result, 'yes');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[ -e ] returns false when .git does not exist', () => {
|
test('[ -e ] returns false when .git does not exist', () => {
|
||||||
const dir = path.join(behaviorDir, 'test-e-none');
|
const dir = path.join(behaviorDir, 'test-e-none');
|
||||||
fs.mkdirSync(dir, { recursive: true });
|
fs.mkdirSync(dir, { recursive: true });
|
||||||
const result = execSync(`bash -c '[ -e "${dir}/.git" ] && echo yes || echo no'`).toString().trim();
|
const result = runBash(`[ -e "${toBashPath(path.join(dir, '.git'))}" ] && echo yes || echo no`);
|
||||||
assert.strictEqual(result, 'no');
|
assert.strictEqual(result, 'no');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -188,20 +202,21 @@ test('detect-project.sh sets PROJECT_NAME and non-global PROJECT_ID for worktree
|
|||||||
|
|
||||||
// Source detect-project.sh from the worktree directory and capture results
|
// Source detect-project.sh from the worktree directory and capture results
|
||||||
const script = `
|
const script = `
|
||||||
export CLAUDE_PROJECT_DIR="${worktreeDir}"
|
export CLAUDE_PROJECT_DIR="${toBashPath(worktreeDir)}"
|
||||||
export HOME="${testDir}"
|
export HOME="${toBashPath(testDir)}"
|
||||||
source "${detectProjectPath}"
|
source "${toBashPath(detectProjectPath)}"
|
||||||
echo "PROJECT_NAME=\${PROJECT_NAME}"
|
echo "PROJECT_NAME=\${PROJECT_NAME}"
|
||||||
echo "PROJECT_ID=\${PROJECT_ID}"
|
echo "PROJECT_ID=\${PROJECT_ID}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const result = execSync(`bash -c '${script.replace(/'/g, "'\\''")}'`, {
|
const result = execSync(`bash -lc '${script.replace(/'/g, "'\\''")}'`, {
|
||||||
cwd: worktreeDir,
|
cwd: worktreeDir,
|
||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
env: {
|
env: {
|
||||||
...process.env,
|
...process.env,
|
||||||
HOME: testDir,
|
HOME: toBashPath(testDir),
|
||||||
CLAUDE_PROJECT_DIR: worktreeDir
|
USERPROFILE: testDir,
|
||||||
|
CLAUDE_PROJECT_DIR: toBashPath(worktreeDir)
|
||||||
}
|
}
|
||||||
}).toString();
|
}).toString();
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ function toBashPath(filePath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return String(filePath)
|
return String(filePath)
|
||||||
.replace(/^([A-Za-z]):/, (_, driveLetter) => `/mnt/${driveLetter.toLowerCase()}`)
|
.replace(/^([A-Za-z]):/, (_, driveLetter) => `/${driveLetter.toLowerCase()}`)
|
||||||
.replace(/\\/g, '/');
|
.replace(/\\/g, '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,15 @@ function setupPluginCache(homeDir, orgName, version) {
|
|||||||
return cacheDir;
|
return cacheDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function withHomeEnv(homeDir, extraEnv = {}) {
|
||||||
|
return {
|
||||||
|
PATH: process.env.PATH,
|
||||||
|
HOME: homeDir,
|
||||||
|
USERPROFILE: homeDir,
|
||||||
|
...extraEnv,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function runTests() {
|
function runTests() {
|
||||||
console.log('\n=== Testing resolve-ecc-root.js ===\n');
|
console.log('\n=== Testing resolve-ecc-root.js ===\n');
|
||||||
|
|
||||||
@@ -215,7 +224,7 @@ function runTests() {
|
|||||||
const result = execFileSync('node', [
|
const result = execFileSync('node', [
|
||||||
'-e', `console.log(${INLINE_RESOLVE})`,
|
'-e', `console.log(${INLINE_RESOLVE})`,
|
||||||
], {
|
], {
|
||||||
env: { PATH: process.env.PATH, HOME: homeDir },
|
env: withHomeEnv(homeDir),
|
||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
}).trim();
|
}).trim();
|
||||||
assert.strictEqual(result, expected);
|
assert.strictEqual(result, expected);
|
||||||
@@ -231,7 +240,7 @@ function runTests() {
|
|||||||
const result = execFileSync('node', [
|
const result = execFileSync('node', [
|
||||||
'-e', `console.log(${INLINE_RESOLVE})`,
|
'-e', `console.log(${INLINE_RESOLVE})`,
|
||||||
], {
|
], {
|
||||||
env: { PATH: process.env.PATH, HOME: homeDir },
|
env: withHomeEnv(homeDir),
|
||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
}).trim();
|
}).trim();
|
||||||
assert.strictEqual(result, path.join(homeDir, '.claude'));
|
assert.strictEqual(result, path.join(homeDir, '.claude'));
|
||||||
|
|||||||
Reference in New Issue
Block a user