pr-checkmate 3.0.3 → 3.1.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/dist/{cli.js → cjs/cli.js} +30 -30
- package/dist/{config → cjs/config}/index.d.ts +2 -2
- package/dist/{config → cjs/config}/index.js +8 -7
- package/dist/{config → cjs/config}/loader.d.ts +1 -1
- package/dist/{config → cjs/config}/loader.js +8 -8
- package/dist/{core → cjs/core}/checks/dependencies/banned-imports.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/dependencies/banned-imports.js +10 -10
- package/dist/{core → cjs/core}/checks/dependencies/circular-deps.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/dependencies/circular-deps.js +27 -27
- package/dist/{core → cjs/core}/checks/dependencies/dependency-check.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/dependencies/dependency-check.js +17 -17
- package/dist/{core → cjs/core}/checks/dependencies/grype-scan.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/dependencies/grype-scan.js +18 -18
- package/dist/{core → cjs/core}/checks/dependencies/license-check.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/dependencies/license-check.js +12 -12
- package/dist/{core → cjs/core}/checks/dependencies/npm-audit.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/dependencies/npm-audit.js +14 -14
- package/dist/{core → cjs/core}/checks/dependencies/outdated-deps.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/dependencies/outdated-deps.js +14 -14
- package/dist/{core → cjs/core}/checks/dependencies/vuln-scan.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/dependencies/vuln-scan.js +14 -14
- package/dist/{core → cjs/core}/checks/findings.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/findings.js +16 -16
- package/dist/{core → cjs/core}/checks/git/custom-rules.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/git/custom-rules.js +19 -19
- package/dist/{core → cjs/core}/checks/git/diff-smell.d.ts +2 -2
- package/dist/{core → cjs/core}/checks/git/diff-smell.js +13 -13
- package/dist/{core → cjs/core}/checks/git/large-files.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/git/large-files.js +15 -15
- package/dist/{core → cjs/core}/checks/git/leftover-debug.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/git/leftover-debug.js +13 -13
- package/dist/{core → cjs/core}/checks/git/lockfile-drift.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/git/lockfile-drift.js +12 -12
- package/dist/{core → cjs/core}/checks/git/merge-conflict.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/git/merge-conflict.js +15 -15
- package/dist/{core → cjs/core}/checks/git/missing-tests.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/git/missing-tests.js +15 -15
- package/dist/{core → cjs/core}/checks/git/todo-fixme.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/git/todo-fixme.js +11 -11
- package/dist/{core → cjs/core}/checks/languages/cpp-format.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/languages/cpp-format.js +18 -18
- package/dist/{core → cjs/core}/checks/languages/external-checks.d.ts +9 -9
- package/dist/{core → cjs/core}/checks/languages/external-checks.js +10 -10
- package/dist/{core → cjs/core}/checks/languages/external-runner.d.ts +2 -2
- package/dist/{core → cjs/core}/checks/languages/external-runner.js +21 -21
- package/dist/{core → cjs/core}/checks/languages/go-format.d.ts +1 -1
- package/dist/cjs/core/checks/languages/go-format.js +202 -0
- package/dist/cjs/core/checks/languages/lint.d.ts +2 -0
- package/dist/{core → cjs/core}/checks/languages/lint.js +21 -21
- package/dist/{core → cjs/core}/checks/languages/prettier.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/languages/prettier.js +18 -18
- package/dist/{core → cjs/core}/checks/languages/python-format.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/languages/python-format.js +14 -14
- package/dist/{core → cjs/core}/checks/languages/python-lint.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/languages/python-lint.js +13 -13
- package/dist/{core → cjs/core}/checks/languages/python-typecheck.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/languages/python-typecheck.js +29 -29
- package/dist/{core → cjs/core}/checks/languages/typecheck.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/languages/typecheck.js +13 -13
- package/dist/{core → cjs/core}/checks/pr/commitlint.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/pr/commitlint.js +12 -12
- package/dist/{core → cjs/core}/checks/pr/pr-body.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/pr/pr-body.js +8 -8
- package/dist/{core → cjs/core}/checks/pr/pr-size-check.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/pr/pr-size-check.js +10 -10
- package/dist/{core → cjs/core}/checks/pr/pr-title-lint.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/pr/pr-title-lint.js +8 -8
- package/dist/{core → cjs/core}/checks/quality/case-collision.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/quality/case-collision.js +7 -7
- package/dist/{core → cjs/core}/checks/quality/config-validation.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/quality/config-validation.js +9 -9
- package/dist/{core → cjs/core}/checks/quality/coverage.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/quality/coverage.js +4 -4
- package/dist/{core → cjs/core}/checks/quality/dead-code.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/quality/dead-code.js +23 -23
- package/dist/{core → cjs/core}/checks/quality/duplicate-check.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/quality/duplicate-check.js +22 -22
- package/dist/{core → cjs/core}/checks/quality/license-header.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/quality/license-header.js +16 -16
- package/dist/{core → cjs/core}/checks/quality/markdown-lint.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/quality/markdown-lint.js +17 -17
- package/dist/{core → cjs/core}/checks/quality/package-size.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/quality/package-size.js +12 -12
- package/dist/{core → cjs/core}/checks/quality/spellcheck.d.ts +2 -2
- package/dist/{core → cjs/core}/checks/quality/spellcheck.js +18 -18
- package/dist/{core → cjs/core}/checks/quality/symlinks.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/quality/symlinks.js +8 -8
- package/dist/{core → cjs/core}/checks/quality/yaml-lint.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/quality/yaml-lint.js +12 -12
- package/dist/{core → cjs/core}/checks/security/diff-security.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/security/diff-security.js +15 -15
- package/dist/{core → cjs/core}/checks/security/dockerfile-security.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/security/dockerfile-security.js +16 -16
- package/dist/{core → cjs/core}/checks/security/migration-safety.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/security/migration-safety.js +17 -17
- package/dist/{core → cjs/core}/checks/security/security.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/security/security.js +21 -21
- package/dist/{core → cjs/core}/checks/security/sensitive-file-guard.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/security/sensitive-file-guard.js +14 -14
- package/dist/{core → cjs/core}/checks/security/workflow-security.d.ts +2 -2
- package/dist/{core → cjs/core}/checks/security/workflow-security.js +14 -14
- package/dist/{core → cjs/core}/checks/tool-install.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/tool-install.js +2 -2
- package/dist/{core → cjs/core}/context.d.ts +1 -1
- package/dist/{core → cjs/core}/context.js +16 -16
- package/dist/cjs/core/index.d.ts +4 -0
- package/dist/{core → cjs/core}/index.js +7 -7
- package/dist/{core → cjs/core}/install/cache.js +2 -2
- package/dist/{core → cjs/core}/install/doctor.d.ts +4 -4
- package/dist/{core → cjs/core}/install/doctor.js +34 -34
- package/dist/{core → cjs/core}/install/ensure.d.ts +2 -2
- package/dist/{core → cjs/core}/install/ensure.js +15 -14
- package/dist/{core → cjs/core}/install/lock.js +4 -4
- package/dist/{core → cjs/core}/install/prepare.d.ts +4 -4
- package/dist/{core → cjs/core}/install/prepare.js +13 -13
- package/dist/{core → cjs/core}/install/profiles.d.ts +2 -2
- package/dist/{core → cjs/core}/install/reuse.d.ts +1 -1
- package/dist/{core → cjs/core}/install/reuse.js +4 -4
- package/dist/{core → cjs/core}/registry.d.ts +1 -1
- package/dist/cjs/core/registry.js +112 -0
- package/dist/{core → cjs/core}/reporters.d.ts +1 -1
- package/dist/{core → cjs/core}/reporters.js +28 -28
- package/dist/{core → cjs/core}/run-checks.d.ts +2 -2
- package/dist/{core → cjs/core}/run-checks.js +31 -31
- package/dist/{core → cjs/core}/targets.d.ts +1 -1
- package/dist/{core → cjs/core}/targets.js +20 -20
- package/dist/{core → cjs/core}/types.d.ts +3 -3
- package/dist/cjs/index.d.ts +12 -0
- package/dist/{index.js → cjs/index.js} +18 -18
- package/dist/{init.js → cjs/init.js} +68 -56
- package/dist/{interfaces → cjs/interfaces}/index.d.ts +3 -3
- package/dist/cjs/package.json +1 -0
- package/dist/{scripts → cjs/scripts}/copy-configs.js +22 -7
- package/dist/{scripts → cjs/scripts}/generate-install-manifests.js +2 -2
- package/dist/{scripts → cjs/scripts}/publish-github.js +4 -4
- package/dist/{utils → cjs/utils}/detect-language.js +12 -12
- package/dist/cjs/utils/execa.js +46 -0
- package/dist/{utils → cjs/utils}/git.js +2 -2
- package/dist/{utils → cjs/utils}/http.js +2 -2
- package/dist/cjs/utils/index.d.ts +15 -0
- package/dist/{utils → cjs/utils}/index.js +13 -13
- package/dist/{utils → cjs/utils}/own-deps.d.ts +2 -0
- package/dist/{utils → cjs/utils}/own-deps.js +1 -0
- package/dist/{utils → cjs/utils}/package-version.js +2 -1
- package/dist/{utils → cjs/utils}/resolve-bin.js +2 -1
- package/dist/{utils → cjs/utils}/update-notifier.js +4 -4
- package/dist/esm/cli.d.ts +2 -0
- package/dist/esm/cli.js +137 -0
- package/dist/esm/config/constants.d.ts +153 -0
- package/dist/esm/config/constants.js +360 -0
- package/dist/esm/config/index.d.ts +40 -0
- package/dist/esm/config/index.js +60 -0
- package/dist/esm/config/loader.d.ts +6 -0
- package/dist/esm/config/loader.js +191 -0
- package/dist/esm/config/pr-checkmate-workflow-docker.yml +79 -0
- package/dist/esm/config/pr-checkmate-workflow.yml +92 -0
- package/dist/esm/core/checks/dependencies/banned-imports.d.ts +2 -0
- package/dist/esm/core/checks/dependencies/banned-imports.js +70 -0
- package/dist/esm/core/checks/dependencies/circular-deps.d.ts +2 -0
- package/dist/esm/core/checks/dependencies/circular-deps.js +155 -0
- package/dist/esm/core/checks/dependencies/dependency-check.d.ts +43 -0
- package/dist/esm/core/checks/dependencies/dependency-check.js +174 -0
- package/dist/esm/core/checks/dependencies/grype-scan.d.ts +22 -0
- package/dist/esm/core/checks/dependencies/grype-scan.js +112 -0
- package/dist/esm/core/checks/dependencies/license-check.d.ts +2 -0
- package/dist/esm/core/checks/dependencies/license-check.js +61 -0
- package/dist/esm/core/checks/dependencies/npm-audit.d.ts +6 -0
- package/dist/esm/core/checks/dependencies/npm-audit.js +80 -0
- package/dist/esm/core/checks/dependencies/outdated-deps.d.ts +2 -0
- package/dist/esm/core/checks/dependencies/outdated-deps.js +66 -0
- package/dist/esm/core/checks/dependencies/vuln-scan.d.ts +2 -0
- package/dist/esm/core/checks/dependencies/vuln-scan.js +54 -0
- package/dist/esm/core/checks/findings.d.ts +299 -0
- package/dist/esm/core/checks/findings.js +701 -0
- package/dist/esm/core/checks/git/custom-rules.d.ts +2 -0
- package/dist/esm/core/checks/git/custom-rules.js +106 -0
- package/dist/esm/core/checks/git/diff-smell.d.ts +19 -0
- package/dist/esm/core/checks/git/diff-smell.js +69 -0
- package/dist/esm/core/checks/git/large-files.d.ts +2 -0
- package/dist/esm/core/checks/git/large-files.js +112 -0
- package/dist/esm/core/checks/git/leftover-debug.d.ts +2 -0
- package/dist/esm/core/checks/git/leftover-debug.js +89 -0
- package/dist/esm/core/checks/git/lockfile-drift.d.ts +2 -0
- package/dist/esm/core/checks/git/lockfile-drift.js +114 -0
- package/dist/esm/core/checks/git/merge-conflict.d.ts +2 -0
- package/dist/esm/core/checks/git/merge-conflict.js +117 -0
- package/dist/esm/core/checks/git/missing-tests.d.ts +2 -0
- package/dist/esm/core/checks/git/missing-tests.js +105 -0
- package/dist/esm/core/checks/git/todo-fixme.d.ts +7 -0
- package/dist/esm/core/checks/git/todo-fixme.js +80 -0
- package/dist/esm/core/checks/languages/cpp-format.d.ts +7 -0
- package/dist/esm/core/checks/languages/cpp-format.js +91 -0
- package/dist/esm/core/checks/languages/external-checks.d.ts +77 -0
- package/dist/esm/core/checks/languages/external-checks.js +197 -0
- package/dist/esm/core/checks/languages/external-runner.d.ts +119 -0
- package/dist/esm/core/checks/languages/external-runner.js +138 -0
- package/dist/esm/core/checks/languages/go-format.d.ts +8 -0
- package/dist/{core → esm/core}/checks/languages/go-format.js +29 -35
- package/dist/esm/core/checks/languages/lint.d.ts +2 -0
- package/dist/esm/core/checks/languages/lint.js +92 -0
- package/dist/esm/core/checks/languages/prettier.d.ts +2 -0
- package/dist/esm/core/checks/languages/prettier.js +85 -0
- package/dist/esm/core/checks/languages/python-format.d.ts +7 -0
- package/dist/esm/core/checks/languages/python-format.js +61 -0
- package/dist/esm/core/checks/languages/python-lint.d.ts +9 -0
- package/dist/esm/core/checks/languages/python-lint.js +55 -0
- package/dist/esm/core/checks/languages/python-typecheck.d.ts +14 -0
- package/dist/esm/core/checks/languages/python-typecheck.js +184 -0
- package/dist/esm/core/checks/languages/ruff-shared.d.ts +10 -0
- package/dist/esm/core/checks/languages/ruff-shared.js +35 -0
- package/dist/esm/core/checks/languages/typecheck.d.ts +2 -0
- package/dist/esm/core/checks/languages/typecheck.js +61 -0
- package/dist/esm/core/checks/pr/commitlint.d.ts +2 -0
- package/dist/esm/core/checks/pr/commitlint.js +102 -0
- package/dist/esm/core/checks/pr/pr-body.d.ts +2 -0
- package/dist/esm/core/checks/pr/pr-body.js +43 -0
- package/dist/esm/core/checks/pr/pr-size-check.d.ts +2 -0
- package/dist/esm/core/checks/pr/pr-size-check.js +42 -0
- package/dist/esm/core/checks/pr/pr-title-lint.d.ts +2 -0
- package/dist/esm/core/checks/pr/pr-title-lint.js +31 -0
- package/dist/esm/core/checks/quality/case-collision.d.ts +8 -0
- package/dist/esm/core/checks/quality/case-collision.js +39 -0
- package/dist/esm/core/checks/quality/config-validation.d.ts +11 -0
- package/dist/esm/core/checks/quality/config-validation.js +188 -0
- package/dist/esm/core/checks/quality/coverage.d.ts +2 -0
- package/dist/esm/core/checks/quality/coverage.js +62 -0
- package/dist/esm/core/checks/quality/dead-code.d.ts +2 -0
- package/dist/esm/core/checks/quality/dead-code.js +124 -0
- package/dist/esm/core/checks/quality/duplicate-check.d.ts +2 -0
- package/dist/esm/core/checks/quality/duplicate-check.js +141 -0
- package/dist/esm/core/checks/quality/license-header.d.ts +7 -0
- package/dist/esm/core/checks/quality/license-header.js +81 -0
- package/dist/esm/core/checks/quality/markdown-lint.d.ts +2 -0
- package/dist/esm/core/checks/quality/markdown-lint.js +104 -0
- package/dist/esm/core/checks/quality/package-size.d.ts +36 -0
- package/dist/esm/core/checks/quality/package-size.js +196 -0
- package/dist/esm/core/checks/quality/spellcheck.d.ts +77 -0
- package/dist/esm/core/checks/quality/spellcheck.js +296 -0
- package/dist/esm/core/checks/quality/symlinks.d.ts +16 -0
- package/dist/esm/core/checks/quality/symlinks.js +57 -0
- package/dist/esm/core/checks/quality/yaml-lint.d.ts +20 -0
- package/dist/esm/core/checks/quality/yaml-lint.js +116 -0
- package/dist/esm/core/checks/security/diff-security.d.ts +2 -0
- package/dist/esm/core/checks/security/diff-security.js +354 -0
- package/dist/esm/core/checks/security/dockerfile-security.d.ts +2 -0
- package/dist/esm/core/checks/security/dockerfile-security.js +98 -0
- package/dist/esm/core/checks/security/migration-safety.d.ts +2 -0
- package/dist/esm/core/checks/security/migration-safety.js +137 -0
- package/dist/esm/core/checks/security/security.d.ts +63 -0
- package/dist/esm/core/checks/security/security.js +201 -0
- package/dist/esm/core/checks/security/sensitive-file-guard.d.ts +2 -0
- package/dist/esm/core/checks/security/sensitive-file-guard.js +160 -0
- package/dist/esm/core/checks/security/workflow-security.d.ts +12 -0
- package/dist/esm/core/checks/security/workflow-security.js +100 -0
- package/dist/esm/core/checks/tool-install.d.ts +102 -0
- package/dist/esm/core/checks/tool-install.js +66 -0
- package/dist/esm/core/commands.d.ts +27 -0
- package/dist/esm/core/commands.js +89 -0
- package/dist/esm/core/context.d.ts +62 -0
- package/dist/esm/core/context.js +241 -0
- package/dist/esm/core/index.d.ts +4 -0
- package/dist/esm/core/index.js +4 -0
- package/dist/esm/core/install/cache.d.ts +58 -0
- package/dist/esm/core/install/cache.js +142 -0
- package/dist/esm/core/install/doctor.d.ts +35 -0
- package/dist/esm/core/install/doctor.js +164 -0
- package/dist/esm/core/install/ensure.d.ts +77 -0
- package/dist/esm/core/install/ensure.js +269 -0
- package/dist/esm/core/install/lock.d.ts +34 -0
- package/dist/esm/core/install/lock.js +92 -0
- package/dist/esm/core/install/merge.d.ts +47 -0
- package/dist/esm/core/install/merge.js +85 -0
- package/dist/esm/core/install/prepare.d.ts +76 -0
- package/dist/esm/core/install/prepare.js +142 -0
- package/dist/esm/core/install/profiles.d.ts +78 -0
- package/dist/esm/core/install/profiles.js +192 -0
- package/dist/esm/core/install/reuse.d.ts +41 -0
- package/dist/esm/core/install/reuse.js +100 -0
- package/dist/esm/core/registry.d.ts +6 -0
- package/dist/esm/core/registry.js +109 -0
- package/dist/esm/core/reporters.d.ts +18 -0
- package/dist/esm/core/reporters.js +266 -0
- package/dist/esm/core/run-checks.d.ts +33 -0
- package/dist/esm/core/run-checks.js +293 -0
- package/dist/esm/core/targets.d.ts +140 -0
- package/dist/esm/core/targets.js +213 -0
- package/dist/esm/core/types.d.ts +195 -0
- package/dist/esm/core/types.js +38 -0
- package/dist/esm/index.d.ts +12 -0
- package/dist/esm/index.js +15 -0
- package/dist/esm/init.d.ts +38 -0
- package/dist/esm/init.js +421 -0
- package/dist/esm/interfaces/index.d.ts +432 -0
- package/dist/esm/interfaces/index.js +2 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/scripts/copy-configs.d.ts +1 -0
- package/dist/esm/scripts/copy-configs.js +64 -0
- package/dist/esm/scripts/generate-install-manifests.d.ts +39 -0
- package/dist/esm/scripts/generate-install-manifests.js +115 -0
- package/dist/esm/scripts/publish-github.d.ts +1 -0
- package/dist/esm/scripts/publish-github.js +45 -0
- package/dist/esm/utils/ci.d.ts +11 -0
- package/dist/esm/utils/ci.js +40 -0
- package/dist/esm/utils/detect-language.d.ts +48 -0
- package/dist/esm/utils/detect-language.js +234 -0
- package/dist/esm/utils/direct-deps.d.ts +21 -0
- package/dist/esm/utils/direct-deps.js +220 -0
- package/dist/esm/utils/execa.d.ts +22 -0
- package/dist/{utils → esm/utils}/execa.js +1 -4
- package/dist/esm/utils/git.d.ts +14 -0
- package/dist/esm/utils/git.js +21 -0
- package/dist/esm/utils/glob.d.ts +24 -0
- package/dist/esm/utils/glob.js +40 -0
- package/dist/esm/utils/http.d.ts +59 -0
- package/dist/esm/utils/http.js +115 -0
- package/dist/esm/utils/index.d.ts +15 -0
- package/dist/esm/utils/index.js +26 -0
- package/dist/esm/utils/logger.d.ts +65 -0
- package/dist/esm/utils/logger.js +157 -0
- package/dist/esm/utils/own-deps.d.ts +16 -0
- package/dist/esm/utils/own-deps.js +107 -0
- package/dist/esm/utils/package-version.d.ts +4 -0
- package/dist/esm/utils/package-version.js +38 -0
- package/dist/esm/utils/pool.d.ts +49 -0
- package/dist/esm/utils/pool.js +113 -0
- package/dist/esm/utils/resolve-bin.d.ts +67 -0
- package/dist/esm/utils/resolve-bin.js +156 -0
- package/dist/esm/utils/result-collector.d.ts +33 -0
- package/dist/esm/utils/result-collector.js +44 -0
- package/dist/esm/utils/update-notifier.d.ts +19 -0
- package/dist/esm/utils/update-notifier.js +108 -0
- package/install-manifests/core/package-lock.json +4 -4
- package/install-manifests/core/package.json +1 -1
- package/install-manifests/cpp/package-lock.json +4 -4
- package/install-manifests/cpp/package.json +1 -1
- package/package.json +16 -14
- package/dist/core/checks/languages/lint.d.ts +0 -2
- package/dist/core/index.d.ts +0 -4
- package/dist/core/registry.js +0 -112
- package/dist/index.d.ts +0 -12
- package/dist/utils/index.d.ts +0 -15
- /package/dist/{cli.d.ts → cjs/cli.d.ts} +0 -0
- /package/dist/{config → cjs/config}/constants.d.ts +0 -0
- /package/dist/{config → cjs/config}/constants.js +0 -0
- /package/dist/{config → cjs/config}/pr-checkmate-workflow-docker.yml +0 -0
- /package/dist/{config → cjs/config}/pr-checkmate-workflow.yml +0 -0
- /package/dist/{core → cjs/core}/checks/languages/ruff-shared.d.ts +0 -0
- /package/dist/{core → cjs/core}/checks/languages/ruff-shared.js +0 -0
- /package/dist/{core → cjs/core}/commands.d.ts +0 -0
- /package/dist/{core → cjs/core}/commands.js +0 -0
- /package/dist/{core → cjs/core}/install/cache.d.ts +0 -0
- /package/dist/{core → cjs/core}/install/lock.d.ts +0 -0
- /package/dist/{core → cjs/core}/install/merge.d.ts +0 -0
- /package/dist/{core → cjs/core}/install/merge.js +0 -0
- /package/dist/{core → cjs/core}/install/profiles.js +0 -0
- /package/dist/{core → cjs/core}/types.js +0 -0
- /package/dist/{init.d.ts → cjs/init.d.ts} +0 -0
- /package/dist/{interfaces → cjs/interfaces}/index.js +0 -0
- /package/dist/{scripts → cjs/scripts}/copy-configs.d.ts +0 -0
- /package/dist/{scripts → cjs/scripts}/generate-install-manifests.d.ts +0 -0
- /package/dist/{scripts → cjs/scripts}/publish-github.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/ci.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/ci.js +0 -0
- /package/dist/{utils → cjs/utils}/detect-language.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/direct-deps.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/direct-deps.js +0 -0
- /package/dist/{utils → cjs/utils}/execa.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/git.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/glob.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/glob.js +0 -0
- /package/dist/{utils → cjs/utils}/http.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/logger.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/logger.js +0 -0
- /package/dist/{utils → cjs/utils}/package-version.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/pool.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/pool.js +0 -0
- /package/dist/{utils → cjs/utils}/resolve-bin.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/result-collector.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/result-collector.js +0 -0
- /package/dist/{utils → cjs/utils}/update-notifier.d.ts +0 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Check } from '../../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Lints changed Python files with Ruff, bundled as a self-contained WASM module
|
|
4
|
+
* (`@astral-sh/ruff-wasm-nodejs`) so it runs on a bare Node image with no Python
|
|
5
|
+
* or pip install. Informational by design — reports issues without failing the
|
|
6
|
+
* build, matching how formatting checks roll out; promote to blocking per repo
|
|
7
|
+
* once teams have adopted it. Uses Ruff's default rule set (pyflakes + pycodestyle).
|
|
8
|
+
*/
|
|
9
|
+
export declare const pythonLintCheck: Check;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { logger } from '../../../utils/index.js';
|
|
4
|
+
import { resolveTargetFiles } from '../../targets.js';
|
|
5
|
+
import { pass, warn, skip } from '../../types.js';
|
|
6
|
+
import { PY_GLOBS, createRuffWorkspace } from './ruff-shared.js';
|
|
7
|
+
/**
|
|
8
|
+
* Lints changed Python files with Ruff, bundled as a self-contained WASM module
|
|
9
|
+
* (`@astral-sh/ruff-wasm-nodejs`) so it runs on a bare Node image with no Python
|
|
10
|
+
* or pip install. Informational by design — reports issues without failing the
|
|
11
|
+
* build, matching how formatting checks roll out; promote to blocking per repo
|
|
12
|
+
* once teams have adopted it. Uses Ruff's default rule set (pyflakes + pycodestyle).
|
|
13
|
+
*/
|
|
14
|
+
export const pythonLintCheck = {
|
|
15
|
+
name: 'Ruff Lint',
|
|
16
|
+
phase: 'informational',
|
|
17
|
+
applies(ctx) {
|
|
18
|
+
return (ctx.config.python?.enabled !== false &&
|
|
19
|
+
ctx.config.python?.ruff?.lint !== false &&
|
|
20
|
+
ctx.languages.includes('python'));
|
|
21
|
+
},
|
|
22
|
+
async run(ctx) {
|
|
23
|
+
const targets = await resolveTargetFiles(ctx, PY_GLOBS);
|
|
24
|
+
if (targets === null)
|
|
25
|
+
return skip('git unavailable');
|
|
26
|
+
if (targets.length === 0)
|
|
27
|
+
return pass('no Python files changed');
|
|
28
|
+
const workspace = createRuffWorkspace();
|
|
29
|
+
let totalIssues = 0;
|
|
30
|
+
let filesWithIssues = 0;
|
|
31
|
+
for (const rel of targets) {
|
|
32
|
+
let content;
|
|
33
|
+
try {
|
|
34
|
+
content = fs.readFileSync(path.join(ctx.cwd, rel), 'utf-8');
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
continue; // renamed/removed between diff and read — skip
|
|
38
|
+
}
|
|
39
|
+
const diagnostics = workspace.check(content);
|
|
40
|
+
if (diagnostics.length === 0)
|
|
41
|
+
continue;
|
|
42
|
+
filesWithIssues += 1;
|
|
43
|
+
totalIssues += diagnostics.length;
|
|
44
|
+
logger.warn(`[Ruff Lint]: ⚠️ ${rel}: ${diagnostics.length} issue(s)`);
|
|
45
|
+
diagnostics
|
|
46
|
+
.slice(0, 5)
|
|
47
|
+
.forEach((d) => logger.warn(` ${rel}:${d.start_location.row} ${d.code ?? '?'} ${d.message}`));
|
|
48
|
+
if (diagnostics.length > 5)
|
|
49
|
+
logger.warn(` ... and ${diagnostics.length - 5} more`);
|
|
50
|
+
}
|
|
51
|
+
if (totalIssues === 0)
|
|
52
|
+
return pass();
|
|
53
|
+
return warn(`${totalIssues} issue(s) in ${filesWithIssues} file(s)`);
|
|
54
|
+
},
|
|
55
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Check } from '../../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Type-checks changed Python files — the Python analogue of `tsc --noEmit`.
|
|
4
|
+
*
|
|
5
|
+
* Two checkers, and the order is the policy. **mypy first**, because a repository
|
|
6
|
+
* that installed mypy configured it too (`mypy.ini`, `[tool.mypy]`), and its
|
|
7
|
+
* settled opinion about its own code beats ours. **Our bundled pyright
|
|
8
|
+
* otherwise**, which is what stopped `⏭️ mypy/pyright not installed` from being
|
|
9
|
+
* the answer on every runner: pyright is a Node bundle carrying its own typeshed,
|
|
10
|
+
* so it needs neither Python nor pip. Force either with `python.typeChecker`.
|
|
11
|
+
*
|
|
12
|
+
* Informational by design, like Ruff lint, so teams can adopt gradually.
|
|
13
|
+
*/
|
|
14
|
+
export declare const pythonTypecheckCheck: Check;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { logger, resolvePackageBin } from '../../../utils/index.js';
|
|
4
|
+
import { resolveTargetFiles } from '../../targets.js';
|
|
5
|
+
import { pass, skip, warn } from '../../types.js';
|
|
6
|
+
import { logSample } from '../findings.js';
|
|
7
|
+
import { notInstalled } from '../tool-install.js';
|
|
8
|
+
import { runTool } from './external-runner.js';
|
|
9
|
+
import { PY_GLOBS } from './ruff-shared.js';
|
|
10
|
+
/** How many diagnostics reach the log before the rest are counted instead. */
|
|
11
|
+
const MAX_LOGGED = 10;
|
|
12
|
+
/** The check's display name — the log prefix, and the row in the report. */
|
|
13
|
+
const NAME = 'Python Types';
|
|
14
|
+
/**
|
|
15
|
+
* Diagnostics that mean pyright could not see the repository's dependencies.
|
|
16
|
+
*
|
|
17
|
+
* Their presence is a verdict about the *setup*, not about the code, and the
|
|
18
|
+
* first attempt at this got it backwards: it dropped these two rules and
|
|
19
|
+
* reported everything else. That removes the cause and keeps the consequences,
|
|
20
|
+
* which is worse than either extreme — on a real client repository (ticket 076)
|
|
21
|
+
* it produced fifteen confident "type errors" of which nine were one cascade:
|
|
22
|
+
*
|
|
23
|
+
* ```python
|
|
24
|
+
* @click.group()
|
|
25
|
+
* def main() -> None: ...
|
|
26
|
+
*
|
|
27
|
+
* @main.command("list-jobs") # nine of these
|
|
28
|
+
* def list_jobs() -> None: ...
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* With `click` absent, pyright sees `main` as a plain `FunctionType` and every
|
|
32
|
+
* `@main.command(...)` becomes an error. Pyright is answering correctly; the
|
|
33
|
+
* question is wrong. The same shape follows from typer, flask, celery and pytest
|
|
34
|
+
* fixtures — most Python projects, in any CI job that does not install first.
|
|
35
|
+
*
|
|
36
|
+
* So an unresolved import means we cannot type-check at all, and the honest
|
|
37
|
+
* answer is a skip that says so. That is exactly what the TypeScript check does
|
|
38
|
+
* with a missing `node_modules`, in the same words.
|
|
39
|
+
*/
|
|
40
|
+
const UNRESOLVED_IMPORT_RULES = new Set(['reportMissingImports', 'reportMissingModuleSource']);
|
|
41
|
+
/** How many unresolved module names the skip message names before stopping. */
|
|
42
|
+
const NAMED_IMPORTS = 3;
|
|
43
|
+
/** The module a `reportMissingImports` diagnostic is about, for the skip message. */
|
|
44
|
+
function unresolvedModule(message) {
|
|
45
|
+
return /"([^"]+)"/.exec(message)?.[1] ?? null;
|
|
46
|
+
}
|
|
47
|
+
/** Whether the repository configures pyright itself. */
|
|
48
|
+
function hasOwnPyrightConfig(cwd) {
|
|
49
|
+
if (fs.existsSync(path.join(cwd, 'pyrightconfig.json')))
|
|
50
|
+
return true;
|
|
51
|
+
try {
|
|
52
|
+
return fs.readFileSync(path.join(cwd, 'pyproject.toml'), 'utf-8').includes('[tool.pyright]');
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/** Where our copy of pyright lives — bundled, or in a fetched profile. */
|
|
59
|
+
function resolvePyright() {
|
|
60
|
+
try {
|
|
61
|
+
return resolvePackageBin('pyright', 'index.js');
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/** Read mypy's text output: one diagnostic per line, with its own final count. */
|
|
68
|
+
function reportMypy(output) {
|
|
69
|
+
const lines = output.split('\n').filter(line => /\berror\b|\bwarning\b/i.test(line));
|
|
70
|
+
if (lines.length === 0)
|
|
71
|
+
return pass();
|
|
72
|
+
// "Found 3 errors in 1 file (checked 12 source files)" — mypy's own count says
|
|
73
|
+
// more than a tally of lines that merely contained the word.
|
|
74
|
+
const summary = lines.find(line => /found\s+\d+\s+error/i.test(line))?.trim();
|
|
75
|
+
logSample(NAME, 'type issues (mypy):', lines);
|
|
76
|
+
return warn(summary ?? `${lines.length} type issue(s)`);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Type-check with our own pyright, and report only what the client can act on.
|
|
80
|
+
*
|
|
81
|
+
* Pyright is a Node bundle, so it runs through `process.execPath` rather than as
|
|
82
|
+
* a binary on the path — the same reason clang-format does.
|
|
83
|
+
*/
|
|
84
|
+
function reportPyright(ctx, stdout) {
|
|
85
|
+
let report;
|
|
86
|
+
try {
|
|
87
|
+
report = JSON.parse(stdout);
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Pyright exits non-zero for a bad invocation too, and calling that a type
|
|
91
|
+
// error would put a finding in the report that is really our own bug.
|
|
92
|
+
logger.warn(`[${NAME}]: ⚠️ pyright produced no readable report`);
|
|
93
|
+
return skip('pyright produced no readable report');
|
|
94
|
+
}
|
|
95
|
+
const diagnostics = (report.generalDiagnostics ?? []).filter(diagnostic => diagnostic.severity !== 'information');
|
|
96
|
+
// Nothing downstream of an unresolved import can be trusted, so this is
|
|
97
|
+
// checked before anything is reported — and skipped rather than filtered.
|
|
98
|
+
//
|
|
99
|
+
// Not applied to a repository that configures pyright itself: having written
|
|
100
|
+
// `pyrightconfig.json` (or a `[tool.pyright]` section) is having an opinion
|
|
101
|
+
// about import resolution — a `venvPath`, or these rules downgraded on
|
|
102
|
+
// purpose — and overriding it with a skip would ignore the one client who
|
|
103
|
+
// said what they wanted.
|
|
104
|
+
const unresolved = diagnostics.filter(diagnostic => UNRESOLVED_IMPORT_RULES.has(diagnostic.rule ?? ''));
|
|
105
|
+
if (unresolved.length > 0 && !hasOwnPyrightConfig(ctx.cwd)) {
|
|
106
|
+
const modules = [
|
|
107
|
+
...new Set(unresolved
|
|
108
|
+
.map(diagnostic => unresolvedModule(diagnostic.message))
|
|
109
|
+
.filter((name) => Boolean(name))),
|
|
110
|
+
];
|
|
111
|
+
const named = modules.slice(0, NAMED_IMPORTS).join(', ');
|
|
112
|
+
const rest = modules.length > NAMED_IMPORTS ? ` and ${modules.length - NAMED_IMPORTS} more` : '';
|
|
113
|
+
logger.warn(`[${NAME}]: ⚠️ ${unresolved.length} import(s) could not be resolved — not type-checking`);
|
|
114
|
+
return skip(`project dependencies not installed (${named || `${unresolved.length} import(s)`}${rest}) ` +
|
|
115
|
+
'— run `pip install` before typecheck');
|
|
116
|
+
}
|
|
117
|
+
if (diagnostics.length === 0) {
|
|
118
|
+
logger.info(`[${NAME}]: ✅ No type errors (pyright)`);
|
|
119
|
+
return pass();
|
|
120
|
+
}
|
|
121
|
+
const errors = diagnostics.filter(diagnostic => diagnostic.severity === 'error').length;
|
|
122
|
+
const summary = `${errors} error(s), ${diagnostics.length - errors} warning(s)`;
|
|
123
|
+
logSample(NAME, `type issues (pyright): ${summary}`, diagnostics.slice(0, MAX_LOGGED).map(diagnostic => {
|
|
124
|
+
const rel = path.relative(ctx.cwd, diagnostic.file) || diagnostic.file;
|
|
125
|
+
// Pyright counts lines from zero; every other tool in the report counts
|
|
126
|
+
// from one, and a line number that is off by one is worse than none.
|
|
127
|
+
const line = (diagnostic.range?.start?.line ?? 0) + 1;
|
|
128
|
+
return `${rel}:${line} ${diagnostic.severity}: ${diagnostic.message.split('\n')[0]}`;
|
|
129
|
+
}));
|
|
130
|
+
return warn(summary);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Type-checks changed Python files — the Python analogue of `tsc --noEmit`.
|
|
134
|
+
*
|
|
135
|
+
* Two checkers, and the order is the policy. **mypy first**, because a repository
|
|
136
|
+
* that installed mypy configured it too (`mypy.ini`, `[tool.mypy]`), and its
|
|
137
|
+
* settled opinion about its own code beats ours. **Our bundled pyright
|
|
138
|
+
* otherwise**, which is what stopped `⏭️ mypy/pyright not installed` from being
|
|
139
|
+
* the answer on every runner: pyright is a Node bundle carrying its own typeshed,
|
|
140
|
+
* so it needs neither Python nor pip. Force either with `python.typeChecker`.
|
|
141
|
+
*
|
|
142
|
+
* Informational by design, like Ruff lint, so teams can adopt gradually.
|
|
143
|
+
*/
|
|
144
|
+
export const pythonTypecheckCheck = {
|
|
145
|
+
name: NAME,
|
|
146
|
+
phase: 'informational',
|
|
147
|
+
applies(ctx) {
|
|
148
|
+
return (ctx.config.python?.enabled !== false &&
|
|
149
|
+
ctx.config.python?.typecheck !== false &&
|
|
150
|
+
ctx.languages.includes('python'));
|
|
151
|
+
},
|
|
152
|
+
async run(ctx) {
|
|
153
|
+
const targets = await resolveTargetFiles(ctx, PY_GLOBS);
|
|
154
|
+
if (targets === null)
|
|
155
|
+
return skip('git unavailable');
|
|
156
|
+
if (targets.length === 0)
|
|
157
|
+
return pass('no Python files changed');
|
|
158
|
+
const forced = ctx.config.python?.typeChecker;
|
|
159
|
+
if (forced !== 'pyright') {
|
|
160
|
+
const mypy = await runTool(ctx, 'mypy', targets);
|
|
161
|
+
if (!mypy.missing) {
|
|
162
|
+
if (mypy.exitCode === 0) {
|
|
163
|
+
logger.info(`[${NAME}]: ✅ No type errors (mypy)`);
|
|
164
|
+
return pass();
|
|
165
|
+
}
|
|
166
|
+
return reportMypy([mypy.stdout, mypy.stderr].filter(Boolean).join('\n'));
|
|
167
|
+
}
|
|
168
|
+
// Asking for mypy by name and not having it is a configuration error the
|
|
169
|
+
// client meant to make visible; falling back to pyright would hide it.
|
|
170
|
+
if (forced === 'mypy')
|
|
171
|
+
return notInstalled('mypy', 'mypy');
|
|
172
|
+
}
|
|
173
|
+
const entry = resolvePyright();
|
|
174
|
+
if (!entry)
|
|
175
|
+
return notInstalled('pyright', 'pyright');
|
|
176
|
+
const result = await runTool(ctx, process.execPath, [entry, '--outputjson', ...targets]);
|
|
177
|
+
// The binary here is the Node running this process, so `missing` is not a
|
|
178
|
+
// reachable state — it is a case of the type, folded in rather than asserted
|
|
179
|
+
// away.
|
|
180
|
+
if (result.missing)
|
|
181
|
+
return notInstalled('pyright', 'pyright');
|
|
182
|
+
return reportPyright(ctx, result.stdout);
|
|
183
|
+
},
|
|
184
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type RuffModule = typeof import('@astral-sh/ruff-wasm-nodejs');
|
|
2
|
+
type RuffWorkspace = InstanceType<RuffModule['Workspace']>;
|
|
3
|
+
export declare const PY_GLOBS: string[];
|
|
4
|
+
/**
|
|
5
|
+
* Instantiate a Ruff WASM workspace. Shared by the Ruff lint and format checks so
|
|
6
|
+
* their setup stays identical, and kept as a function (not a module-level
|
|
7
|
+
* singleton) so the WASM module loads only when a check runs.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createRuffWorkspace(): RuffWorkspace;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from 'node:module';
|
|
2
|
+
const require = __createRequire(import.meta.url);
|
|
3
|
+
export const PY_GLOBS = ['*.py'];
|
|
4
|
+
/**
|
|
5
|
+
* The rules we lint Python with — pinned here rather than left to Ruff's defaults.
|
|
6
|
+
*
|
|
7
|
+
* `E4`/`E7`/`E9` (import placement, statement style, syntax) plus `F` (pyflakes:
|
|
8
|
+
* undefined names, unused imports, unreachable code) — the set Ruff itself
|
|
9
|
+
* shipped as its default through 0.15.
|
|
10
|
+
*
|
|
11
|
+
* Written down because leaving it implicit made our verdict change under us.
|
|
12
|
+
* Ruff 0.16 added the isort rules (`I`) to its defaults, and a routine dependency
|
|
13
|
+
* bump turned that into a 5- to 48-fold increase in findings across seventeen
|
|
14
|
+
* Python repositories — every one of them `I001`, "import block is un-sorted".
|
|
15
|
+
* Two repositories went from a clean report to a warning on code nobody had
|
|
16
|
+
* touched. Import order is a matter of taste, and a check that fires on every
|
|
17
|
+
* file in a repository is how people learn to ignore the whole report.
|
|
18
|
+
*
|
|
19
|
+
* Adding a rule to this list is a decision with a measurement behind it, which
|
|
20
|
+
* is the point: it is ours to make, not our dependency's to make for us.
|
|
21
|
+
*/
|
|
22
|
+
const SELECTED_RULES = ['E4', 'E7', 'E9', 'F'];
|
|
23
|
+
/**
|
|
24
|
+
* Instantiate a Ruff WASM workspace. Shared by the Ruff lint and format checks so
|
|
25
|
+
* their setup stays identical, and kept as a function (not a module-level
|
|
26
|
+
* singleton) so the WASM module loads only when a check runs.
|
|
27
|
+
*/
|
|
28
|
+
export function createRuffWorkspace() {
|
|
29
|
+
const { Workspace, PositionEncoding } = require('@astral-sh/ruff-wasm-nodejs');
|
|
30
|
+
const settings = {
|
|
31
|
+
...Workspace.defaultSettings(),
|
|
32
|
+
lint: { select: SELECTED_RULES },
|
|
33
|
+
};
|
|
34
|
+
return new Workspace(settings, PositionEncoding.Utf16);
|
|
35
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { execa } from '../../../utils/execa.js';
|
|
4
|
+
import { logger, resolvePackageBin } from '../../../utils/index.js';
|
|
5
|
+
import { clientToolPaths } from '../../install/reuse.js';
|
|
6
|
+
import { pass, fail, warn, skip } from '../../types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Prefer the consumer project's own TypeScript so its tsconfig is compiled by the
|
|
9
|
+
* version it was written for; fall back to the compiler bundled with pr-checkmate.
|
|
10
|
+
*/
|
|
11
|
+
function resolveTsc(ctx) {
|
|
12
|
+
// `clientOwnsConfig` unconditionally: this check does not apply without a
|
|
13
|
+
// `tsconfig.json` in the repository, so the compiler their config was written
|
|
14
|
+
// for is always theirs. `install.reuseLocal: "off"` still overrides, for a
|
|
15
|
+
// client who wants our pinned compiler for reproducibility.
|
|
16
|
+
return resolvePackageBin('typescript', 'bin/tsc', {
|
|
17
|
+
paths: clientToolPaths('typescript', ctx, { clientOwnsConfig: true }),
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export const typecheckCheck = {
|
|
21
|
+
name: 'TypeScript',
|
|
22
|
+
phase: 'blocking',
|
|
23
|
+
weight: 'heavy',
|
|
24
|
+
applies(ctx) {
|
|
25
|
+
if (ctx.config.typecheck?.enabled === false)
|
|
26
|
+
return false;
|
|
27
|
+
if (!ctx.languages.includes('typescript'))
|
|
28
|
+
return false;
|
|
29
|
+
return fs.existsSync(path.join(ctx.cwd, 'tsconfig.json'));
|
|
30
|
+
},
|
|
31
|
+
async run(ctx) {
|
|
32
|
+
// tsc needs the project's installed type declarations — everything listed in
|
|
33
|
+
// tsconfig's `types`, plus every imported @types package — to resolve. When the
|
|
34
|
+
// project's dependencies aren't installed (e.g. a CI step that runs pr-checkmate
|
|
35
|
+
// via npx without a prior `npm ci`), tsc emits a wall of cryptic TS2688
|
|
36
|
+
// "cannot find type definition file" errors that look like code problems but are
|
|
37
|
+
// really a setup gap. Skip with an actionable message instead of failing the PR.
|
|
38
|
+
if (!fs.existsSync(path.join(ctx.cwd, 'node_modules'))) {
|
|
39
|
+
return skip('project dependencies not installed (no node_modules) — run `npm ci` before typecheck');
|
|
40
|
+
}
|
|
41
|
+
const tscBin = resolveTsc(ctx);
|
|
42
|
+
const result = await execa(process.execPath, [tscBin, '--noEmit'], {
|
|
43
|
+
cwd: ctx.cwd,
|
|
44
|
+
reject: false,
|
|
45
|
+
});
|
|
46
|
+
if (result.exitCode === 0)
|
|
47
|
+
return pass();
|
|
48
|
+
const output = [result.stdout, result.stderr].filter(Boolean).join('\n');
|
|
49
|
+
const errorCount = (output.match(/error TS\d+/g) ?? []).length;
|
|
50
|
+
if (output)
|
|
51
|
+
logger.warn(output);
|
|
52
|
+
// A non-zero exit with no diagnostic in it is not a type error — tsc was
|
|
53
|
+
// killed (OOM on a large project), crashed, or never started. Reporting that
|
|
54
|
+
// as `0 type error(s)` blocked PRs with a message naming nothing to fix.
|
|
55
|
+
if (errorCount === 0) {
|
|
56
|
+
logger.warn(`[TypeScript]: ⚠️ tsc exited ${result.exitCode ?? 'abnormally'} without reporting a type error — treating as a tooling failure, not a type error`);
|
|
57
|
+
return warn(`tsc failed to run (exit ${result.exitCode ?? 'killed'})`);
|
|
58
|
+
}
|
|
59
|
+
return fail(`${errorCount} type error(s)`);
|
|
60
|
+
},
|
|
61
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { hasLocalConfig } from '../../../config/index.js';
|
|
5
|
+
import { execa } from '../../../utils/execa.js';
|
|
6
|
+
import { logger, resolveGitRef, resolvePackageBin } from '../../../utils/index.js';
|
|
7
|
+
import { pass, skip, warn } from '../../types.js';
|
|
8
|
+
const LOCAL_CONFIG_FILES = [
|
|
9
|
+
'commitlint.config.cjs',
|
|
10
|
+
'commitlint.config.js',
|
|
11
|
+
'commitlint.config.mjs',
|
|
12
|
+
'commitlint.config.ts',
|
|
13
|
+
'.commitlintrc',
|
|
14
|
+
'.commitlintrc.json',
|
|
15
|
+
'.commitlintrc.yaml',
|
|
16
|
+
'.commitlintrc.yml',
|
|
17
|
+
'.commitlintrc.js',
|
|
18
|
+
'.commitlintrc.cjs',
|
|
19
|
+
];
|
|
20
|
+
const DEFAULT_TYPES = [
|
|
21
|
+
'feat',
|
|
22
|
+
'fix',
|
|
23
|
+
'docs',
|
|
24
|
+
'chore',
|
|
25
|
+
'ci',
|
|
26
|
+
'refactor',
|
|
27
|
+
'perf',
|
|
28
|
+
'style',
|
|
29
|
+
'revert',
|
|
30
|
+
'test',
|
|
31
|
+
'build',
|
|
32
|
+
];
|
|
33
|
+
const DEFAULT_IGNORES = ['^Release\\b', '^chore\\(release\\):'];
|
|
34
|
+
function buildTempConfig(types, ignores) {
|
|
35
|
+
// Emit a CJS module so `ignores` can hold functions — commitlint requires
|
|
36
|
+
// predicate functions there, which a JSON config cannot express.
|
|
37
|
+
// Resolve config-conventional via Node module resolution — robust to hoisting.
|
|
38
|
+
const configConventional = require.resolve('@commitlint/config-conventional');
|
|
39
|
+
const content = `const patterns = ${JSON.stringify(ignores)}.map((p) => new RegExp(p, 'i'));
|
|
40
|
+
module.exports = {
|
|
41
|
+
extends: [${JSON.stringify(configConventional)}],
|
|
42
|
+
rules: { 'type-enum': [2, 'always', ${JSON.stringify(types)}] },
|
|
43
|
+
ignores: [(commit) => patterns.some((re) => re.test(commit))],
|
|
44
|
+
};
|
|
45
|
+
`;
|
|
46
|
+
const tmpFile = path.join(os.tmpdir(), `.commitlint-${process.pid}.cjs`);
|
|
47
|
+
fs.writeFileSync(tmpFile, content);
|
|
48
|
+
return tmpFile;
|
|
49
|
+
}
|
|
50
|
+
export const commitlintCheck = {
|
|
51
|
+
name: 'Commitlint',
|
|
52
|
+
phase: 'informational',
|
|
53
|
+
applies(ctx) {
|
|
54
|
+
return ctx.config.commitlint?.enabled !== false;
|
|
55
|
+
},
|
|
56
|
+
async run(ctx) {
|
|
57
|
+
// This check needs a commit to lint. Without a repository `--last` finds
|
|
58
|
+
// none, commitlint prints nothing and exits 0, and we reported `pass` — a
|
|
59
|
+
// verdict on a commit message that does not exist. Ticket 072: a check that
|
|
60
|
+
// examined nothing must not read as a check that found nothing.
|
|
61
|
+
if (!(await resolveGitRef(ctx.cwd, 'HEAD')))
|
|
62
|
+
return skip('git unavailable');
|
|
63
|
+
const commitlintBin = resolvePackageBin('@commitlint/cli', 'cli.js');
|
|
64
|
+
const hasLocal = hasLocalConfig(LOCAL_CONFIG_FILES, ctx.cwd);
|
|
65
|
+
let tempConfigFile = null;
|
|
66
|
+
// With no diff range (a full-repo review, or `--full`) the check still has a
|
|
67
|
+
// meaningful subject: the newest commit message. `HEAD~1` cannot be assumed to
|
|
68
|
+
// exist, though — it is absent on a repository's first commit and in a shallow
|
|
69
|
+
// clone (`actions/checkout` fetches depth 1 by default). Passing it blind made
|
|
70
|
+
// commitlint die with an unhandled "ambiguous argument 'HEAD~1..HEAD'" stack
|
|
71
|
+
// trace in the client's log, and the check then reported "commit message
|
|
72
|
+
// violations found" — a verdict about code quality for what was a crash.
|
|
73
|
+
// `--last` lints exactly the newest commit and needs no ancestor.
|
|
74
|
+
const range = ctx.baseSha
|
|
75
|
+
? ['--from', ctx.baseSha, '--to', ctx.headSha ?? 'HEAD']
|
|
76
|
+
: (await resolveGitRef(ctx.cwd, 'HEAD~1'))
|
|
77
|
+
? ['--from', 'HEAD~1', '--to', ctx.headSha ?? 'HEAD']
|
|
78
|
+
: ['--last'];
|
|
79
|
+
const args = [...range, '--verbose'];
|
|
80
|
+
try {
|
|
81
|
+
if (hasLocal) {
|
|
82
|
+
logger.info('[Commitlint]: Using local config');
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
const types = ctx.config.commitlint?.types ?? DEFAULT_TYPES;
|
|
86
|
+
const ignores = ctx.config.commitlint?.ignores ?? DEFAULT_IGNORES;
|
|
87
|
+
tempConfigFile = buildTempConfig(types, ignores);
|
|
88
|
+
args.push('--config', tempConfigFile);
|
|
89
|
+
}
|
|
90
|
+
const result = await execa(process.execPath, [commitlintBin, ...args], {
|
|
91
|
+
cwd: ctx.cwd,
|
|
92
|
+
reject: false,
|
|
93
|
+
stdio: 'inherit',
|
|
94
|
+
});
|
|
95
|
+
return result.exitCode === 0 ? pass() : warn('commit message violations found');
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
if (tempConfigFile && fs.existsSync(tempConfigFile))
|
|
99
|
+
fs.unlinkSync(tempConfigFile);
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { logger } from '../../../utils/index.js';
|
|
3
|
+
import { pass, warn, skip } from '../../types.js';
|
|
4
|
+
// Matches "Closes #123", "Fixes #45", "Resolves #7" or JIRA-style "PROJ-456".
|
|
5
|
+
const TICKET_PATTERN = /(?:closes?|fixes?|resolves?)\s+#\d+|[A-Z][A-Z0-9]+-\d+/i;
|
|
6
|
+
export const prBodyCheck = {
|
|
7
|
+
name: 'PR Body',
|
|
8
|
+
phase: 'informational',
|
|
9
|
+
applies(ctx) {
|
|
10
|
+
if (ctx.config.prBody?.enabled === false)
|
|
11
|
+
return false;
|
|
12
|
+
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
13
|
+
return Boolean(eventPath && fs.existsSync(eventPath));
|
|
14
|
+
},
|
|
15
|
+
async run(ctx) {
|
|
16
|
+
const minLength = ctx.config.prBody?.minLength ?? 20;
|
|
17
|
+
const requireTicket = ctx.config.prBody?.requireTicket ?? true;
|
|
18
|
+
let event;
|
|
19
|
+
try {
|
|
20
|
+
event = JSON.parse(fs.readFileSync(process.env.GITHUB_EVENT_PATH, 'utf-8'));
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
logger.warn(`[PR Body]: ⚠️ Could not read GitHub event\n${err}`);
|
|
24
|
+
return skip('event unreadable');
|
|
25
|
+
}
|
|
26
|
+
const pr = event.pull_request;
|
|
27
|
+
if (!pr)
|
|
28
|
+
return skip('no PR data');
|
|
29
|
+
const trimmed = (pr.body ?? '').trim();
|
|
30
|
+
const issues = [];
|
|
31
|
+
if (trimmed.length < minLength) {
|
|
32
|
+
issues.push(`description too short (${trimmed.length}/${minLength} chars min)`);
|
|
33
|
+
}
|
|
34
|
+
if (requireTicket && trimmed && !TICKET_PATTERN.test(trimmed)) {
|
|
35
|
+
issues.push('no ticket reference (e.g. "Closes #123" or "PROJ-456")');
|
|
36
|
+
}
|
|
37
|
+
if (issues.length > 0) {
|
|
38
|
+
issues.forEach(i => logger.warn(`[PR Body]: ⚠️ ${i}`));
|
|
39
|
+
return warn(issues.join('; '));
|
|
40
|
+
}
|
|
41
|
+
return pass();
|
|
42
|
+
},
|
|
43
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { execa } from '../../../utils/execa.js';
|
|
2
|
+
import { logger } from '../../../utils/index.js';
|
|
3
|
+
import { pass, warn, skip } from '../../types.js';
|
|
4
|
+
const DEFAULT_MAX_FILES = 50;
|
|
5
|
+
const DEFAULT_MAX_LINES = 1000;
|
|
6
|
+
export const prSizeCheck = {
|
|
7
|
+
name: 'PR Size',
|
|
8
|
+
phase: 'informational',
|
|
9
|
+
requiresDiff: true,
|
|
10
|
+
applies(ctx) {
|
|
11
|
+
return ctx.config.prSize?.enabled !== false;
|
|
12
|
+
},
|
|
13
|
+
async run(ctx) {
|
|
14
|
+
const maxFiles = ctx.config.prSize?.maxFiles ?? DEFAULT_MAX_FILES;
|
|
15
|
+
const maxLines = ctx.config.prSize?.maxLines ?? DEFAULT_MAX_LINES;
|
|
16
|
+
try {
|
|
17
|
+
const { stdout } = await execa('git', ['diff', '--shortstat', ctx.baseSha, ctx.headSha ?? 'HEAD'], {
|
|
18
|
+
cwd: ctx.cwd,
|
|
19
|
+
});
|
|
20
|
+
// "5 files changed, 123 insertions(+), 45 deletions(-)"
|
|
21
|
+
const fileCount = parseInt(stdout.match(/(\d+) files? changed/)?.[1] ?? '0', 10);
|
|
22
|
+
const insertions = parseInt(stdout.match(/(\d+) insertion/)?.[1] ?? '0', 10);
|
|
23
|
+
const deletions = parseInt(stdout.match(/(\d+) deletion/)?.[1] ?? '0', 10);
|
|
24
|
+
const lines = insertions + deletions;
|
|
25
|
+
logger.info(`[PR Size]: ${fileCount} files changed, ${lines} lines`);
|
|
26
|
+
const issues = [];
|
|
27
|
+
if (fileCount > maxFiles)
|
|
28
|
+
issues.push(`${fileCount} files (recommended < ${maxFiles})`);
|
|
29
|
+
if (lines > maxLines)
|
|
30
|
+
issues.push(`${lines} lines (recommended < ${maxLines})`);
|
|
31
|
+
if (issues.length > 0) {
|
|
32
|
+
issues.forEach(i => logger.warn(`[PR Size]: ⚠️ Large PR: ${i}`));
|
|
33
|
+
return warn(issues.join(', '));
|
|
34
|
+
}
|
|
35
|
+
return pass();
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
logger.warn(`[PR Size]: ⚠️ Could not measure PR size\n${err}`);
|
|
39
|
+
return skip('diff unavailable');
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { logger } from '../../../utils/index.js';
|
|
3
|
+
import { pass, warn, skip } from '../../types.js';
|
|
4
|
+
const CONVENTIONAL_PREFIX = /^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)(\(.+\))?!?: .+/;
|
|
5
|
+
export const prTitleLintCheck = {
|
|
6
|
+
name: 'PR Title',
|
|
7
|
+
phase: 'informational',
|
|
8
|
+
applies() {
|
|
9
|
+
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
10
|
+
return Boolean(eventPath && fs.existsSync(eventPath));
|
|
11
|
+
},
|
|
12
|
+
async run() {
|
|
13
|
+
let event;
|
|
14
|
+
try {
|
|
15
|
+
event = JSON.parse(fs.readFileSync(process.env.GITHUB_EVENT_PATH, 'utf-8'));
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
logger.warn(`[PR Title]: ⚠️ Could not read GitHub event\n${err}`);
|
|
19
|
+
return skip('event unreadable');
|
|
20
|
+
}
|
|
21
|
+
const pr = event.pull_request;
|
|
22
|
+
if (!pr?.title)
|
|
23
|
+
return skip('no PR title');
|
|
24
|
+
const title = pr.title;
|
|
25
|
+
if (!CONVENTIONAL_PREFIX.test(title)) {
|
|
26
|
+
logger.warn(`[PR Title]: ⚠️ Not Conventional Commits: "${title}"`);
|
|
27
|
+
return warn('title does not follow Conventional Commits');
|
|
28
|
+
}
|
|
29
|
+
return pass();
|
|
30
|
+
},
|
|
31
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Check } from '../../types.js';
|
|
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;
|