pr-checkmate 3.0.4 → 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/package.json +15 -13
- 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,47 @@
|
|
|
1
|
+
/** The `package.json` half of a shipped profile manifest. */
|
|
2
|
+
interface ProfilePkg {
|
|
3
|
+
dependencies?: Record<string, string>;
|
|
4
|
+
overrides?: Record<string, unknown>;
|
|
5
|
+
}
|
|
6
|
+
/** The `package-lock.json` half. Entries are opaque to us beyond their identity. */
|
|
7
|
+
interface ProfileLock {
|
|
8
|
+
packages: Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
/** A manifest pair `npm ci` can be pointed at. */
|
|
11
|
+
export interface MergedManifest {
|
|
12
|
+
pkg: object;
|
|
13
|
+
lockfile: object;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Merge several profile manifests into the one a single `npm ci` installs.
|
|
17
|
+
*
|
|
18
|
+
* This is what stops the tooling cache from paying for the same package twice.
|
|
19
|
+
* Installing each profile into its own directory leaves npm nothing to
|
|
20
|
+
* deduplicate: `commitlint` and `js` share 30 MB, and separate trees download
|
|
21
|
+
* both copies. One tree costs the union instead of the sum — measured at 213 MB
|
|
22
|
+
* against 234 for a JavaScript repository, where per-profile directories came to
|
|
23
|
+
* 267 (ticket 087).
|
|
24
|
+
*
|
|
25
|
+
* The merge is a union, not a resolution, and it never reaches the network. Every
|
|
26
|
+
* shipped manifest was cut out of our own `package-lock.json` at build time, so
|
|
27
|
+
* two profiles that both contain a package contain the *same* entry for it,
|
|
28
|
+
* byte for byte. That is the whole reason this is safe to do at run time on a
|
|
29
|
+
* client's machine.
|
|
30
|
+
*
|
|
31
|
+
* Which makes a disagreement impossible unless we broke the build — so it throws
|
|
32
|
+
* rather than picking a winner. Choosing silently would hand a client a tree
|
|
33
|
+
* neither profile was tested against, and the integrity hashes that make this
|
|
34
|
+
* design defensible would be describing something we never ran.
|
|
35
|
+
*
|
|
36
|
+
* @param profiles Directories holding the shipped manifests, in any order.
|
|
37
|
+
* @param read Injected by tests; defaults to reading the two files.
|
|
38
|
+
* @throws If two profiles disagree about a package, or a manifest cannot be read.
|
|
39
|
+
*/
|
|
40
|
+
export declare function mergeManifests(profiles: Array<{
|
|
41
|
+
name: string;
|
|
42
|
+
dir: string;
|
|
43
|
+
}>, read?: (dir: string) => {
|
|
44
|
+
pkg: ProfilePkg;
|
|
45
|
+
lock: ProfileLock;
|
|
46
|
+
}): MergedManifest;
|
|
47
|
+
export {};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
const MERGED_NAME = 'pr-checkmate-tooling';
|
|
4
|
+
const MERGED_VERSION = '1.0.0';
|
|
5
|
+
/** Read a profile's shipped manifest pair from the installed package. */
|
|
6
|
+
function readShippedManifest(dir) {
|
|
7
|
+
return {
|
|
8
|
+
pkg: JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf-8')),
|
|
9
|
+
lock: JSON.parse(fs.readFileSync(path.join(dir, 'package-lock.json'), 'utf-8')),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Merge several profile manifests into the one a single `npm ci` installs.
|
|
14
|
+
*
|
|
15
|
+
* This is what stops the tooling cache from paying for the same package twice.
|
|
16
|
+
* Installing each profile into its own directory leaves npm nothing to
|
|
17
|
+
* deduplicate: `commitlint` and `js` share 30 MB, and separate trees download
|
|
18
|
+
* both copies. One tree costs the union instead of the sum — measured at 213 MB
|
|
19
|
+
* against 234 for a JavaScript repository, where per-profile directories came to
|
|
20
|
+
* 267 (ticket 087).
|
|
21
|
+
*
|
|
22
|
+
* The merge is a union, not a resolution, and it never reaches the network. Every
|
|
23
|
+
* shipped manifest was cut out of our own `package-lock.json` at build time, so
|
|
24
|
+
* two profiles that both contain a package contain the *same* entry for it,
|
|
25
|
+
* byte for byte. That is the whole reason this is safe to do at run time on a
|
|
26
|
+
* client's machine.
|
|
27
|
+
*
|
|
28
|
+
* Which makes a disagreement impossible unless we broke the build — so it throws
|
|
29
|
+
* rather than picking a winner. Choosing silently would hand a client a tree
|
|
30
|
+
* neither profile was tested against, and the integrity hashes that make this
|
|
31
|
+
* design defensible would be describing something we never ran.
|
|
32
|
+
*
|
|
33
|
+
* @param profiles Directories holding the shipped manifests, in any order.
|
|
34
|
+
* @param read Injected by tests; defaults to reading the two files.
|
|
35
|
+
* @throws If two profiles disagree about a package, or a manifest cannot be read.
|
|
36
|
+
*/
|
|
37
|
+
export function mergeManifests(profiles, read = readShippedManifest) {
|
|
38
|
+
const dependencies = {};
|
|
39
|
+
const overrides = {};
|
|
40
|
+
const packages = {};
|
|
41
|
+
// Which profile first claimed a given key, so a conflict names both sides.
|
|
42
|
+
const claimedBy = new Map();
|
|
43
|
+
const claim = (kind, key, value, by, into) => {
|
|
44
|
+
const id = `${kind}:${key}`;
|
|
45
|
+
const seen = claimedBy.get(id);
|
|
46
|
+
if (seen === undefined) {
|
|
47
|
+
claimedBy.set(id, by);
|
|
48
|
+
into[key] = value;
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (JSON.stringify(into[key]) !== JSON.stringify(value)) {
|
|
52
|
+
throw new Error(`profiles "${seen}" and "${by}" disagree about ${kind} "${key}" — ` +
|
|
53
|
+
'the shipped manifests are out of sync with our lockfile');
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
for (const { name, dir } of profiles) {
|
|
57
|
+
const { pkg, lock } = read(dir);
|
|
58
|
+
for (const [dep, version] of Object.entries(pkg.dependencies ?? {})) {
|
|
59
|
+
claim('dependency', dep, version, name, dependencies);
|
|
60
|
+
}
|
|
61
|
+
for (const [target, rule] of Object.entries(pkg.overrides ?? {})) {
|
|
62
|
+
claim('override', target, rule, name, overrides);
|
|
63
|
+
}
|
|
64
|
+
for (const [entryPath, entry] of Object.entries(lock.packages ?? {})) {
|
|
65
|
+
// The root entry describes the profile itself — its name, its direct
|
|
66
|
+
// dependencies. It is replaced by the merged root below, not merged: two
|
|
67
|
+
// profiles always "disagree" about it, and rightly so.
|
|
68
|
+
if (entryPath === '')
|
|
69
|
+
continue;
|
|
70
|
+
claim('package', entryPath, entry, name, packages);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const scoped = Object.keys(overrides).length > 0 ? { overrides } : {};
|
|
74
|
+
const root = { name: MERGED_NAME, version: MERGED_VERSION, dependencies, ...scoped };
|
|
75
|
+
return {
|
|
76
|
+
pkg: { ...root, private: true },
|
|
77
|
+
lockfile: {
|
|
78
|
+
name: MERGED_NAME,
|
|
79
|
+
version: MERGED_VERSION,
|
|
80
|
+
lockfileVersion: 3,
|
|
81
|
+
requires: true,
|
|
82
|
+
packages: { '': root, ...packages },
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { PRCheckMateConfig } from '../../interfaces/index.js';
|
|
2
|
+
import type { LanguageUsage } from '../../utils/detect-language.js';
|
|
3
|
+
import { type EnsureOptions } from './ensure.js';
|
|
4
|
+
import { type Profile } from './profiles.js';
|
|
5
|
+
/**
|
|
6
|
+
* Whether a profile needs fetching at all, or already ships inside the package.
|
|
7
|
+
*
|
|
8
|
+
* This is the hinge the whole adaptive-install rollout turns on. Nearly every
|
|
9
|
+
* profile's packages sit in our `dependencies`, so it answers `true`, nothing is
|
|
10
|
+
* fetched, and a run is byte-for-byte the run it was before any of this existed.
|
|
11
|
+
* `pytypes` is the exception that already proves the other half works: `pyright`
|
|
12
|
+
* is a devDependency, so it reaches no client and is fetched on demand. When a
|
|
13
|
+
* package is moved out of `dependencies` it stops being present, its profile
|
|
14
|
+
* starts answering `false`, and the fetch turns itself on — no flag, no second
|
|
15
|
+
* code path, nothing to remember to flip.
|
|
16
|
+
*
|
|
17
|
+
* Which is what makes releases 2 and 3 of ticket 064 an edit to `package.json`
|
|
18
|
+
* rather than another change to this logic.
|
|
19
|
+
*/
|
|
20
|
+
export declare function profileSatisfiedLocally(profile: Profile): boolean;
|
|
21
|
+
/** What the run knows about tooling before the first check starts. */
|
|
22
|
+
export interface ToolingPlan {
|
|
23
|
+
/** Check name → why its tooling is not available. Empty on a healthy run. */
|
|
24
|
+
unavailable: Map<string, string>;
|
|
25
|
+
/** Profile directories tool resolution should search. */
|
|
26
|
+
dirs: string[];
|
|
27
|
+
/**
|
|
28
|
+
* True when tooling is missing and `install.onMissingTool` is `"error"`. The
|
|
29
|
+
* affected checks fail instead of skipping: in a closed contour a check that
|
|
30
|
+
* quietly stops running is worse than a red build.
|
|
31
|
+
*/
|
|
32
|
+
fatal: boolean;
|
|
33
|
+
}
|
|
34
|
+
interface PrepareOptions {
|
|
35
|
+
cwd: string;
|
|
36
|
+
config: PRCheckMateConfig;
|
|
37
|
+
/** Detected languages with file counts — reused so the tree is scanned once. */
|
|
38
|
+
usage: LanguageUsage[];
|
|
39
|
+
/** Names of the checks this run intends to execute. */
|
|
40
|
+
selected: string[];
|
|
41
|
+
/** pr-checkmate's own version; part of the cache path. */
|
|
42
|
+
version: string;
|
|
43
|
+
/**
|
|
44
|
+
* The profile catalogue. Defaults to the shipped one; injected by tests.
|
|
45
|
+
*
|
|
46
|
+
* A seam rather than a mock of the module, for the same reason `ensure.ts` has
|
|
47
|
+
* one: nearly every profile ships inside the package, so the interesting half
|
|
48
|
+
* of this function — a profile that is genuinely absent — is otherwise reachable
|
|
49
|
+
* only through a network install in a unit test. The code that runs when a
|
|
50
|
+
* package leaves `dependencies` must be tested before that day, not on it.
|
|
51
|
+
*/
|
|
52
|
+
profiles?: Profile[];
|
|
53
|
+
/** The fetch itself, forwarded to `ensureTooling`. Injected by tests. */
|
|
54
|
+
installer?: EnsureOptions['installer'];
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Make sure the tooling this run needs is present, and say what is missing.
|
|
58
|
+
*
|
|
59
|
+
* Runs once, before the first check, and answers two questions the run cannot
|
|
60
|
+
* proceed honestly without: which directories tool resolution should search, and
|
|
61
|
+
* which checks have no tool to run. The second is the one ticket 057 is about —
|
|
62
|
+
* a check whose tooling never arrived must appear in the report saying so, not
|
|
63
|
+
* vanish from it.
|
|
64
|
+
*
|
|
65
|
+
* Only profiles backing checks that are actually selected are considered, so
|
|
66
|
+
* `severity: { "Spellcheck": "off" }` stops costing a download rather than only a
|
|
67
|
+
* row in the report (lever B of ticket 064).
|
|
68
|
+
*/
|
|
69
|
+
export declare function prepareTooling(opts: PrepareOptions): Promise<ToolingPlan>;
|
|
70
|
+
/**
|
|
71
|
+
* The plan for a run where preparation did not happen — nothing missing, nothing
|
|
72
|
+
* registered. Built fresh each time rather than shared: a caller holding a plan
|
|
73
|
+
* must not be able to see another run's.
|
|
74
|
+
*/
|
|
75
|
+
export declare function noTooling(): ToolingPlan;
|
|
76
|
+
export {};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { logger } from '../../utils/logger.js';
|
|
2
|
+
import { clearToolPaths, packagePresent, registerToolPaths } from '../../utils/resolve-bin.js';
|
|
3
|
+
import { ensureTooling } from './ensure.js';
|
|
4
|
+
import { PROFILES, planProfiles } from './profiles.js';
|
|
5
|
+
/**
|
|
6
|
+
* Whether a profile needs fetching at all, or already ships inside the package.
|
|
7
|
+
*
|
|
8
|
+
* This is the hinge the whole adaptive-install rollout turns on. Nearly every
|
|
9
|
+
* profile's packages sit in our `dependencies`, so it answers `true`, nothing is
|
|
10
|
+
* fetched, and a run is byte-for-byte the run it was before any of this existed.
|
|
11
|
+
* `pytypes` is the exception that already proves the other half works: `pyright`
|
|
12
|
+
* is a devDependency, so it reaches no client and is fetched on demand. When a
|
|
13
|
+
* package is moved out of `dependencies` it stops being present, its profile
|
|
14
|
+
* starts answering `false`, and the fetch turns itself on — no flag, no second
|
|
15
|
+
* code path, nothing to remember to flip.
|
|
16
|
+
*
|
|
17
|
+
* Which is what makes releases 2 and 3 of ticket 064 an edit to `package.json`
|
|
18
|
+
* rather than another change to this logic.
|
|
19
|
+
*/
|
|
20
|
+
export function profileSatisfiedLocally(profile) {
|
|
21
|
+
return profile.packages.every(pkg => packagePresent(pkg));
|
|
22
|
+
}
|
|
23
|
+
/** Profiles blocked outright by `install.deny`, with a line saying so. */
|
|
24
|
+
function denied(profile, deny) {
|
|
25
|
+
const blocked = profile.packages.filter(pkg => deny.has(pkg));
|
|
26
|
+
if (blocked.length === 0)
|
|
27
|
+
return null;
|
|
28
|
+
return `install.deny lists ${blocked.join(', ')}`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Make sure the tooling this run needs is present, and say what is missing.
|
|
32
|
+
*
|
|
33
|
+
* Runs once, before the first check, and answers two questions the run cannot
|
|
34
|
+
* proceed honestly without: which directories tool resolution should search, and
|
|
35
|
+
* which checks have no tool to run. The second is the one ticket 057 is about —
|
|
36
|
+
* a check whose tooling never arrived must appear in the report saying so, not
|
|
37
|
+
* vanish from it.
|
|
38
|
+
*
|
|
39
|
+
* Only profiles backing checks that are actually selected are considered, so
|
|
40
|
+
* `severity: { "Spellcheck": "off" }` stops costing a download rather than only a
|
|
41
|
+
* row in the report (lever B of ticket 064).
|
|
42
|
+
*/
|
|
43
|
+
export async function prepareTooling(opts) {
|
|
44
|
+
// Every run starts from no registered roots. The SDK can call `runChecks` more
|
|
45
|
+
// than once in one process, and a directory registered by a previous run — for
|
|
46
|
+
// a different repository, with a different profile set — must not still be on
|
|
47
|
+
// the search path for this one.
|
|
48
|
+
clearToolPaths();
|
|
49
|
+
const install = opts.config.install ?? {};
|
|
50
|
+
const strategy = process.env.PR_CHECKMATE_INSTALL_STRATEGY ?? install.strategy ?? 'adaptive';
|
|
51
|
+
const onMissing = install.onMissingTool ?? 'auto';
|
|
52
|
+
const deny = new Set(install.deny ?? []);
|
|
53
|
+
// Which profiles this repository needs: languages by file count, universal
|
|
54
|
+
// profiles by whether their check survived config. `install.profiles` and
|
|
55
|
+
// `excludeProfiles` have already had their say inside `planProfiles`.
|
|
56
|
+
const required = new Set(planProfiles(opts.usage, opts.config)
|
|
57
|
+
.filter(decision => decision.required)
|
|
58
|
+
.map(decision => decision.profile));
|
|
59
|
+
// A profile nobody in this run would use is not worth a thought, let alone a
|
|
60
|
+
// download. `eager` opts out of that reasoning by definition: it exists so a
|
|
61
|
+
// container build or an air-gapped mirror can hold everything up front.
|
|
62
|
+
const chosen = opts.selected.length > 0 ? new Set(opts.selected) : null;
|
|
63
|
+
const wanted = (opts.profiles ?? PROFILES).filter(profile => {
|
|
64
|
+
if (strategy === 'eager')
|
|
65
|
+
return true;
|
|
66
|
+
if (!required.has(profile.name))
|
|
67
|
+
return false;
|
|
68
|
+
return !chosen || profile.checks.some(check => chosen.has(check));
|
|
69
|
+
});
|
|
70
|
+
const unavailable = new Map();
|
|
71
|
+
const dirs = [];
|
|
72
|
+
const miss = (profile, reason) => {
|
|
73
|
+
for (const check of profile.checks)
|
|
74
|
+
unavailable.set(check, reason);
|
|
75
|
+
};
|
|
76
|
+
const toFetch = [];
|
|
77
|
+
for (const profile of wanted) {
|
|
78
|
+
// Bundled tooling is the answer to "where is it" for most profiles, and
|
|
79
|
+
// asking first is what keeps this whole path free of network calls.
|
|
80
|
+
if (profileSatisfiedLocally(profile))
|
|
81
|
+
continue;
|
|
82
|
+
const block = denied(profile, deny);
|
|
83
|
+
if (block) {
|
|
84
|
+
miss(profile, block);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
// No early exit for `install.strategy: "manual"`. It means "never fetch",
|
|
88
|
+
// and `ensureTooling` enforces that — but only after checking the cache, so
|
|
89
|
+
// pre-warmed tooling is still used. Returning here instead meant `manual`
|
|
90
|
+
// also refused tooling that was already downloaded.
|
|
91
|
+
if (onMissing === 'skip') {
|
|
92
|
+
miss(profile, 'install.onMissingTool is "skip"');
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
toFetch.push(profile);
|
|
96
|
+
}
|
|
97
|
+
// One call, one directory, one lock — for the whole run rather than per profile.
|
|
98
|
+
// Profiles overlap heavily, and a tree each made the client download the shared
|
|
99
|
+
// half once per profile that named it (ticket 087).
|
|
100
|
+
//
|
|
101
|
+
// Reached only when something actually needs fetching, which is also what keeps
|
|
102
|
+
// the cache directory untouched otherwise: resolving it is not a read — it
|
|
103
|
+
// creates the directory and warns when the configured path is unwritable, and a
|
|
104
|
+
// container with a read-only home would print that on every single run.
|
|
105
|
+
if (toFetch.length > 0) {
|
|
106
|
+
const result = await ensureTooling(toFetch.map(profile => profile.name), {
|
|
107
|
+
cwd: opts.cwd,
|
|
108
|
+
version: opts.version,
|
|
109
|
+
install,
|
|
110
|
+
...(opts.installer ? { installer: opts.installer } : {}),
|
|
111
|
+
});
|
|
112
|
+
if (result.status === 'failed' || result.status === 'skipped') {
|
|
113
|
+
for (const profile of toFetch)
|
|
114
|
+
miss(profile, result.reason);
|
|
115
|
+
}
|
|
116
|
+
else if (result.dir) {
|
|
117
|
+
dirs.push(result.dir);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (unavailable.size > 0) {
|
|
121
|
+
// Always logged, never behind --debug. A check that did not run is the
|
|
122
|
+
// failure mode this whole layer exists to make loud.
|
|
123
|
+
const names = [...new Set(unavailable.keys())].join(', ');
|
|
124
|
+
logger.warn(`[install]: ⚠️ tooling unavailable — these checks cannot run: ${names}`);
|
|
125
|
+
if (onMissing === 'error') {
|
|
126
|
+
logger.error('[install]: ❌ install.onMissingTool is "error" — the affected checks fail');
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
logger.info('[install]: Pre-warm the cache with: npx pr-checkmate install --all');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
registerToolPaths(dirs);
|
|
133
|
+
return { unavailable, dirs, fatal: onMissing === 'error' && unavailable.size > 0 };
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The plan for a run where preparation did not happen — nothing missing, nothing
|
|
137
|
+
* registered. Built fresh each time rather than shared: a caller holding a plan
|
|
138
|
+
* must not be able to see another run's.
|
|
139
|
+
*/
|
|
140
|
+
export function noTooling() {
|
|
141
|
+
return { unavailable: new Map(), dirs: [], fatal: false };
|
|
142
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { PRCheckMateConfig } from '../../interfaces/index.js';
|
|
2
|
+
import type { Language, LanguageUsage } from '../../utils/detect-language.js';
|
|
3
|
+
/**
|
|
4
|
+
* A named bundle of tooling, and the checks that stop working without it.
|
|
5
|
+
*
|
|
6
|
+
* The package ships ~233 MB of tooling, and no repository needs all of it: a
|
|
7
|
+
* Python service pays for the whole JavaScript toolchain, a repository with
|
|
8
|
+
* Spellcheck switched off still pays for cspell. Profiles are how that stops —
|
|
9
|
+
* they name which slice of the tooling a given repository actually needs.
|
|
10
|
+
*
|
|
11
|
+
* `checks` is not documentation. It is what turns a failed install into an
|
|
12
|
+
* honest report: when a profile is missing, exactly those checks skip, with the
|
|
13
|
+
* reason, instead of quietly disappearing (the mistake of ticket 057).
|
|
14
|
+
*/
|
|
15
|
+
export interface Profile {
|
|
16
|
+
name: ProfileName;
|
|
17
|
+
/** Top-level packages installed for this profile. */
|
|
18
|
+
packages: string[];
|
|
19
|
+
/** Registry names of the checks that need it. */
|
|
20
|
+
checks: string[];
|
|
21
|
+
/**
|
|
22
|
+
* Languages that make this profile necessary. Absent for profiles driven by
|
|
23
|
+
* enabled checks rather than by what the repository is written in.
|
|
24
|
+
*/
|
|
25
|
+
languages?: Language[];
|
|
26
|
+
/**
|
|
27
|
+
* An extra condition on the client's config, for a language profile whose
|
|
28
|
+
* checks can be switched off by a key of their own.
|
|
29
|
+
*
|
|
30
|
+
* `severity: { "X": "off" }` is already honoured for every profile, but it is
|
|
31
|
+
* not the only off switch: `python.typecheck: false` and `go.enabled: false`
|
|
32
|
+
* are the ones a client actually writes, and a language profile decided on
|
|
33
|
+
* file counts alone downloads the tooling regardless. For `pytypes` that is
|
|
34
|
+
* 19 MB fetched to run nothing.
|
|
35
|
+
*
|
|
36
|
+
* Deliberately a predicate over the config rather than a list of keys: the
|
|
37
|
+
* condition it mirrors lives in the check's own `applies`, and expressing it
|
|
38
|
+
* the same way is what makes the two readable side by side.
|
|
39
|
+
*/
|
|
40
|
+
enabledBy?(config: PRCheckMateConfig): boolean;
|
|
41
|
+
}
|
|
42
|
+
export type ProfileName = 'core' | 'js' | 'python' | 'pytypes' | 'cpp' | 'go' | 'spellcheck' | 'markdown' | 'commitlint' | 'duplicate';
|
|
43
|
+
/**
|
|
44
|
+
* The catalogue.
|
|
45
|
+
*
|
|
46
|
+
* Sizes in the comments are measured exclusive footprints — what leaves with the
|
|
47
|
+
* profile and is shared with nothing else (see ticket 069).
|
|
48
|
+
*/
|
|
49
|
+
export declare const PROFILES: Profile[];
|
|
50
|
+
/** The profile a check belongs to, or `undefined` when it needs no extra tooling. */
|
|
51
|
+
export declare function profileForCheck(check: string): Profile | undefined;
|
|
52
|
+
/** Why a profile is (or is not) part of this run — the answer `doctor` prints. */
|
|
53
|
+
export interface ProfileDecision {
|
|
54
|
+
profile: ProfileName;
|
|
55
|
+
required: boolean;
|
|
56
|
+
reason: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Decide which profiles this repository needs, and why.
|
|
60
|
+
*
|
|
61
|
+
* The two inputs are deliberately different in kind:
|
|
62
|
+
*
|
|
63
|
+
* - **Languages are counted in files, never in markers.** A Python service that
|
|
64
|
+
* installed us through npm has a `package.json`, which is a JavaScript marker
|
|
65
|
+
* — and downloading 152 MB of JavaScript tooling because of the file that
|
|
66
|
+
* installed us would be the whole feature backfiring. `LanguageUsage.files`
|
|
67
|
+
* exists for exactly this (ticket 068).
|
|
68
|
+
* - **Universal profiles are driven by enabled checks**, so `severity: {
|
|
69
|
+
* "Spellcheck": "off" }` starts saving bandwidth instead of only a report row.
|
|
70
|
+
*
|
|
71
|
+
* @param usage Detected languages with their tracked file counts.
|
|
72
|
+
* @param config The client's config; `install.profiles` and `install.excludeProfiles`
|
|
73
|
+
* have the last word, in that order — an explicit exclusion beats an explicit
|
|
74
|
+
* request, because it is the one that can be a hard requirement (air-gapped,
|
|
75
|
+
* licence policy, a runner that must not download a wasm binary).
|
|
76
|
+
* @returns One decision per profile, in catalogue order.
|
|
77
|
+
*/
|
|
78
|
+
export declare function planProfiles(usage: LanguageUsage[], config: PRCheckMateConfig): ProfileDecision[];
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The catalogue.
|
|
3
|
+
*
|
|
4
|
+
* Sizes in the comments are measured exclusive footprints — what leaves with the
|
|
5
|
+
* profile and is shared with nothing else (see ticket 069).
|
|
6
|
+
*/
|
|
7
|
+
export const PROFILES = [
|
|
8
|
+
{
|
|
9
|
+
// Always installed. Everything here backs a check that runs on any
|
|
10
|
+
// repository whatever it is written in, so there is nothing to decide.
|
|
11
|
+
name: 'core',
|
|
12
|
+
packages: ['execa', 'yaml', 'inquirer', 'gitleaks-secret-scanner-fixed'],
|
|
13
|
+
checks: ['Security Scan'],
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
// 152 MB, the largest by far, and the one a Python repository pays for
|
|
17
|
+
// today with nothing to show for it.
|
|
18
|
+
name: 'js',
|
|
19
|
+
packages: [
|
|
20
|
+
'typescript',
|
|
21
|
+
'eslint',
|
|
22
|
+
'eslint-config-prettier',
|
|
23
|
+
'eslint-plugin-import-x',
|
|
24
|
+
'eslint-plugin-jsdoc',
|
|
25
|
+
'eslint-plugin-prettier',
|
|
26
|
+
'eslint-plugin-sonarjs',
|
|
27
|
+
'@typescript-eslint/eslint-plugin',
|
|
28
|
+
'@typescript-eslint/parser',
|
|
29
|
+
'prettier',
|
|
30
|
+
'dpdm',
|
|
31
|
+
'knip',
|
|
32
|
+
'ts-unused-exports',
|
|
33
|
+
'license-checker-rseidelsohn',
|
|
34
|
+
],
|
|
35
|
+
checks: [
|
|
36
|
+
'ESLint',
|
|
37
|
+
'Prettier',
|
|
38
|
+
'TypeScript',
|
|
39
|
+
'Circular Deps',
|
|
40
|
+
'Dependencies',
|
|
41
|
+
'Dead Code',
|
|
42
|
+
'License Check',
|
|
43
|
+
],
|
|
44
|
+
languages: ['typescript', 'javascript'],
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'python',
|
|
48
|
+
packages: ['@astral-sh/ruff-wasm-nodejs'],
|
|
49
|
+
checks: ['Ruff Lint', 'Ruff Format'],
|
|
50
|
+
languages: ['python'],
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
// Separate from `python` because it is 19 MB against ruff's 12, and because
|
|
54
|
+
// the two answer different questions: plenty of repositories want the linter
|
|
55
|
+
// and have their own opinion about type checking. Bundling them would make
|
|
56
|
+
// `python.typecheck: false` cost the download anyway, which is the feature
|
|
57
|
+
// defeating itself.
|
|
58
|
+
name: 'pytypes',
|
|
59
|
+
packages: ['pyright'],
|
|
60
|
+
checks: ['Python Types'],
|
|
61
|
+
languages: ['python'],
|
|
62
|
+
enabledBy: config => config.python?.typecheck !== false && config.python?.enabled !== false,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'cpp',
|
|
66
|
+
packages: ['@wasm-fmt/clang-format'],
|
|
67
|
+
checks: ['C++ Format'],
|
|
68
|
+
languages: ['cpp'],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
// Go Format only. `go vet` needs the toolchain itself, which is not ours to
|
|
72
|
+
// ship, so it stays a runner dependency and is deliberately absent here.
|
|
73
|
+
name: 'go',
|
|
74
|
+
packages: ['@wasm-fmt/gofmt'],
|
|
75
|
+
checks: ['Go Format'],
|
|
76
|
+
languages: ['go'],
|
|
77
|
+
enabledBy: config => config.go?.enabled !== false,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
// The four below are not languages. They are single checks with heavy
|
|
81
|
+
// tooling behind them, which is exactly why they are separate: switching
|
|
82
|
+
// one off should stop costing megabytes, not just a line in the report.
|
|
83
|
+
name: 'spellcheck',
|
|
84
|
+
packages: ['cspell'],
|
|
85
|
+
checks: ['Spellcheck'],
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: 'markdown',
|
|
89
|
+
packages: ['markdownlint-cli2'],
|
|
90
|
+
checks: ['Markdown'],
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: 'commitlint',
|
|
94
|
+
packages: ['@commitlint/cli', '@commitlint/config-conventional'],
|
|
95
|
+
checks: ['Commitlint'],
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: 'duplicate',
|
|
99
|
+
packages: ['jscpd'],
|
|
100
|
+
checks: ['Duplicate Code'],
|
|
101
|
+
},
|
|
102
|
+
];
|
|
103
|
+
/** The profile a check belongs to, or `undefined` when it needs no extra tooling. */
|
|
104
|
+
export function profileForCheck(check) {
|
|
105
|
+
return PROFILES.find(p => p.checks.includes(check));
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* A check counts as enabled unless it is switched off.
|
|
109
|
+
*
|
|
110
|
+
* Deliberately asymmetric with how the runner selects checks: this must not
|
|
111
|
+
* import the registry (that would drag every check into the install path), and
|
|
112
|
+
* being wrong in the "enabled" direction only costs a download, while being
|
|
113
|
+
* wrong the other way silently removes a check. So anything not explicitly off
|
|
114
|
+
* is treated as on.
|
|
115
|
+
*/
|
|
116
|
+
function isCheckEnabled(check, config) {
|
|
117
|
+
return config.severity?.[check] !== 'off';
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Decide which profiles this repository needs, and why.
|
|
121
|
+
*
|
|
122
|
+
* The two inputs are deliberately different in kind:
|
|
123
|
+
*
|
|
124
|
+
* - **Languages are counted in files, never in markers.** A Python service that
|
|
125
|
+
* installed us through npm has a `package.json`, which is a JavaScript marker
|
|
126
|
+
* — and downloading 152 MB of JavaScript tooling because of the file that
|
|
127
|
+
* installed us would be the whole feature backfiring. `LanguageUsage.files`
|
|
128
|
+
* exists for exactly this (ticket 068).
|
|
129
|
+
* - **Universal profiles are driven by enabled checks**, so `severity: {
|
|
130
|
+
* "Spellcheck": "off" }` starts saving bandwidth instead of only a report row.
|
|
131
|
+
*
|
|
132
|
+
* @param usage Detected languages with their tracked file counts.
|
|
133
|
+
* @param config The client's config; `install.profiles` and `install.excludeProfiles`
|
|
134
|
+
* have the last word, in that order — an explicit exclusion beats an explicit
|
|
135
|
+
* request, because it is the one that can be a hard requirement (air-gapped,
|
|
136
|
+
* licence policy, a runner that must not download a wasm binary).
|
|
137
|
+
* @returns One decision per profile, in catalogue order.
|
|
138
|
+
*/
|
|
139
|
+
export function planProfiles(usage, config) {
|
|
140
|
+
const install = config.install ?? {};
|
|
141
|
+
const minFiles = Math.max(1, install.minFilesPerLanguage ?? 1);
|
|
142
|
+
const requested = new Set(install.profiles ?? []);
|
|
143
|
+
const excluded = new Set(install.excludeProfiles ?? []);
|
|
144
|
+
return PROFILES.map(profile => {
|
|
145
|
+
const decision = decide(profile, usage, config, minFiles);
|
|
146
|
+
if (excluded.has(profile.name)) {
|
|
147
|
+
return {
|
|
148
|
+
profile: profile.name,
|
|
149
|
+
required: false,
|
|
150
|
+
reason: 'excluded by install.excludeProfiles',
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
if (!decision.required && requested.has(profile.name)) {
|
|
154
|
+
return { profile: profile.name, required: true, reason: 'requested by install.profiles' };
|
|
155
|
+
}
|
|
156
|
+
return { profile: profile.name, required: decision.required, reason: decision.reason };
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
/** The automatic half of {@link planProfiles}, before the client's overrides. */
|
|
160
|
+
function decide(profile, usage, config, minFiles) {
|
|
161
|
+
if (profile.name === 'core')
|
|
162
|
+
return { required: true, reason: 'always installed' };
|
|
163
|
+
if (profile.languages) {
|
|
164
|
+
// Asked before the file counts, because it is the cheaper and the more
|
|
165
|
+
// definite answer: a client who wrote `python.typecheck: false` has settled
|
|
166
|
+
// the question, and counting `.py` files can only override them.
|
|
167
|
+
if (profile.enabledBy && !profile.enabledBy(config)) {
|
|
168
|
+
return { required: false, reason: `${profile.checks.join(', ')} switched off` };
|
|
169
|
+
}
|
|
170
|
+
const found = profile.languages
|
|
171
|
+
.map(lang => usage.find(u => u.lang === lang))
|
|
172
|
+
.filter((u) => Boolean(u) && u.files >= minFiles);
|
|
173
|
+
if (found.length > 0) {
|
|
174
|
+
const detail = found.map(u => `${u.files} ${u.lang} file(s)`).join(', ');
|
|
175
|
+
return { required: true, reason: detail };
|
|
176
|
+
}
|
|
177
|
+
// Named separately from "no files": a marker with no source files is the
|
|
178
|
+
// OctoBot case — a `Cargo.toml` beside zero `.rs`. The language is real
|
|
179
|
+
// enough to run checks for; it is not real enough to download a toolchain.
|
|
180
|
+
const markerOnly = profile.languages.some(lang => usage.some(u => u.lang === lang));
|
|
181
|
+
return {
|
|
182
|
+
required: false,
|
|
183
|
+
reason: markerOnly
|
|
184
|
+
? 'declared by a marker file but no source files tracked'
|
|
185
|
+
: 'no source files tracked',
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
const enabled = profile.checks.filter(check => isCheckEnabled(check, config));
|
|
189
|
+
return enabled.length > 0
|
|
190
|
+
? { required: true, reason: `${enabled.join(', ')} enabled` }
|
|
191
|
+
: { required: false, reason: `${profile.checks.join(', ')} switched off` };
|
|
192
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { CheckContext } from '../types.js';
|
|
2
|
+
/** One reuse decision, with the sentence that explains it. */
|
|
3
|
+
interface ReuseDecision {
|
|
4
|
+
/** Search roots to prefer, or `undefined` to use our own copy. */
|
|
5
|
+
paths?: string[];
|
|
6
|
+
reason: string;
|
|
7
|
+
}
|
|
8
|
+
interface ReuseOptions {
|
|
9
|
+
/**
|
|
10
|
+
* The tool will read the client's OWN configuration file.
|
|
11
|
+
*
|
|
12
|
+
* When it will, the version check is the wrong question and must not be asked:
|
|
13
|
+
* a repository with ESLint 8 and a legacy `.eslintrc` can only be linted by
|
|
14
|
+
* ESLint 8, because ESLint 10 does not read eslintrc — and falling back to ours
|
|
15
|
+
* on the strength of a major mismatch would break precisely the case the reuse
|
|
16
|
+
* was there to serve. TypeScript is the same shape permanently: the check only
|
|
17
|
+
* applies when the repository has a `tsconfig.json`, so their compiler is
|
|
18
|
+
* always the one their config was written for.
|
|
19
|
+
*
|
|
20
|
+
* The version check exists for the opposite case — the client's old tool being
|
|
21
|
+
* handed configuration WE generated.
|
|
22
|
+
*/
|
|
23
|
+
clientOwnsConfig?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Decide whether this run should prefer the client's copy of `pkgName`.
|
|
27
|
+
*
|
|
28
|
+
* `compatible` (the default) reuses when the client's major matches ours, or when
|
|
29
|
+
* the client's own configuration is what the tool will read. A mismatch is not an
|
|
30
|
+
* error — we have our own copy — so it downgrades to ours with a line saying why.
|
|
31
|
+
*/
|
|
32
|
+
export declare function reuseDecision(pkgName: string, ctx: CheckContext, opts?: ReuseOptions): ReuseDecision;
|
|
33
|
+
/**
|
|
34
|
+
* The search roots a check should prefer for `pkgName`, logging the reason once.
|
|
35
|
+
*
|
|
36
|
+
* The reason is logged rather than returned to each caller because it answers the
|
|
37
|
+
* question every confusing lint result starts with — "whose ESLint ran" — and no
|
|
38
|
+
* check should have to remember to say so.
|
|
39
|
+
*/
|
|
40
|
+
export declare function clientToolPaths(pkgName: string, ctx: CheckContext, opts?: ReuseOptions): string[] | undefined;
|
|
41
|
+
export {};
|