-
Notifications
You must be signed in to change notification settings - Fork 0
/
lint-changed.ts
81 lines (68 loc) · 2.88 KB
/
lint-changed.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import { createRequire } from 'node:module';
import type { ExecaError } from 'execa';
import { execa } from 'execa';
import micromatch from 'micromatch';
import c from 'picocolors';
import { consola, execaWithOutput, formatDuration, logWithBox } from './utils';
const baseBranch = process.env.CHANGE_TARGET || 'master';
consola.info(`Base Branch:${baseBranch}`);
process.stdout.write('\n');
const require = createRequire(import.meta.url);
const lintStagedConfig = require('../lint-staged.config') as Record<
string,
(files: string[]) => string
>;
/**
* @see https://github.com/okonet/lint-staged/blob/master/lib/getDiffCommand.js
*/
async function getChangedFiles() {
const { stdout } = await execa('git', [
'diff',
'--name-only',
// 排除删除了的文件
'--diff-filter=ACMR',
`${baseBranch}...HEAD`,
]);
return stdout.trim().split(/\r?\n/);
}
const changedFiles = await getChangedFiles();
const lintTasks = Object.entries(lintStagedConfig).map(async ([pattern, taskCreator]) => {
const expandedPattern = `**/${pattern}`;
const matchedFiles = micromatch(changedFiles, expandedPattern, {});
const command = taskCreator(matchedFiles).trim();
if (command === (globalThis as any).__lintStagedSkipMessage__) {
consola.info(c.yellow(`no files matched, skip ${c.bold(c.magenta(taskCreator.name))}`));
return;
}
const doubleQuoteIndex = command.indexOf('"');
const [exe, ...args] = command.slice(0, doubleQuoteIndex).trim().split(/\s+/);
const pathList = command
.slice(doubleQuoteIndex)
.split(/(?<=")\s+(?=")/)
// 去除引号
.map((pathWithQuote) => pathWithQuote.slice(1, -1));
const filesTooMany = pathList.length > 10;
const pathListStr = filesTooMany ? `<...${pathList.length}files>` : pathList.join(' ');
const commandStr = `${[c.bold(exe), ...args, c.green(pathListStr)].join(' ')}`;
console.log(c.magenta(`$ ${commandStr}\n`));
const start = Date.now();
try {
await execaWithOutput(exe, [...args, ...pathList], { outputCommand: false });
} catch (_error) {
const error = _error as unknown as ExecaError;
let { message, command, exitCode } = error;
if (filesTooMany) {
message = message.replace(command, c.red(commandStr));
}
consola.error(message);
const fixCommand = `pnpm lint:fix ${baseBranch}`;
const title = c.red('Lint 失败,请尝试在本地运行下面的修复命令!');
logWithBox(title, c.green(fixCommand));
consola.error(`Changed files:\n${pathList.map((path) => c.green(path)).join('\n')}`);
process.exit(exitCode);
}
consola.success(`${taskCreator.name} ${formatDuration(Date.now() - start)}`);
});
// 只 lint 不修复,也就是只读不写不会有并发问题
await Promise.all(lintTasks);
consola.success('Lint 通过');