pr-checkmate 1.22.8 → 1.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +101 -333
- package/cspell.json +9 -1
- package/dist/cli.js +32 -2
- package/dist/config/constants.d.ts +9 -0
- package/dist/config/constants.js +68 -1
- package/dist/core/checks/dependencies/banned-imports.d.ts +2 -0
- package/dist/core/checks/dependencies/banned-imports.js +71 -0
- package/dist/core/checks/{circular-deps.d.ts → dependencies/circular-deps.d.ts} +1 -1
- package/dist/core/checks/{circular-deps.js → dependencies/circular-deps.js} +5 -5
- package/dist/core/checks/{dependency-check.d.ts → dependencies/dependency-check.d.ts} +1 -1
- package/dist/core/checks/{dependency-check.js → dependencies/dependency-check.js} +3 -3
- package/dist/core/checks/{license-check.d.ts → dependencies/license-check.d.ts} +1 -1
- package/dist/core/checks/{license-check.js → dependencies/license-check.js} +3 -3
- package/dist/core/checks/{npm-audit.d.ts → dependencies/npm-audit.d.ts} +1 -1
- package/dist/core/checks/{npm-audit.js → dependencies/npm-audit.js} +3 -3
- package/dist/core/checks/{outdated-deps.d.ts → dependencies/outdated-deps.d.ts} +1 -1
- package/dist/core/checks/{outdated-deps.js → dependencies/outdated-deps.js} +3 -3
- package/dist/core/checks/dependencies/vuln-scan.d.ts +9 -0
- package/dist/core/checks/dependencies/vuln-scan.js +41 -0
- package/dist/core/checks/findings.d.ts +37 -1
- package/dist/core/checks/findings.js +80 -3
- package/dist/core/checks/git/custom-rules.d.ts +2 -0
- package/dist/core/checks/git/custom-rules.js +102 -0
- package/dist/core/checks/{diff-smell.d.ts → git/diff-smell.d.ts} +1 -1
- package/dist/core/checks/{diff-smell.js → git/diff-smell.js} +3 -3
- package/dist/core/checks/git/large-files.d.ts +2 -0
- package/dist/core/checks/git/large-files.js +83 -0
- package/dist/core/checks/git/leftover-debug.d.ts +2 -0
- package/dist/core/checks/git/leftover-debug.js +77 -0
- package/dist/core/checks/git/lockfile-drift.d.ts +2 -0
- package/dist/core/checks/git/lockfile-drift.js +114 -0
- package/dist/core/checks/git/merge-conflict.d.ts +2 -0
- package/dist/core/checks/git/merge-conflict.js +109 -0
- package/dist/core/checks/git/missing-tests.d.ts +2 -0
- package/dist/core/checks/git/missing-tests.js +92 -0
- package/dist/core/checks/git/todo-fixme.d.ts +7 -0
- package/dist/core/checks/git/todo-fixme.js +74 -0
- package/dist/core/checks/{cpp-format.d.ts → languages/cpp-format.d.ts} +1 -1
- package/dist/core/checks/{cpp-format.js → languages/cpp-format.js} +3 -3
- package/dist/core/checks/languages/csharp-format.d.ts +13 -0
- package/dist/core/checks/languages/csharp-format.js +52 -0
- package/dist/core/checks/languages/go-format.d.ts +8 -0
- package/dist/core/checks/languages/go-format.js +48 -0
- package/dist/core/checks/languages/go-lint.d.ts +8 -0
- package/dist/core/checks/languages/go-lint.js +48 -0
- package/dist/core/checks/{kotlin-lint.d.ts → languages/kotlin-lint.d.ts} +1 -1
- package/dist/core/checks/{kotlin-lint.js → languages/kotlin-lint.js} +13 -17
- package/dist/core/checks/{lint.d.ts → languages/lint.d.ts} +1 -1
- package/dist/core/checks/{lint.js → languages/lint.js} +5 -5
- package/dist/core/checks/languages/php-format.d.ts +9 -0
- package/dist/core/checks/languages/php-format.js +49 -0
- package/dist/core/checks/{prettier.d.ts → languages/prettier.d.ts} +1 -1
- package/dist/core/checks/{prettier.js → languages/prettier.js} +5 -5
- package/dist/core/checks/{python-format.d.ts → languages/python-format.d.ts} +1 -1
- package/dist/core/checks/{python-format.js → languages/python-format.js} +3 -3
- package/dist/core/checks/{python-lint.d.ts → languages/python-lint.d.ts} +1 -1
- package/dist/core/checks/{python-lint.js → languages/python-lint.js} +3 -3
- package/dist/core/checks/languages/python-typecheck.d.ts +9 -0
- package/dist/core/checks/languages/python-typecheck.js +66 -0
- package/dist/core/checks/languages/ruby-lint.d.ts +8 -0
- package/dist/core/checks/languages/ruby-lint.js +50 -0
- package/dist/core/checks/languages/rust-format.d.ts +9 -0
- package/dist/core/checks/languages/rust-format.js +45 -0
- package/dist/core/checks/languages/rust-lint.d.ts +8 -0
- package/dist/core/checks/languages/rust-lint.js +50 -0
- package/dist/core/checks/{swift-lint.d.ts → languages/swift-lint.d.ts} +1 -1
- package/dist/core/checks/{swift-lint.js → languages/swift-lint.js} +13 -17
- package/dist/core/checks/{typecheck.d.ts → languages/typecheck.d.ts} +1 -1
- package/dist/core/checks/{typecheck.js → languages/typecheck.js} +3 -3
- package/dist/core/checks/{commitlint.d.ts → pr/commitlint.d.ts} +1 -1
- package/dist/core/checks/{commitlint.js → pr/commitlint.js} +4 -4
- package/dist/core/checks/{pr-body.d.ts → pr/pr-body.d.ts} +1 -1
- package/dist/core/checks/{pr-body.js → pr/pr-body.js} +2 -2
- package/dist/core/checks/{pr-size-check.d.ts → pr/pr-size-check.d.ts} +1 -1
- package/dist/core/checks/{pr-size-check.js → pr/pr-size-check.js} +13 -11
- package/dist/core/checks/{pr-title-lint.d.ts → pr/pr-title-lint.d.ts} +1 -1
- package/dist/core/checks/{pr-title-lint.js → pr/pr-title-lint.js} +2 -2
- package/dist/core/checks/quality/case-collision.d.ts +8 -0
- package/dist/core/checks/quality/case-collision.js +40 -0
- package/dist/core/checks/quality/config-validation.d.ts +8 -0
- package/dist/core/checks/quality/config-validation.js +63 -0
- package/dist/core/checks/quality/coverage.d.ts +2 -0
- package/dist/core/checks/quality/coverage.js +63 -0
- package/dist/core/checks/{dead-code.d.ts → quality/dead-code.d.ts} +1 -1
- package/dist/core/checks/{dead-code.js → quality/dead-code.js} +4 -4
- package/dist/core/checks/{duplicate-check.d.ts → quality/duplicate-check.d.ts} +1 -1
- package/dist/core/checks/{duplicate-check.js → quality/duplicate-check.js} +6 -6
- package/dist/core/checks/quality/license-header.d.ts +7 -0
- package/dist/core/checks/quality/license-header.js +74 -0
- package/dist/core/checks/{markdown-lint.d.ts → quality/markdown-lint.d.ts} +1 -1
- package/dist/core/checks/{markdown-lint.js → quality/markdown-lint.js} +5 -5
- package/dist/core/checks/{spellcheck.d.ts → quality/spellcheck.d.ts} +1 -1
- package/dist/core/checks/{spellcheck.js → quality/spellcheck.js} +5 -5
- package/dist/core/checks/{diff-security.d.ts → security/diff-security.d.ts} +1 -1
- package/dist/core/checks/security/diff-security.js +262 -0
- package/dist/core/checks/security/dockerfile-security.d.ts +2 -0
- package/dist/core/checks/security/dockerfile-security.js +92 -0
- package/dist/core/checks/security/migration-safety.d.ts +2 -0
- package/dist/core/checks/security/migration-safety.js +110 -0
- package/dist/core/checks/{security.d.ts → security/security.d.ts} +1 -1
- package/dist/core/checks/{security.js → security/security.js} +4 -4
- package/dist/core/checks/{sensitive-file-guard.d.ts → security/sensitive-file-guard.d.ts} +1 -1
- package/dist/core/checks/{sensitive-file-guard.js → security/sensitive-file-guard.js} +4 -4
- package/dist/core/checks/security/workflow-security.d.ts +2 -0
- package/dist/core/checks/security/workflow-security.js +75 -0
- package/dist/core/context.js +14 -0
- package/dist/core/registry.js +73 -28
- package/dist/core/reporters.d.ts +4 -3
- package/dist/core/reporters.js +104 -4
- package/dist/core/run-checks.js +21 -3
- package/dist/core/targets.d.ts +4 -1
- package/dist/core/targets.js +16 -3
- package/dist/core/types.d.ts +13 -1
- package/dist/init.js +63 -0
- package/dist/interfaces/index.d.ts +99 -0
- package/dist/scripts/copy-configs.js +1 -0
- package/dist/utils/detect-language.d.ts +1 -1
- package/dist/utils/detect-language.js +32 -3
- package/dist/utils/glob.d.ts +10 -0
- package/dist/utils/glob.js +25 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/package.json +2 -1
- package/pr-checkmate.schema.json +166 -0
- package/src/config/cspell.json +9 -1
- package/src/config/pr-checkmate.schema.json +166 -0
- package/dist/core/checks/diff-security.js +0 -145
- /package/dist/core/checks/{ruff-shared.d.ts → languages/ruff-shared.d.ts} +0 -0
- /package/dist/core/checks/{ruff-shared.js → languages/ruff-shared.js} +0 -0
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.prSizeCheck = void 0;
|
|
4
|
-
const utils_1 = require("
|
|
5
|
-
const execa_1 = require("
|
|
6
|
-
const types_1 = require("
|
|
7
|
-
const
|
|
8
|
-
const
|
|
4
|
+
const utils_1 = require("../../../utils");
|
|
5
|
+
const execa_1 = require("../../../utils/execa");
|
|
6
|
+
const types_1 = require("../../types");
|
|
7
|
+
const DEFAULT_MAX_FILES = 50;
|
|
8
|
+
const DEFAULT_MAX_LINES = 1000;
|
|
9
9
|
exports.prSizeCheck = {
|
|
10
10
|
name: 'PR Size',
|
|
11
11
|
phase: 'informational',
|
|
12
12
|
applies(ctx) {
|
|
13
|
-
return Boolean(ctx.baseSha);
|
|
13
|
+
return ctx.config.prSize?.enabled !== false && Boolean(ctx.baseSha);
|
|
14
14
|
},
|
|
15
15
|
async run(ctx) {
|
|
16
|
+
const maxFiles = ctx.config.prSize?.maxFiles ?? DEFAULT_MAX_FILES;
|
|
17
|
+
const maxLines = ctx.config.prSize?.maxLines ?? DEFAULT_MAX_LINES;
|
|
16
18
|
try {
|
|
17
|
-
const { stdout } = await (0, execa_1.execa)('git', ['diff', '--shortstat', ctx.baseSha, 'HEAD'], {
|
|
19
|
+
const { stdout } = await (0, execa_1.execa)('git', ['diff', '--shortstat', ctx.baseSha, ctx.headSha ?? 'HEAD'], {
|
|
18
20
|
cwd: ctx.cwd,
|
|
19
21
|
});
|
|
20
22
|
// "5 files changed, 123 insertions(+), 45 deletions(-)"
|
|
@@ -24,10 +26,10 @@ exports.prSizeCheck = {
|
|
|
24
26
|
const lines = insertions + deletions;
|
|
25
27
|
utils_1.logger.info(`[PR Size]: ${fileCount} files changed, ${lines} lines`);
|
|
26
28
|
const issues = [];
|
|
27
|
-
if (fileCount >
|
|
28
|
-
issues.push(`${fileCount} files (recommended < ${
|
|
29
|
-
if (lines >
|
|
30
|
-
issues.push(`${lines} lines (recommended < ${
|
|
29
|
+
if (fileCount > maxFiles)
|
|
30
|
+
issues.push(`${fileCount} files (recommended < ${maxFiles})`);
|
|
31
|
+
if (lines > maxLines)
|
|
32
|
+
issues.push(`${lines} lines (recommended < ${maxLines})`);
|
|
31
33
|
if (issues.length > 0) {
|
|
32
34
|
issues.forEach(i => utils_1.logger.warn(`[PR Size]: ⚠️ Large PR: ${i}`));
|
|
33
35
|
return (0, types_1.warn)(issues.join(', '));
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Check } from '
|
|
1
|
+
import { Check } from '../../types';
|
|
2
2
|
export declare const prTitleLintCheck: Check;
|
|
@@ -5,8 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.prTitleLintCheck = void 0;
|
|
7
7
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
-
const utils_1 = require("
|
|
9
|
-
const types_1 = require("
|
|
8
|
+
const utils_1 = require("../../../utils");
|
|
9
|
+
const types_1 = require("../../types");
|
|
10
10
|
const CONVENTIONAL_PREFIX = /^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)(\(.+\))?!?: .+/;
|
|
11
11
|
exports.prTitleLintCheck = {
|
|
12
12
|
name: 'PR Title',
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Check } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Flags tracked files whose paths differ only by case (e.g. `Foo.ts` vs
|
|
4
|
+
* `foo.ts`). Such pairs coexist on Linux (case-sensitive) but collide on macOS/
|
|
5
|
+
* Windows and in many Docker layers, silently breaking checkouts and builds.
|
|
6
|
+
* Whole-repo scan (not delta), scoped to `sourcePath` and honouring `ignoreDirs`.
|
|
7
|
+
*/
|
|
8
|
+
export declare const caseCollisionCheck: Check;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.caseCollisionCheck = void 0;
|
|
4
|
+
const config_1 = require("../../../config");
|
|
5
|
+
const utils_1 = require("../../../utils");
|
|
6
|
+
const targets_1 = require("../../targets");
|
|
7
|
+
const types_1 = require("../../types");
|
|
8
|
+
/**
|
|
9
|
+
* Flags tracked files whose paths differ only by case (e.g. `Foo.ts` vs
|
|
10
|
+
* `foo.ts`). Such pairs coexist on Linux (case-sensitive) but collide on macOS/
|
|
11
|
+
* Windows and in many Docker layers, silently breaking checkouts and builds.
|
|
12
|
+
* Whole-repo scan (not delta), scoped to `sourcePath` and honouring `ignoreDirs`.
|
|
13
|
+
*/
|
|
14
|
+
exports.caseCollisionCheck = {
|
|
15
|
+
name: 'Case Collision',
|
|
16
|
+
phase: 'informational',
|
|
17
|
+
applies(ctx) {
|
|
18
|
+
return ctx.config.caseCollision?.enabled !== false;
|
|
19
|
+
},
|
|
20
|
+
async run(ctx) {
|
|
21
|
+
const files = await (0, targets_1.listTrackedFiles)(ctx, ['*'], (0, config_1.getSourcePaths)());
|
|
22
|
+
if (files.length === 0)
|
|
23
|
+
return (0, types_1.skip)('no tracked files');
|
|
24
|
+
const byLower = new Map();
|
|
25
|
+
for (const f of files) {
|
|
26
|
+
const key = f.toLowerCase();
|
|
27
|
+
let set = byLower.get(key);
|
|
28
|
+
if (!set) {
|
|
29
|
+
set = new Set();
|
|
30
|
+
byLower.set(key, set);
|
|
31
|
+
}
|
|
32
|
+
set.add(f);
|
|
33
|
+
}
|
|
34
|
+
const collisions = [...byLower.values()].filter(set => set.size > 1);
|
|
35
|
+
if (collisions.length === 0)
|
|
36
|
+
return (0, types_1.pass)();
|
|
37
|
+
collisions.forEach(set => utils_1.logger.warn(`[Case Collision]: ⚠️ ${[...set].join(' ↔ ')}`));
|
|
38
|
+
return (0, types_1.warn)(`${collisions.length} case-collision(s) — paths differing only by case`);
|
|
39
|
+
},
|
|
40
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Check } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Validates pr-checkmate.json itself: warns on unknown top-level keys (typos
|
|
4
|
+
* like `mergeConfict` that silently do nothing) and on invalid values in the
|
|
5
|
+
* `severity` map. Reads the raw file so it checks what the user actually wrote,
|
|
6
|
+
* not the merged defaults. `//`-comment keys and `$schema` are ignored.
|
|
7
|
+
*/
|
|
8
|
+
export declare const configValidationCheck: Check;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.configValidationCheck = void 0;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const config_1 = require("../../../config");
|
|
10
|
+
const utils_1 = require("../../../utils");
|
|
11
|
+
const types_1 = require("../../types");
|
|
12
|
+
const VALID_SEVERITIES = ['error', 'warn', 'off'];
|
|
13
|
+
/**
|
|
14
|
+
* Validates pr-checkmate.json itself: warns on unknown top-level keys (typos
|
|
15
|
+
* like `mergeConfict` that silently do nothing) and on invalid values in the
|
|
16
|
+
* `severity` map. Reads the raw file so it checks what the user actually wrote,
|
|
17
|
+
* not the merged defaults. `//`-comment keys and `$schema` are ignored.
|
|
18
|
+
*/
|
|
19
|
+
exports.configValidationCheck = {
|
|
20
|
+
name: 'Config Validation',
|
|
21
|
+
phase: 'informational',
|
|
22
|
+
applies(ctx) {
|
|
23
|
+
return ctx.config.configValidation?.enabled !== false;
|
|
24
|
+
},
|
|
25
|
+
async run(ctx) {
|
|
26
|
+
const file = node_path_1.default.join(ctx.cwd, 'pr-checkmate.json');
|
|
27
|
+
let raw;
|
|
28
|
+
try {
|
|
29
|
+
raw = node_fs_1.default.readFileSync(file, 'utf-8');
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return (0, types_1.skip)('no pr-checkmate.json');
|
|
33
|
+
}
|
|
34
|
+
let json;
|
|
35
|
+
try {
|
|
36
|
+
json = JSON.parse(raw);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
const msg = err instanceof Error ? err.message.split('\n')[0] : String(err);
|
|
40
|
+
return (0, types_1.warn)(`pr-checkmate.json is not valid JSON: ${msg}`);
|
|
41
|
+
}
|
|
42
|
+
const issues = [];
|
|
43
|
+
for (const key of Object.keys(json)) {
|
|
44
|
+
if (key.startsWith('//') || key === '$schema')
|
|
45
|
+
continue;
|
|
46
|
+
if (!config_1.KNOWN_CONFIG_KEYS.has(key))
|
|
47
|
+
issues.push(`unknown key "${key}"`);
|
|
48
|
+
}
|
|
49
|
+
const sev = json.severity;
|
|
50
|
+
if (sev && typeof sev === 'object') {
|
|
51
|
+
for (const [name, val] of Object.entries(sev)) {
|
|
52
|
+
if (!VALID_SEVERITIES.includes(val)) {
|
|
53
|
+
issues.push(`severity["${name}"] must be error|warn|off (got ${JSON.stringify(val)})`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (issues.length === 0)
|
|
58
|
+
return (0, types_1.pass)();
|
|
59
|
+
issues.slice(0, 10).forEach(i => utils_1.logger.warn(`[Config Validation]: ⚠️ ${i}`));
|
|
60
|
+
const sample = issues.slice(0, 3).join('; ');
|
|
61
|
+
return (0, types_1.warn)(`${issues.length} config issue(s): ${sample}${issues.length > 3 ? ' …' : ''}`);
|
|
62
|
+
},
|
|
63
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.coverageCheck = void 0;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const types_1 = require("../../types");
|
|
10
|
+
const findings_1 = require("../findings");
|
|
11
|
+
/**
|
|
12
|
+
* Common coverage-report locations across languages/tools. Presence of any one
|
|
13
|
+
* means the test step produced coverage. Reports are usually git-ignored, so we
|
|
14
|
+
* probe the working tree with fs, not git. A client with a non-standard path
|
|
15
|
+
* sets `coverage.reportPath`.
|
|
16
|
+
*/
|
|
17
|
+
const DEFAULT_REPORTS = [
|
|
18
|
+
'coverage/lcov.info', // JS/TS (lcov), C++
|
|
19
|
+
'lcov.info',
|
|
20
|
+
'coverage/coverage-final.json', // istanbul
|
|
21
|
+
'coverage/coverage-summary.json',
|
|
22
|
+
'coverage/cobertura-coverage.xml', // Cobertura (JS, Python)
|
|
23
|
+
'coverage/clover.xml',
|
|
24
|
+
'coverage.xml', // Python (pytest-cov / coverage.py)
|
|
25
|
+
'coverage.out', // Go
|
|
26
|
+
'build/reports/jacoco/test/jacocoTestReport.xml', // Kotlin/Java (Gradle)
|
|
27
|
+
'target/site/jacoco/jacoco.xml', // Java (Maven)
|
|
28
|
+
];
|
|
29
|
+
exports.coverageCheck = {
|
|
30
|
+
name: 'Coverage',
|
|
31
|
+
phase: 'informational',
|
|
32
|
+
/**
|
|
33
|
+
* Opt-in: only runs when a repo explicitly enables it (`coverage.enabled:
|
|
34
|
+
* true`). Presence-warning by default everywhere would be pure noise in repos
|
|
35
|
+
* that don't collect coverage — so a client turns it on to say "we produce
|
|
36
|
+
* coverage", and the check then guards against the report silently going
|
|
37
|
+
* missing (a broken `--coverage` flag, tests not running, etc.).
|
|
38
|
+
*/
|
|
39
|
+
applies(ctx) {
|
|
40
|
+
return ctx.config.coverage?.enabled === true;
|
|
41
|
+
},
|
|
42
|
+
async run(ctx) {
|
|
43
|
+
const cfg = ctx.config.coverage;
|
|
44
|
+
const candidates = cfg?.reportPath
|
|
45
|
+
? Array.isArray(cfg.reportPath)
|
|
46
|
+
? cfg.reportPath
|
|
47
|
+
: [cfg.reportPath]
|
|
48
|
+
: DEFAULT_REPORTS;
|
|
49
|
+
const found = candidates.find(rel => {
|
|
50
|
+
try {
|
|
51
|
+
return node_fs_1.default.statSync(node_path_1.default.join(ctx.cwd, rel)).size > 0;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
if (found)
|
|
58
|
+
return (0, types_1.pass)(`coverage report found: ${found}`);
|
|
59
|
+
const sev = (0, findings_1.severityEmitter)(cfg?.severity, 'warn');
|
|
60
|
+
sev.log(`[Coverage]: ${sev.icon} no coverage report found (looked for ${candidates.length} location(s), e.g. ${candidates.slice(0, 3).join(', ')})`);
|
|
61
|
+
return sev.emit('no coverage report found — is the test step running with coverage enabled?');
|
|
62
|
+
},
|
|
63
|
+
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Check } from '
|
|
1
|
+
import { Check } from '../../types';
|
|
2
2
|
export declare const deadCodeCheck: Check;
|
|
@@ -6,10 +6,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.deadCodeCheck = void 0;
|
|
7
7
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
8
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
-
const constants_1 = require("
|
|
10
|
-
const utils_1 = require("
|
|
11
|
-
const execa_1 = require("
|
|
12
|
-
const types_1 = require("
|
|
9
|
+
const constants_1 = require("../../../config/constants");
|
|
10
|
+
const utils_1 = require("../../../utils");
|
|
11
|
+
const execa_1 = require("../../../utils/execa");
|
|
12
|
+
const types_1 = require("../../types");
|
|
13
13
|
exports.deadCodeCheck = {
|
|
14
14
|
name: 'Dead Code',
|
|
15
15
|
phase: 'informational',
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Check } from '
|
|
1
|
+
import { Check } from '../../types';
|
|
2
2
|
export declare const duplicateCheck: Check;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.duplicateCheck = void 0;
|
|
4
|
-
const config_1 = require("
|
|
5
|
-
const constants_1 = require("
|
|
6
|
-
const utils_1 = require("
|
|
7
|
-
const execa_1 = require("
|
|
8
|
-
const targets_1 = require("
|
|
9
|
-
const types_1 = require("
|
|
4
|
+
const config_1 = require("../../../config");
|
|
5
|
+
const constants_1 = require("../../../config/constants");
|
|
6
|
+
const utils_1 = require("../../../utils");
|
|
7
|
+
const execa_1 = require("../../../utils/execa");
|
|
8
|
+
const targets_1 = require("../../targets");
|
|
9
|
+
const types_1 = require("../../types");
|
|
10
10
|
// Always excluded regardless of client config — scanning these never yields
|
|
11
11
|
// meaningful production duplication. Config files (eslint/*.config.*) are data,
|
|
12
12
|
// not logic, and are commonly shipped in two formats (e.g. .eslintrc + flat
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Check } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Requires a license/copyright header (a configured regex) in the first N lines
|
|
4
|
+
* of newly ADDED source files. Opt-in — needs `licenseHeader.pattern`; does
|
|
5
|
+
* nothing until a repo configures one. Advisory (warn).
|
|
6
|
+
*/
|
|
7
|
+
export declare const licenseHeaderCheck: Check;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.licenseHeaderCheck = void 0;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const utils_1 = require("../../../utils");
|
|
10
|
+
const execa_1 = require("../../../utils/execa");
|
|
11
|
+
const types_1 = require("../../types");
|
|
12
|
+
/** Source extensions a license header is expected on. */
|
|
13
|
+
const SOURCE_EXT = /\.(ts|tsx|js|jsx|mjs|cjs|py|kt|java|go|rs|cs|rb|php|swift|c|cc|cpp|h|hpp)$/i;
|
|
14
|
+
const DEFAULT_HEADER_LINES = 10;
|
|
15
|
+
/**
|
|
16
|
+
* Requires a license/copyright header (a configured regex) in the first N lines
|
|
17
|
+
* of newly ADDED source files. Opt-in — needs `licenseHeader.pattern`; does
|
|
18
|
+
* nothing until a repo configures one. Advisory (warn).
|
|
19
|
+
*/
|
|
20
|
+
exports.licenseHeaderCheck = {
|
|
21
|
+
name: 'License Header',
|
|
22
|
+
phase: 'informational',
|
|
23
|
+
applies(ctx) {
|
|
24
|
+
return ctx.config.licenseHeader?.enabled === true && Boolean(ctx.baseSha);
|
|
25
|
+
},
|
|
26
|
+
async run(ctx) {
|
|
27
|
+
const patternSrc = ctx.config.licenseHeader?.pattern;
|
|
28
|
+
if (!patternSrc)
|
|
29
|
+
return (0, types_1.skip)('no licenseHeader.pattern configured');
|
|
30
|
+
let header;
|
|
31
|
+
try {
|
|
32
|
+
header = new RegExp(patternSrc);
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
utils_1.logger.warn(`[License Header]: ⚠️ invalid pattern\n${err}`);
|
|
36
|
+
return (0, types_1.skip)('invalid licenseHeader.pattern');
|
|
37
|
+
}
|
|
38
|
+
const maxLines = ctx.config.licenseHeader?.lines ?? DEFAULT_HEADER_LINES;
|
|
39
|
+
let added;
|
|
40
|
+
try {
|
|
41
|
+
const { stdout } = await (0, execa_1.execa)('git', ['diff', '--name-only', '--diff-filter=A', ctx.baseSha, ctx.headSha ?? 'HEAD'], { cwd: ctx.cwd });
|
|
42
|
+
added = stdout
|
|
43
|
+
.split('\n')
|
|
44
|
+
.filter(Boolean)
|
|
45
|
+
.filter(f => SOURCE_EXT.test(f));
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
utils_1.logger.warn(`[License Header]: ⚠️ Could not analyze diff\n${err}`);
|
|
49
|
+
return (0, types_1.skip)('diff unavailable');
|
|
50
|
+
}
|
|
51
|
+
const missing = [];
|
|
52
|
+
for (const file of added) {
|
|
53
|
+
let head;
|
|
54
|
+
try {
|
|
55
|
+
head = node_fs_1.default
|
|
56
|
+
.readFileSync(node_path_1.default.join(ctx.cwd, file), 'utf-8')
|
|
57
|
+
.split('\n')
|
|
58
|
+
.slice(0, maxLines)
|
|
59
|
+
.join('\n');
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
continue; // removed/renamed between diff and read
|
|
63
|
+
}
|
|
64
|
+
if (!header.test(head))
|
|
65
|
+
missing.push(file);
|
|
66
|
+
}
|
|
67
|
+
if (missing.length === 0)
|
|
68
|
+
return (0, types_1.pass)();
|
|
69
|
+
missing.slice(0, 10).forEach(f => utils_1.logger.warn(`[License Header]: ⚠️ missing header: ${f}`));
|
|
70
|
+
if (missing.length > 10)
|
|
71
|
+
utils_1.logger.warn(`[License Header]: ⚠️ ... and ${missing.length - 10} more`);
|
|
72
|
+
return (0, types_1.warn)(`${missing.length} new source file(s) missing the license header`);
|
|
73
|
+
},
|
|
74
|
+
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Check } from '
|
|
1
|
+
import { Check } from '../../types';
|
|
2
2
|
export declare const markdownLintCheck: Check;
|
|
@@ -7,11 +7,11 @@ exports.markdownLintCheck = void 0;
|
|
|
7
7
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
8
|
const node_os_1 = __importDefault(require("node:os"));
|
|
9
9
|
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
-
const config_1 = require("
|
|
11
|
-
const utils_1 = require("
|
|
12
|
-
const execa_1 = require("
|
|
13
|
-
const targets_1 = require("
|
|
14
|
-
const types_1 = require("
|
|
10
|
+
const config_1 = require("../../../config");
|
|
11
|
+
const utils_1 = require("../../../utils");
|
|
12
|
+
const execa_1 = require("../../../utils/execa");
|
|
13
|
+
const targets_1 = require("../../targets");
|
|
14
|
+
const types_1 = require("../../types");
|
|
15
15
|
function loadUserMarkdownConfig(cwd) {
|
|
16
16
|
const configPath = node_path_1.default.join(cwd, 'pr-checkmate.json');
|
|
17
17
|
if (!node_fs_1.default.existsSync(configPath))
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Check } from '
|
|
1
|
+
import { Check } from '../../types';
|
|
2
2
|
export declare const spellcheckCheck: Check;
|
|
@@ -6,11 +6,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.spellcheckCheck = void 0;
|
|
7
7
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
8
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
-
const config_1 = require("
|
|
10
|
-
const utils_1 = require("
|
|
11
|
-
const execa_1 = require("
|
|
12
|
-
const targets_1 = require("
|
|
13
|
-
const types_1 = require("
|
|
9
|
+
const config_1 = require("../../../config");
|
|
10
|
+
const utils_1 = require("../../../utils");
|
|
11
|
+
const execa_1 = require("../../../utils/execa");
|
|
12
|
+
const targets_1 = require("../../targets");
|
|
13
|
+
const types_1 = require("../../types");
|
|
14
14
|
function loadUserCspellConfig(cwd) {
|
|
15
15
|
const configPath = node_path_1.default.join(cwd, 'pr-checkmate.json');
|
|
16
16
|
if (!node_fs_1.default.existsSync(configPath))
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Check } from '
|
|
1
|
+
import { Check } from '../../types';
|
|
2
2
|
export declare const diffSecurityCheck: Check;
|