fix(ci): format-check-changed 兼容缺失 revision range
- diff range 缺失时自动补全 git 历史(unshallow/depth fetch) - range 仍不可用时回退为 HEAD 变更文件列表,避免 CI 因浅克隆直接失败
This commit is contained in:
@@ -2,8 +2,14 @@ const fs = require('node:fs');
|
|||||||
const path = require('node:path');
|
const path = require('node:path');
|
||||||
const { execFileSync } = require('node:child_process');
|
const { execFileSync } = require('node:child_process');
|
||||||
|
|
||||||
function runGit(args, cwd) {
|
function runGit(args, cwd, options = {}) {
|
||||||
return execFileSync('git', args, { cwd, encoding: 'utf8' }).trim();
|
const { allowFailure = false, stdio } = options;
|
||||||
|
try {
|
||||||
|
return execFileSync('git', args, { cwd, encoding: 'utf8', stdio: stdio || 'pipe' }).trim();
|
||||||
|
} catch (error) {
|
||||||
|
if (allowFailure) return null;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function tryReadGithubEvent(eventPath) {
|
function tryReadGithubEvent(eventPath) {
|
||||||
@@ -38,24 +44,93 @@ function getDiffRangeFromGithubEvent(event) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function gitObjectExists(repoRoot, sha) {
|
||||||
|
if (!sha) return false;
|
||||||
|
const result = runGit(['cat-file', '-e', `${sha}^{commit}`], repoRoot, { allowFailure: true });
|
||||||
|
return result !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isShallowRepository(repoRoot) {
|
||||||
|
const result = runGit(['rev-parse', '--is-shallow-repository'], repoRoot, { allowFailure: true });
|
||||||
|
return result === 'true';
|
||||||
|
}
|
||||||
|
|
||||||
|
function tryFetchMoreHistory(repoRoot) {
|
||||||
|
// 仅在 CI 场景兜底:actions/checkout 若是浅克隆,可能缺少 base commit,导致 diff range 失败
|
||||||
|
try {
|
||||||
|
if (isShallowRepository(repoRoot)) {
|
||||||
|
execFileSync('git', ['fetch', '--prune', '--no-tags', '--unshallow'], {
|
||||||
|
cwd: repoRoot,
|
||||||
|
stdio: 'inherit',
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
execFileSync('git', ['fetch', '--prune', '--no-tags', '--depth=200', 'origin'], {
|
||||||
|
cwd: repoRoot,
|
||||||
|
stdio: 'inherit',
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectHeadChangedFiles(repoRoot) {
|
||||||
|
const output = runGit(
|
||||||
|
['show', '--name-only', '--diff-filter=ACMR', '--pretty=format:', 'HEAD'],
|
||||||
|
repoRoot,
|
||||||
|
{ allowFailure: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!output) return [];
|
||||||
|
|
||||||
|
return output
|
||||||
|
.split('\n')
|
||||||
|
.map((line) => line.trim())
|
||||||
|
.filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
function collectChangedFiles(repoRoot, range) {
|
function collectChangedFiles(repoRoot, range) {
|
||||||
if (!range) return [];
|
if (!range) return [];
|
||||||
const output = runGit(
|
|
||||||
['diff', '--name-only', '--diff-filter=ACMR', `${range.base}..${range.head}`],
|
const diffArgs = ['diff', '--name-only', '--diff-filter=ACMR', `${range.base}..${range.head}`];
|
||||||
repoRoot
|
|
||||||
);
|
const baseExists = gitObjectExists(repoRoot, range.base);
|
||||||
|
const headExists = gitObjectExists(repoRoot, range.head);
|
||||||
|
if (!baseExists || !headExists) {
|
||||||
|
console.warn(
|
||||||
|
'格式检查:检测到 diff range 所需提交缺失,尝试补全 git 历史(避免浅克隆导致失败)'
|
||||||
|
);
|
||||||
|
tryFetchMoreHistory(repoRoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
const output = runGit(diffArgs, repoRoot, { allowFailure: true });
|
||||||
|
if (!output) {
|
||||||
|
console.warn(
|
||||||
|
'格式检查:无法计算 revision range,回退为 HEAD 变更文件(可能仅覆盖最后一次提交)'
|
||||||
|
);
|
||||||
|
return collectHeadChangedFiles(repoRoot);
|
||||||
|
}
|
||||||
|
|
||||||
return output
|
return output
|
||||||
? output
|
.split('\n')
|
||||||
.split('\n')
|
.map((line) => line.trim())
|
||||||
.map((line) => line.trim())
|
.filter(Boolean);
|
||||||
.filter(Boolean)
|
|
||||||
: [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function collectWorkingTreeChangedFiles(repoRoot) {
|
function collectWorkingTreeChangedFiles(repoRoot) {
|
||||||
const files = new Set();
|
const files = new Set();
|
||||||
const unstaged = runGit(['diff', '--name-only', '--diff-filter=ACMR', 'HEAD'], repoRoot);
|
const unstaged = runGit(['diff', '--name-only', '--diff-filter=ACMR', 'HEAD'], repoRoot, {
|
||||||
const staged = runGit(['diff', '--cached', '--name-only', '--diff-filter=ACMR'], repoRoot);
|
allowFailure: true,
|
||||||
|
});
|
||||||
|
const staged = runGit(['diff', '--cached', '--name-only', '--diff-filter=ACMR'], repoRoot, {
|
||||||
|
allowFailure: true,
|
||||||
|
});
|
||||||
|
|
||||||
[unstaged, staged].forEach((block) => {
|
[unstaged, staged].forEach((block) => {
|
||||||
if (!block) return;
|
if (!block) return;
|
||||||
|
|||||||
Reference in New Issue
Block a user