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,21 @@
|
|
|
1
|
+
import { execa } from './execa.js';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve a git ref to a concrete commit SHA, or `undefined` when this clone
|
|
4
|
+
* cannot resolve it.
|
|
5
|
+
*
|
|
6
|
+
* `--verify --quiet` emits nothing (rather than echoing the literal ref) and exits
|
|
7
|
+
* non-zero for a missing ref, so the caller gets a clear "not here" instead of a
|
|
8
|
+
* string that looks like a ref but resolves to nothing. Refs go missing more often
|
|
9
|
+
* than it seems: `HEAD^` on a repository's first commit, and any ancestor in a
|
|
10
|
+
* shallow CI clone — `actions/checkout` fetches depth 1 by default.
|
|
11
|
+
*
|
|
12
|
+
* Every caller must degrade rather than fail when this returns `undefined`: a
|
|
13
|
+
* missing base means "review everything", never "review nothing".
|
|
14
|
+
*/
|
|
15
|
+
export async function resolveGitRef(cwd, ref) {
|
|
16
|
+
const { stdout } = await execa('git', ['rev-parse', '--verify', '--quiet', `${ref}^{commit}`], {
|
|
17
|
+
cwd,
|
|
18
|
+
reject: false,
|
|
19
|
+
});
|
|
20
|
+
return stdout.trim() || undefined;
|
|
21
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal glob → RegExp for path matching against config patterns. Supports `*`
|
|
3
|
+
* (matches within a path segment), `**` (across segments), and a leading `** /`
|
|
4
|
+
* that also matches the repo root (zero segments). Anchored to the whole path.
|
|
5
|
+
* Not a full glob implementation — enough for the allow/ignore lists in
|
|
6
|
+
* pr-checkmate.json (e.g. "assets/**", "*.png", "** / *.d.ts").
|
|
7
|
+
*/
|
|
8
|
+
export declare function globToRegExp(glob: string): RegExp;
|
|
9
|
+
/** True when `file` matches any of the glob `patterns`. */
|
|
10
|
+
export declare function matchesAnyGlob(file: string, patterns: string[]): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* True when any segment of a repo-relative path names an excluded directory —
|
|
13
|
+
* `node_modules/x/y.py` for `node_modules`, at any nesting depth.
|
|
14
|
+
*
|
|
15
|
+
* Shared so the two consumers cannot drift: the file list every check operates on
|
|
16
|
+
* (`excludeIgnoredDirs` in core/targets.ts) and language detection, which counts
|
|
17
|
+
* tracked source files. They disagreed once — detection counted a repository that
|
|
18
|
+
* commits its dependencies as a Python/Go/PHP project and switched on the checks
|
|
19
|
+
* for languages nobody had written a line of.
|
|
20
|
+
*
|
|
21
|
+
* @param file Repo-relative path, forward slashes.
|
|
22
|
+
* @param ignoredDirs Directory NAMES (not globs) to exclude.
|
|
23
|
+
*/
|
|
24
|
+
export declare function isUnderIgnoredDir(file: string, ignoredDirs: Iterable<string>): boolean;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal glob → RegExp for path matching against config patterns. Supports `*`
|
|
3
|
+
* (matches within a path segment), `**` (across segments), and a leading `** /`
|
|
4
|
+
* that also matches the repo root (zero segments). Anchored to the whole path.
|
|
5
|
+
* Not a full glob implementation — enough for the allow/ignore lists in
|
|
6
|
+
* pr-checkmate.json (e.g. "assets/**", "*.png", "** / *.d.ts").
|
|
7
|
+
*/
|
|
8
|
+
export function globToRegExp(glob) {
|
|
9
|
+
const re = glob
|
|
10
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&') // escape regex specials (not * or /)
|
|
11
|
+
.replace(/\*\*\//g, ' dir ') // `**/` → optional leading dirs (matches root too)
|
|
12
|
+
.replace(/\*\*/g, ' any ') // bare `**` → across segments
|
|
13
|
+
.replace(/\*/g, '[^/]*') // `*` → within a segment
|
|
14
|
+
.replace(/ dir /g, '(?:.*/)?')
|
|
15
|
+
.replace(/ any /g, '.*');
|
|
16
|
+
return new RegExp(`^${re}$`);
|
|
17
|
+
}
|
|
18
|
+
/** True when `file` matches any of the glob `patterns`. */
|
|
19
|
+
export function matchesAnyGlob(file, patterns) {
|
|
20
|
+
return patterns.some(p => globToRegExp(p).test(file));
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* True when any segment of a repo-relative path names an excluded directory —
|
|
24
|
+
* `node_modules/x/y.py` for `node_modules`, at any nesting depth.
|
|
25
|
+
*
|
|
26
|
+
* Shared so the two consumers cannot drift: the file list every check operates on
|
|
27
|
+
* (`excludeIgnoredDirs` in core/targets.ts) and language detection, which counts
|
|
28
|
+
* tracked source files. They disagreed once — detection counted a repository that
|
|
29
|
+
* commits its dependencies as a Python/Go/PHP project and switched on the checks
|
|
30
|
+
* for languages nobody had written a line of.
|
|
31
|
+
*
|
|
32
|
+
* @param file Repo-relative path, forward slashes.
|
|
33
|
+
* @param ignoredDirs Directory NAMES (not globs) to exclude.
|
|
34
|
+
*/
|
|
35
|
+
export function isUnderIgnoredDir(file, ignoredDirs) {
|
|
36
|
+
const ignored = ignoredDirs instanceof Set ? ignoredDirs : new Set(ignoredDirs);
|
|
37
|
+
if (ignored.size === 0)
|
|
38
|
+
return false;
|
|
39
|
+
return file.split('/').some(segment => ignored.has(segment));
|
|
40
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outcome of one request: never throws, so a reporting hiccup cannot kill a run.
|
|
3
|
+
*
|
|
4
|
+
* Internal to this module — `utils/index.ts` does not re-export `http`, and the
|
|
5
|
+
* reporters consume the result inline rather than naming the type.
|
|
6
|
+
*/
|
|
7
|
+
interface HttpResult<T = unknown> {
|
|
8
|
+
ok: boolean;
|
|
9
|
+
/** 0 when the request never reached a server (timeout, DNS, offline). */
|
|
10
|
+
status: number;
|
|
11
|
+
body?: T;
|
|
12
|
+
/** Human-readable reason, present whenever `ok` is false. */
|
|
13
|
+
error?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface HttpOptions {
|
|
16
|
+
/** Per-attempt timeout. A hung API must not hold the process open. */
|
|
17
|
+
timeoutMs?: number;
|
|
18
|
+
/** Attempts for retryable failures (5xx, 429, network). 1 disables retrying. */
|
|
19
|
+
retries?: number;
|
|
20
|
+
/** Label used in log lines, e.g. `GitHub`. */
|
|
21
|
+
label?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* One HTTP request with a timeout and bounded retries, returning a result rather
|
|
25
|
+
* than throwing.
|
|
26
|
+
*
|
|
27
|
+
* The reason this exists: every write in the reporter used to be a bare `await
|
|
28
|
+
* fetch(...)` whose result was discarded, followed by a log line claiming
|
|
29
|
+
* success. A 403 from a workflow missing `pull-requests: write` produced
|
|
30
|
+
* "✅ Posted PR CheckMate summary" and no comment — the user had nothing to
|
|
31
|
+
* debug from.
|
|
32
|
+
*/
|
|
33
|
+
export declare function request<T = unknown>(url: string, init?: RequestInit, opts?: HttpOptions): Promise<HttpResult<T>>;
|
|
34
|
+
/**
|
|
35
|
+
* Walk a paginated collection until `nextUrl` returns nothing or `maxPages` is
|
|
36
|
+
* reached, returning every item found.
|
|
37
|
+
*
|
|
38
|
+
* Without this the reporter read only the first page — 30 comments on GitHub, 20
|
|
39
|
+
* on GitLab — so on any PR with more discussion than that its own marker fell off
|
|
40
|
+
* the end, the upsert became an insert, and every push added another comment.
|
|
41
|
+
*
|
|
42
|
+
* Stopping at `maxPages` is logged rather than silent: a truncated search can
|
|
43
|
+
* only produce a duplicate comment, and that should be explainable.
|
|
44
|
+
*/
|
|
45
|
+
export declare function paginate<T>(firstUrl: string, init: RequestInit, extract: (body: unknown) => T[],
|
|
46
|
+
/**
|
|
47
|
+
* URL of the page after this one, or null when the collection is exhausted.
|
|
48
|
+
* Receives the page's item count so page-number APIs (GitHub, GitLab) can stop
|
|
49
|
+
* on a short page, while cursor APIs (Bitbucket) read a link out of the body.
|
|
50
|
+
*/
|
|
51
|
+
nextUrl: (body: unknown, page: number, count: number) => string | null, opts?: HttpOptions & {
|
|
52
|
+
maxPages?: number;
|
|
53
|
+
}): Promise<{
|
|
54
|
+
items: T[];
|
|
55
|
+
ok: boolean;
|
|
56
|
+
truncated: boolean;
|
|
57
|
+
error?: string;
|
|
58
|
+
}>;
|
|
59
|
+
export {};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { logger } from './logger.js';
|
|
2
|
+
const DEFAULT_TIMEOUT_MS = 10000;
|
|
3
|
+
const DEFAULT_RETRIES = 3;
|
|
4
|
+
/** 5xx and 429 are worth another attempt; a 4xx will fail identically forever. */
|
|
5
|
+
function isRetryable(status) {
|
|
6
|
+
return status === 0 || status === 429 || status >= 500;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Turn a response into a diagnosis a person can act on.
|
|
10
|
+
*
|
|
11
|
+
* "Could not post comment: 403" sends someone hunting through Actions docs;
|
|
12
|
+
* naming the likely cause is the difference between a fixable message and a
|
|
13
|
+
* shrug. These three account for nearly every real failure.
|
|
14
|
+
*/
|
|
15
|
+
function explain(status, body) {
|
|
16
|
+
if (status === 401 || status === 403) {
|
|
17
|
+
return `${status} — token missing, expired, or lacking write scope (GitHub needs \`permissions: pull-requests: write\` AND \`env: GITHUB_TOKEN\`)`;
|
|
18
|
+
}
|
|
19
|
+
if (status === 404)
|
|
20
|
+
return `${status} — repository or PR not found, or the token cannot see it`;
|
|
21
|
+
if (status === 429)
|
|
22
|
+
return `${status} — rate limited`;
|
|
23
|
+
return `${status}${body ? ` — ${body.slice(0, 200)}` : ''}`;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Never let a token reach a log line, whatever an API decides to echo back.
|
|
27
|
+
*
|
|
28
|
+
* `pousr` and `glpat` below are not words: the first is the character class of
|
|
29
|
+
* GitHub's token prefixes (`ghp_`/`gho_`/`ghu_`/`ghs_`/`ghr_`), the second is
|
|
30
|
+
* GitLab's literal `glpat-`. Muted here rather than in the dictionary, which
|
|
31
|
+
* ships to every client and should not carry our regex fragments.
|
|
32
|
+
* cspell:ignore pousr glpat
|
|
33
|
+
*/
|
|
34
|
+
function redact(text) {
|
|
35
|
+
return text.replace(/\b(gh[pousr]_|glpat-|xox[baprs]-)[A-Za-z0-9_-]{8,}/g, '$1***');
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* One HTTP request with a timeout and bounded retries, returning a result rather
|
|
39
|
+
* than throwing.
|
|
40
|
+
*
|
|
41
|
+
* The reason this exists: every write in the reporter used to be a bare `await
|
|
42
|
+
* fetch(...)` whose result was discarded, followed by a log line claiming
|
|
43
|
+
* success. A 403 from a workflow missing `pull-requests: write` produced
|
|
44
|
+
* "✅ Posted PR CheckMate summary" and no comment — the user had nothing to
|
|
45
|
+
* debug from.
|
|
46
|
+
*/
|
|
47
|
+
export async function request(url, init = {}, opts = {}) {
|
|
48
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
49
|
+
const attempts = Math.max(1, opts.retries ?? DEFAULT_RETRIES);
|
|
50
|
+
const label = opts.label ? `[${opts.label}] ` : '';
|
|
51
|
+
let last = { ok: false, status: 0, error: 'no attempt made' };
|
|
52
|
+
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
53
|
+
last = await attempt_(url, init, timeoutMs);
|
|
54
|
+
if (last.ok || !isRetryable(last.status))
|
|
55
|
+
return last;
|
|
56
|
+
if (attempt < attempts) {
|
|
57
|
+
// Exponential backoff, capped so three attempts stay well inside a CI step.
|
|
58
|
+
const waitMs = Math.min(2000, 250 * 2 ** (attempt - 1));
|
|
59
|
+
logger.warn(`${label}retrying after ${last.error} (attempt ${attempt}/${attempts})`);
|
|
60
|
+
await new Promise(resolve => setTimeout(resolve, waitMs));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return last;
|
|
64
|
+
}
|
|
65
|
+
/** A single attempt, with every failure mode flattened into an HttpResult. */
|
|
66
|
+
async function attempt_(url, init, timeoutMs) {
|
|
67
|
+
try {
|
|
68
|
+
const res = await fetch(url, { ...init, signal: AbortSignal.timeout(timeoutMs) });
|
|
69
|
+
if (!res.ok) {
|
|
70
|
+
const text = await res.text().catch(() => '');
|
|
71
|
+
return { ok: false, status: res.status, error: redact(explain(res.status, text)) };
|
|
72
|
+
}
|
|
73
|
+
// A successful response with an unreadable body is still a successful write;
|
|
74
|
+
// only callers that need the body care, and they check for `undefined`.
|
|
75
|
+
const body = (await res.json().catch(() => undefined));
|
|
76
|
+
return { ok: true, status: res.status, body };
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
80
|
+
return { ok: false, status: 0, error: redact(`request failed — ${reason}`) };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Walk a paginated collection until `nextUrl` returns nothing or `maxPages` is
|
|
85
|
+
* reached, returning every item found.
|
|
86
|
+
*
|
|
87
|
+
* Without this the reporter read only the first page — 30 comments on GitHub, 20
|
|
88
|
+
* on GitLab — so on any PR with more discussion than that its own marker fell off
|
|
89
|
+
* the end, the upsert became an insert, and every push added another comment.
|
|
90
|
+
*
|
|
91
|
+
* Stopping at `maxPages` is logged rather than silent: a truncated search can
|
|
92
|
+
* only produce a duplicate comment, and that should be explainable.
|
|
93
|
+
*/
|
|
94
|
+
export async function paginate(firstUrl, init, extract,
|
|
95
|
+
/**
|
|
96
|
+
* URL of the page after this one, or null when the collection is exhausted.
|
|
97
|
+
* Receives the page's item count so page-number APIs (GitHub, GitLab) can stop
|
|
98
|
+
* on a short page, while cursor APIs (Bitbucket) read a link out of the body.
|
|
99
|
+
*/
|
|
100
|
+
nextUrl, opts = {}) {
|
|
101
|
+
const maxPages = Math.max(1, opts.maxPages ?? 10);
|
|
102
|
+
const items = [];
|
|
103
|
+
let url = firstUrl;
|
|
104
|
+
for (let page = 1; page <= maxPages; page++) {
|
|
105
|
+
const res = await request(url, init, opts);
|
|
106
|
+
if (!res.ok)
|
|
107
|
+
return { items, ok: false, truncated: false, error: res.error };
|
|
108
|
+
const pageItems = extract(res.body);
|
|
109
|
+
items.push(...pageItems);
|
|
110
|
+
url = nextUrl(res.body, page, pageItems.length);
|
|
111
|
+
if (!url)
|
|
112
|
+
return { items, ok: true, truncated: false };
|
|
113
|
+
}
|
|
114
|
+
return { items, ok: true, truncated: true };
|
|
115
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export * from './logger.js';
|
|
2
|
+
export * from './result-collector.js';
|
|
3
|
+
export * from './resolve-bin.js';
|
|
4
|
+
export * from './own-deps.js';
|
|
5
|
+
export * from './direct-deps.js';
|
|
6
|
+
export * from './detect-language.js';
|
|
7
|
+
export * from './glob.js';
|
|
8
|
+
export * from './update-notifier.js';
|
|
9
|
+
export * from './package-version.js';
|
|
10
|
+
export * from './ci.js';
|
|
11
|
+
export * from './git.js';
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
15
|
+
export declare function cleanupTempFile(filePath: string): void;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { logger } from './logger.js';
|
|
3
|
+
export * from './logger.js';
|
|
4
|
+
export * from './result-collector.js';
|
|
5
|
+
export * from './resolve-bin.js';
|
|
6
|
+
export * from './own-deps.js';
|
|
7
|
+
export * from './direct-deps.js';
|
|
8
|
+
export * from './detect-language.js';
|
|
9
|
+
export * from './glob.js';
|
|
10
|
+
export * from './update-notifier.js';
|
|
11
|
+
export * from './package-version.js';
|
|
12
|
+
export * from './ci.js';
|
|
13
|
+
export * from './git.js';
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
*/
|
|
17
|
+
export function cleanupTempFile(filePath) {
|
|
18
|
+
try {
|
|
19
|
+
if (fs.existsSync(filePath)) {
|
|
20
|
+
fs.unlinkSync(filePath);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
logger.warn(`[cleanupTempFile]: ⚠️ Failed cleanup: ${filePath}\n${err}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/** Destination for log lines; see {@link Logger.setSink}. */
|
|
2
|
+
export interface LogSink {
|
|
3
|
+
out(chunk: string): void;
|
|
4
|
+
err(chunk: string): void;
|
|
5
|
+
}
|
|
6
|
+
export type LogLevel = 'log' | 'info' | 'warn' | 'error' | 'debug';
|
|
7
|
+
/** How a line is rendered. */
|
|
8
|
+
export type LogFormat = 'pretty' | 'ci' | 'json';
|
|
9
|
+
export interface LoggerOptions {
|
|
10
|
+
level?: LogLevel;
|
|
11
|
+
format?: LogFormat;
|
|
12
|
+
color?: 'auto' | 'always' | 'never';
|
|
13
|
+
timestamps?: boolean;
|
|
14
|
+
/** Levels routed to stderr rather than stdout. */
|
|
15
|
+
stderrLevels?: LogLevel[];
|
|
16
|
+
}
|
|
17
|
+
export declare class Logger {
|
|
18
|
+
private currentLevel;
|
|
19
|
+
private format;
|
|
20
|
+
private color;
|
|
21
|
+
private timestamps;
|
|
22
|
+
private stderrLevels;
|
|
23
|
+
constructor(options?: LoggerOptions);
|
|
24
|
+
/** Apply options; unset fields keep their current value. */
|
|
25
|
+
configure(options: LoggerOptions): void;
|
|
26
|
+
private shouldLog;
|
|
27
|
+
private streamFor;
|
|
28
|
+
/**
|
|
29
|
+
* Where lines actually go. Swappable so tests can capture output without
|
|
30
|
+
* touching `process.stdout`.
|
|
31
|
+
*
|
|
32
|
+
* That distinction is not stylistic. Node's test runner reports each file's
|
|
33
|
+
* results to the parent process over stdout, so a test that replaces
|
|
34
|
+
* `process.stdout.write` and swallows what it receives also swallows those
|
|
35
|
+
* frames: the parent then waits forever for a file that already finished. It
|
|
36
|
+
* only shows up under load — on a two-core CI runner the frames land inside
|
|
37
|
+
* the capture window, on a developer's machine they usually do not — which
|
|
38
|
+
* made it a three-hour hang that never reproduced locally.
|
|
39
|
+
*/
|
|
40
|
+
private sink;
|
|
41
|
+
/**
|
|
42
|
+
* Redirect output, returning the previous sink so the caller can restore it.
|
|
43
|
+
* Passing `null` restores the real streams.
|
|
44
|
+
*/
|
|
45
|
+
setSink(sink: LogSink | null): LogSink | null;
|
|
46
|
+
private emit;
|
|
47
|
+
private render;
|
|
48
|
+
private logMessage;
|
|
49
|
+
log(msg: string): void;
|
|
50
|
+
info(msg: string): void;
|
|
51
|
+
warn(msg: string): void;
|
|
52
|
+
error(msg: string, err?: unknown): void;
|
|
53
|
+
debug(msg: string): void;
|
|
54
|
+
/**
|
|
55
|
+
* Product output: the run summary, printed verbatim.
|
|
56
|
+
*
|
|
57
|
+
* Distinct from `info` because the summary is the thing the run exists to
|
|
58
|
+
* produce, not a note about producing it. Routing it through the log formatter
|
|
59
|
+
* prefixed every line with a timestamp and a level, which pushed the box
|
|
60
|
+
* borders out of alignment and made the headline artefact look broken.
|
|
61
|
+
*/
|
|
62
|
+
print(msg: string): void;
|
|
63
|
+
setLevel(level: LogLevel): void;
|
|
64
|
+
}
|
|
65
|
+
export declare const logger: Logger;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
const LEVEL_ORDER = {
|
|
2
|
+
error: 0,
|
|
3
|
+
warn: 1,
|
|
4
|
+
info: 2,
|
|
5
|
+
log: 2,
|
|
6
|
+
debug: 3,
|
|
7
|
+
};
|
|
8
|
+
const COLORS = {
|
|
9
|
+
error: '\x1b[31m', // red
|
|
10
|
+
warn: '\x1b[33m', // yellow
|
|
11
|
+
info: '\x1b[32m', // green
|
|
12
|
+
log: '\x1b[37m', // white
|
|
13
|
+
debug: '\x1b[36m', // cyan
|
|
14
|
+
};
|
|
15
|
+
const RESET = '\x1b[0m';
|
|
16
|
+
/**
|
|
17
|
+
* Whether ANSI colour is wanted on `stream`.
|
|
18
|
+
*
|
|
19
|
+
* Colour used to be emitted unconditionally, so a piped or redirected run — and
|
|
20
|
+
* every CI log — was littered with escape sequences. `NO_COLOR` is the de-facto
|
|
21
|
+
* standard (no-color.org) and `FORCE_COLOR` the usual override; both are honoured
|
|
22
|
+
* here, and the TTY test asks about the stream actually being written to.
|
|
23
|
+
*/
|
|
24
|
+
function wantsColor(mode, stream) {
|
|
25
|
+
if (mode === 'never')
|
|
26
|
+
return false;
|
|
27
|
+
if (mode === 'always')
|
|
28
|
+
return true;
|
|
29
|
+
if (process.env.FORCE_COLOR)
|
|
30
|
+
return process.env.FORCE_COLOR !== '0';
|
|
31
|
+
if (process.env.NO_COLOR !== undefined)
|
|
32
|
+
return false;
|
|
33
|
+
return Boolean(stream.isTTY);
|
|
34
|
+
}
|
|
35
|
+
export class Logger {
|
|
36
|
+
constructor(options = {}) {
|
|
37
|
+
this.currentLevel = 'info';
|
|
38
|
+
this.color = 'auto';
|
|
39
|
+
this.stderrLevels = new Set(['error', 'warn']);
|
|
40
|
+
/**
|
|
41
|
+
* Where lines actually go. Swappable so tests can capture output without
|
|
42
|
+
* touching `process.stdout`.
|
|
43
|
+
*
|
|
44
|
+
* That distinction is not stylistic. Node's test runner reports each file's
|
|
45
|
+
* results to the parent process over stdout, so a test that replaces
|
|
46
|
+
* `process.stdout.write` and swallows what it receives also swallows those
|
|
47
|
+
* frames: the parent then waits forever for a file that already finished. It
|
|
48
|
+
* only shows up under load — on a two-core CI runner the frames land inside
|
|
49
|
+
* the capture window, on a developer's machine they usually do not — which
|
|
50
|
+
* made it a three-hour hang that never reproduced locally.
|
|
51
|
+
*/
|
|
52
|
+
this.sink = null;
|
|
53
|
+
// CI logs are read long after the fact and benefit from timestamps; a
|
|
54
|
+
// terminal is read as it scrolls, where they are noise that also breaks the
|
|
55
|
+
// alignment of the summary box.
|
|
56
|
+
const inCi = Boolean(process.env.CI);
|
|
57
|
+
this.format = options.format ?? (inCi ? 'ci' : 'pretty');
|
|
58
|
+
this.timestamps = options.timestamps ?? this.format === 'ci';
|
|
59
|
+
this.configure(options);
|
|
60
|
+
}
|
|
61
|
+
/** Apply options; unset fields keep their current value. */
|
|
62
|
+
configure(options) {
|
|
63
|
+
if (options.level)
|
|
64
|
+
this.currentLevel = options.level;
|
|
65
|
+
if (options.format) {
|
|
66
|
+
this.format = options.format;
|
|
67
|
+
if (options.timestamps === undefined)
|
|
68
|
+
this.timestamps = options.format === 'ci';
|
|
69
|
+
}
|
|
70
|
+
if (options.color)
|
|
71
|
+
this.color = options.color;
|
|
72
|
+
if (options.timestamps !== undefined)
|
|
73
|
+
this.timestamps = options.timestamps;
|
|
74
|
+
if (options.stderrLevels)
|
|
75
|
+
this.stderrLevels = new Set(options.stderrLevels);
|
|
76
|
+
}
|
|
77
|
+
shouldLog(level) {
|
|
78
|
+
return LEVEL_ORDER[level] <= LEVEL_ORDER[this.currentLevel];
|
|
79
|
+
}
|
|
80
|
+
streamFor(level) {
|
|
81
|
+
return this.stderrLevels.has(level) ? process.stderr : process.stdout;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Redirect output, returning the previous sink so the caller can restore it.
|
|
85
|
+
* Passing `null` restores the real streams.
|
|
86
|
+
*/
|
|
87
|
+
setSink(sink) {
|
|
88
|
+
const previous = this.sink;
|
|
89
|
+
this.sink = sink;
|
|
90
|
+
return previous;
|
|
91
|
+
}
|
|
92
|
+
emit(stream, text) {
|
|
93
|
+
if (!this.sink) {
|
|
94
|
+
stream.write(text);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (stream === process.stderr)
|
|
98
|
+
this.sink.err(text);
|
|
99
|
+
else
|
|
100
|
+
this.sink.out(text);
|
|
101
|
+
}
|
|
102
|
+
render(level, message, error) {
|
|
103
|
+
const stack = error instanceof Error ? `\n${error.stack}` : '';
|
|
104
|
+
if (this.format === 'json') {
|
|
105
|
+
return JSON.stringify({
|
|
106
|
+
level,
|
|
107
|
+
message,
|
|
108
|
+
...(stack ? { stack: stack.trim() } : {}),
|
|
109
|
+
time: new Date().toISOString(),
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
const time = this.timestamps ? `[${new Date().toISOString()}] ` : '';
|
|
113
|
+
const tag = this.format === 'ci' ? `[${level.toUpperCase()}] ` : '';
|
|
114
|
+
return `${time}${tag}${message}${stack}`;
|
|
115
|
+
}
|
|
116
|
+
logMessage(level, message, error) {
|
|
117
|
+
if (!this.shouldLog(level))
|
|
118
|
+
return;
|
|
119
|
+
const stream = this.streamFor(level);
|
|
120
|
+
const line = this.render(level, message, error);
|
|
121
|
+
// JSON output is meant to be parsed; coloring it would corrupt the payload.
|
|
122
|
+
const colored = this.format !== 'json' && wantsColor(this.color, stream)
|
|
123
|
+
? `${COLORS[level]}${line}${RESET}`
|
|
124
|
+
: line;
|
|
125
|
+
this.emit(stream, `${colored}\n`);
|
|
126
|
+
}
|
|
127
|
+
log(msg) {
|
|
128
|
+
this.logMessage('log', msg);
|
|
129
|
+
}
|
|
130
|
+
info(msg) {
|
|
131
|
+
this.logMessage('info', msg);
|
|
132
|
+
}
|
|
133
|
+
warn(msg) {
|
|
134
|
+
this.logMessage('warn', msg);
|
|
135
|
+
}
|
|
136
|
+
error(msg, err) {
|
|
137
|
+
this.logMessage('error', msg, err);
|
|
138
|
+
}
|
|
139
|
+
debug(msg) {
|
|
140
|
+
this.logMessage('debug', msg);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Product output: the run summary, printed verbatim.
|
|
144
|
+
*
|
|
145
|
+
* Distinct from `info` because the summary is the thing the run exists to
|
|
146
|
+
* produce, not a note about producing it. Routing it through the log formatter
|
|
147
|
+
* prefixed every line with a timestamp and a level, which pushed the box
|
|
148
|
+
* borders out of alignment and made the headline artefact look broken.
|
|
149
|
+
*/
|
|
150
|
+
print(msg) {
|
|
151
|
+
this.emit(process.stdout, `${msg}\n`);
|
|
152
|
+
}
|
|
153
|
+
setLevel(level) {
|
|
154
|
+
this.currentLevel = level;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
export const logger = new Logger();
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Walk up from this module until we find pr-checkmate's own package root. */
|
|
2
|
+
export declare function findOwnPackageRoot(): string | null;
|
|
3
|
+
/**
|
|
4
|
+
* Compute the full set of package names in pr-checkmate's own dependency
|
|
5
|
+
* closure (direct + transitive runtime dependencies), plus pr-checkmate itself.
|
|
6
|
+
*
|
|
7
|
+
* pr-checkmate installs into the consumer's node_modules, so its own runtime
|
|
8
|
+
* deps (eslint plugins, cspell dictionaries, …) become part of the consumer's
|
|
9
|
+
* production dependency tree. Some carry copyleft licenses that would otherwise
|
|
10
|
+
* trip pr-checkmate's own license check against an innocent client. These are
|
|
11
|
+
* pr-checkmate's dependencies, not the client's, so they must be exempt.
|
|
12
|
+
*
|
|
13
|
+
* Result is cached for the process. Returns a set containing only pr-checkmate
|
|
14
|
+
* itself if the package root cannot be located (defensive; never throws).
|
|
15
|
+
*/
|
|
16
|
+
export declare function getOwnDependencyClosure(): Set<string>;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { fileURLToPath as __fileURLToPath } from 'node:url';
|
|
2
|
+
import { dirname as __dirnameFn } from 'node:path';
|
|
3
|
+
const __dirname = __dirnameFn(__fileURLToPath(import.meta.url));
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
const OWN_PACKAGE_NAME = 'pr-checkmate';
|
|
7
|
+
const PACKAGE_JSON = 'package.json';
|
|
8
|
+
let cachedClosure;
|
|
9
|
+
/** Read a package.json's `dependencies` keys, tolerating missing/broken files. */
|
|
10
|
+
function readDependencyNames(pkgDir) {
|
|
11
|
+
try {
|
|
12
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(pkgDir, PACKAGE_JSON), 'utf-8'));
|
|
13
|
+
return Object.keys(pkg.dependencies ?? {});
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Walk up from `startDir` (inclusive) toward the filesystem root, returning the
|
|
21
|
+
* first directory whose package.json declares `name === expectedName`, or null.
|
|
22
|
+
* Broken/missing package.json files are skipped rather than thrown.
|
|
23
|
+
*/
|
|
24
|
+
function findPackageRootByName(startDir, expectedName) {
|
|
25
|
+
let dir = startDir;
|
|
26
|
+
while (dir !== path.dirname(dir)) {
|
|
27
|
+
const pkgJsonPath = path.join(dir, PACKAGE_JSON);
|
|
28
|
+
if (fs.existsSync(pkgJsonPath)) {
|
|
29
|
+
try {
|
|
30
|
+
const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
|
|
31
|
+
if (pkg.name === expectedName)
|
|
32
|
+
return dir;
|
|
33
|
+
}
|
|
34
|
+
catch { }
|
|
35
|
+
}
|
|
36
|
+
dir = path.dirname(dir);
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
/** Walk up from this module until we find pr-checkmate's own package root. */
|
|
41
|
+
export function findOwnPackageRoot() {
|
|
42
|
+
return findPackageRootByName(__dirname, OWN_PACKAGE_NAME);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Resolve a dependency's install directory by name, starting the search from
|
|
46
|
+
* `fromDir`. Relies on Node's upward node_modules walk so hoisted packages are
|
|
47
|
+
* found regardless of physical layout.
|
|
48
|
+
*/
|
|
49
|
+
function resolvePackageDir(name, fromDir) {
|
|
50
|
+
// Prefer the explicit package.json subpath.
|
|
51
|
+
try {
|
|
52
|
+
return path.dirname(require.resolve(`${name}/package.json`, { paths: [fromDir] }));
|
|
53
|
+
}
|
|
54
|
+
catch { }
|
|
55
|
+
// Fallback for packages whose exports map hides ./package.json: resolve the
|
|
56
|
+
// entry point and walk up to the package's own root.
|
|
57
|
+
try {
|
|
58
|
+
const entryDir = path.dirname(require.resolve(name, { paths: [fromDir] }));
|
|
59
|
+
return findPackageRootByName(entryDir, name);
|
|
60
|
+
}
|
|
61
|
+
catch { }
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Compute the full set of package names in pr-checkmate's own dependency
|
|
66
|
+
* closure (direct + transitive runtime dependencies), plus pr-checkmate itself.
|
|
67
|
+
*
|
|
68
|
+
* pr-checkmate installs into the consumer's node_modules, so its own runtime
|
|
69
|
+
* deps (eslint plugins, cspell dictionaries, …) become part of the consumer's
|
|
70
|
+
* production dependency tree. Some carry copyleft licenses that would otherwise
|
|
71
|
+
* trip pr-checkmate's own license check against an innocent client. These are
|
|
72
|
+
* pr-checkmate's dependencies, not the client's, so they must be exempt.
|
|
73
|
+
*
|
|
74
|
+
* Result is cached for the process. Returns a set containing only pr-checkmate
|
|
75
|
+
* itself if the package root cannot be located (defensive; never throws).
|
|
76
|
+
*/
|
|
77
|
+
export function getOwnDependencyClosure() {
|
|
78
|
+
if (cachedClosure)
|
|
79
|
+
return cachedClosure;
|
|
80
|
+
const closure = new Set([OWN_PACKAGE_NAME]);
|
|
81
|
+
const root = findOwnPackageRoot();
|
|
82
|
+
if (!root) {
|
|
83
|
+
cachedClosure = closure;
|
|
84
|
+
return closure;
|
|
85
|
+
}
|
|
86
|
+
// BFS over the dependency graph, resolving each package relative to the parent
|
|
87
|
+
// that declared it so nested (non-hoisted) installs resolve correctly.
|
|
88
|
+
const queue = readDependencyNames(root).map(name => ({
|
|
89
|
+
name,
|
|
90
|
+
fromDir: root,
|
|
91
|
+
}));
|
|
92
|
+
while (queue.length > 0) {
|
|
93
|
+
const { name, fromDir } = queue.shift();
|
|
94
|
+
if (closure.has(name))
|
|
95
|
+
continue;
|
|
96
|
+
closure.add(name);
|
|
97
|
+
const depDir = resolvePackageDir(name, fromDir);
|
|
98
|
+
if (!depDir)
|
|
99
|
+
continue;
|
|
100
|
+
for (const child of readDependencyNames(depDir)) {
|
|
101
|
+
if (!closure.has(child))
|
|
102
|
+
queue.push({ name: child, fromDir: depDir });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
cachedClosure = closure;
|
|
106
|
+
return closure;
|
|
107
|
+
}
|