mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-08-26 17:13:32 +00:00
109 lines
3 KiB
JavaScript
109 lines
3 KiB
JavaScript
#!/usr/bin/env node
|
|
import { readFileSync } from 'node:fs';
|
|
|
|
export const CI_PROFILES = {
|
|
DOCS_ONLY: 'docs_only',
|
|
GITHUB_CI_ONLY: 'github_ci_only',
|
|
FULL: 'full',
|
|
};
|
|
|
|
export const GITHUB_CI_ONLY_FILES = new Set([
|
|
'.github/scripts/pr-safety-precheck.mjs',
|
|
'.github/scripts/pr-safety-precheck.test.mjs',
|
|
'.github/workflows/qwen-pr-safety-precheck.yml',
|
|
]);
|
|
|
|
function isDocsOnlyFile(file) {
|
|
const normalized = file.replace(/\\/g, '/');
|
|
return (
|
|
// .md ONLY: MDX pages are executable (imported components, expressions)
|
|
// and keep the full profile with its runtime/build failure surface.
|
|
/^docs\/.+\.md$/i.test(normalized) ||
|
|
// Extensionless or known-inert documentation extensions ONLY: the open
|
|
// `(?:\.[^/]*)?` form classified executable files named after reserved
|
|
// prose basenames (README.js, SECURITY.ts, LICENSE.sh) as docs, which
|
|
// would downgrade an automatic review over runnable code. MDX is
|
|
// excluded here for the same reason it is above.
|
|
/^(?:README|CHANGELOG|CONTRIBUTING|CODE_OF_CONDUCT|SECURITY|SUPPORT|LICENSE|NOTICE)(?:\.(?:md|txt|rst))?$/i.test(
|
|
normalized,
|
|
)
|
|
);
|
|
}
|
|
|
|
function classifyPath(file) {
|
|
if (isDocsOnlyFile(file)) return CI_PROFILES.DOCS_ONLY;
|
|
if (GITHUB_CI_ONLY_FILES.has(file)) return CI_PROFILES.GITHUB_CI_ONLY;
|
|
return CI_PROFILES.FULL;
|
|
}
|
|
|
|
function classifyFileEntry(entry) {
|
|
if (typeof entry === 'string') return classifyPath(entry);
|
|
|
|
const filename = entry?.filename;
|
|
if (!filename) return CI_PROFILES.FULL;
|
|
|
|
const profile = classifyPath(filename);
|
|
if (entry.status !== 'renamed') return profile;
|
|
|
|
const previousProfile = entry.previous_filename
|
|
? classifyPath(entry.previous_filename)
|
|
: CI_PROFILES.FULL;
|
|
return previousProfile === profile ? profile : CI_PROFILES.FULL;
|
|
}
|
|
|
|
export function classifyChangedFiles(files) {
|
|
const changedFiles = files.filter(Boolean);
|
|
if (changedFiles.length === 0) return CI_PROFILES.FULL;
|
|
|
|
if (
|
|
changedFiles.every(
|
|
(entry) => classifyFileEntry(entry) === CI_PROFILES.DOCS_ONLY,
|
|
)
|
|
) {
|
|
return CI_PROFILES.DOCS_ONLY;
|
|
}
|
|
|
|
if (
|
|
changedFiles.every(
|
|
(entry) => classifyFileEntry(entry) === CI_PROFILES.GITHUB_CI_ONLY,
|
|
)
|
|
) {
|
|
return CI_PROFILES.GITHUB_CI_ONLY;
|
|
}
|
|
|
|
return CI_PROFILES.FULL;
|
|
}
|
|
|
|
function parseChangedFiles(text) {
|
|
return text
|
|
.split(/\r?\n/)
|
|
.filter(Boolean)
|
|
.map((line) => {
|
|
try {
|
|
return JSON.parse(line);
|
|
} catch {
|
|
return line;
|
|
}
|
|
});
|
|
}
|
|
|
|
function main() {
|
|
const filePath = process.argv[2];
|
|
if (!filePath) {
|
|
console.log(CI_PROFILES.FULL);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const files = parseChangedFiles(readFileSync(filePath, 'utf8'));
|
|
console.log(classifyChangedFiles(files));
|
|
} catch (err) {
|
|
const message = err instanceof Error ? err.message : String(err);
|
|
console.error(`::warning::Failed to read changed files: ${message}`);
|
|
console.log(CI_PROFILES.FULL);
|
|
}
|
|
}
|
|
|
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
main();
|
|
}
|