From da2b3c745ea3312ecf5920d2e3fdb22f4ec15c6b Mon Sep 17 00:00:00 2001 From: Niels Pardon Date: Wed, 23 Sep 2026 15:38:19 +0200 Subject: [PATCH 1/3] build: pin the commitlint toolchain and harden the PR title check Replace the unpinned, inline commitlint setup in the PR title check with a checked-in commitlint.config.js and a package.json / package-lock.json pinning @commitlint/cli and @commitlint/config-conventional at exact versions, matching the shape used by substrait, substrait-java and substrait-rs. --- .github/workflows/pr_title.yml | 96 ++- .gitignore | 3 + .npmrc | 1 + commitlint.config.js | 13 + package-lock.json | 1388 ++++++++++++++++++++++++++++++++ package.json | 11 + renovate.json | 4 +- 7 files changed, 1489 insertions(+), 27 deletions(-) create mode 100644 .npmrc create mode 100644 commitlint.config.js create mode 100644 package-lock.json create mode 100644 package.json diff --git a/.github/workflows/pr_title.yml b/.github/workflows/pr_title.yml index c796dbe5..9fbd6f6a 100644 --- a/.github/workflows/pr_title.yml +++ b/.github/workflows/pr_title.yml @@ -9,13 +9,20 @@ on: pull_request_target: types: [opened, edited, synchronize, reopened] -# Serialize runs for the same PR so the comment job can't race with itself, but -# never cancel in progress: a Dependabot rebase force-pushes and edits the PR -# body at once, firing synchronize and edited on the same commit. Cancelling one -# leaves a cancelled check-run on the head commit that fails the status rollup -# (#198). Letting both finish yields two harmless successes instead. +# Serialize runs for the same PR so the comment job can't race with itself. +# +# cancel-in-progress must stay false: a Dependabot rebase force-pushes and edits +# the PR body at once, firing synchronize and edited on the same commit. +# Cancelling one leaves a cancelled check-run on the head commit that fails the +# status rollup (#198). Letting both finish yields two harmless successes. +# +# queue: max is needed for the same reason. The default, queue: single, allows +# only one pending run and lets a newly arriving run displace it, so the run that +# gets cancelled is simply the waiting one instead of the running one. max allows +# up to 100 pending runs, so both finish. concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + queue: max cancel-in-progress: false # Default to the minimum read-only token for all jobs. @@ -32,39 +39,75 @@ jobs: - uses: actions/setup-node@v7 with: node-version: "24" - - run: npm install @commitlint/config-conventional - - run: > - echo 'module.exports = { - // Bot PR descriptions are not conventional-commit bodies, so do not lint them. - "ignores": [ - // Renovate - (message) => /^This PR contains the following updates:$/m.test(message) - ], - "rules": { - "body-max-line-length": [0, "always", Infinity], - "footer-max-line-length": [0, "always", Infinity], - "body-leading-blank": [0, "always"] - } - }' > .commitlintrc.js + # pull_request_target runs the workflow from the base ref and checks out + # the base ref, so neither this workflow nor commitlint.config.js nor the + # pinned toolchain can be altered by the PR being validated. + - uses: actions/checkout@v7 + with: + # Do not leave the workflow token in .git/config: npm ci runs + # third-party package code in this same workspace. + persist-credentials: false + sparse-checkout: | + commitlint.config.js + package.json + package-lock.json + .npmrc + sparse-checkout-cone-mode: false + # npm ci installs exactly the tree recorded in package-lock.json, so + # neither a new commitlint release nor a compromised transitive dependency + # can change what runs here. --ignore-scripts also blocks install hooks. + - run: npm ci --ignore-scripts + # continue-on-error keeps a lint failure distinguishable from an + # infrastructure failure: only outcome == 'failure' means the title or + # description is genuinely malformed, and only that should be commented on. + # --no-install so this can only run the pinned local CLI, never fetch one. - id: commitlint continue-on-error: true - run: npx commitlint --extends @commitlint/config-conventional --verbose <<< $COMMIT_MSG + run: npx --no-install commitlint --verbose <<< "$COMMIT_MSG" env: COMMIT_MSG: > ${{ github.event.pull_request.title }} ${{ github.event.pull_request.body }} + # Fail this job, rather than the comment job, so that the check which goes + # red is the one whose name describes what is wrong. + - if: steps.commitlint.outcome == 'failure' + run: | + echo "PR title and description do not follow the Conventional Commits specification." >&2 + exit 1 comment: name: Post / remove PR comment runs-on: ubuntu-latest needs: commitlint + # always(), because the lint job now fails when the message is malformed, + # which is exactly when the comment has to be posted. + if: always() && contains(fromJSON('["success", "failure"]'), needs.commitlint.outputs.outcome) permissions: pull-requests: write steps: - uses: actions/github-script@v9 + env: + # Passed through the environment rather than interpolated into the + # script, so a crafted title or body cannot inject JavaScript. + LINTED_TITLE: ${{ github.event.pull_request.title }} + LINTED_BODY: ${{ github.event.pull_request.body }} with: script: | + // queue: max lets two runs for one commit finish, and their order is + // not guaranteed, so an older run could otherwise overwrite a newer + // one's result. Skip if the PR text has moved on since this run's + // event fired; the run for that edit will handle it. + const { data: pr } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + }); + if (pr.title !== process.env.LINTED_TITLE || (pr.body ?? "") !== (process.env.LINTED_BODY ?? "")) { + core.info("PR title or description changed since this run started; leaving it to the newer run."); + return; + } + // Hidden marker used to find this job's comment regardless of wording. const marker = ""; const message = `${marker} @@ -81,7 +124,12 @@ jobs: repo: context.repo.repo, issue_number: context.issue.number, }); - const existing = comments.find((c) => c.body.includes(marker)); + // Match on author as well as marker: the marker is a plain string, so + // anyone quoting this workflow could otherwise have their comment + // deleted on a pass, or suppress the warning on a failure. + const existing = comments.find( + (c) => c.user?.login === "github-actions[bot]" && c.body.includes(marker) + ); if (passed) { // Clean up the comment now that the check passes. @@ -95,7 +143,8 @@ jobs: return; } - // Check failed: post the comment if it isn't already there, then fail the job. + // Check failed: post the comment if it isn't already there. The lint + // job has already gone red, so this job does not need to fail too. if (!existing) { await github.rest.issues.createComment({ owner: context.repo.owner, @@ -104,6 +153,3 @@ jobs: body: message, }); } - core.setFailed( - "PR title and description do not follow the Conventional Commits specification." - ); diff --git a/.gitignore b/.gitignore index ee5cefbd..512501d8 100644 --- a/.gitignore +++ b/.gitignore @@ -145,3 +145,6 @@ src/substrait/_version.py # pixi environments .pixi/* !.pixi/config.toml + +# commitlint toolchain (see package.json) +node_modules/ diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..214c29d1 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +registry=https://registry.npmjs.org/ diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 00000000..3f9ae9bd --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1,13 @@ +module.exports = { + extends: ["@commitlint/config-conventional"], + // Bot PR descriptions are not conventional-commit bodies, so do not lint them. + ignores: [ + // Renovate + (message) => /^This PR contains the following updates:$/m.test(message), + ], + rules: { + "body-max-line-length": [0, "always", Infinity], + "footer-max-line-length": [0, "always", Infinity], + "body-leading-blank": [0, "always"], + }, +}; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..b9d3ca94 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1388 @@ +{ + "name": "substrait-python-commitlint", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "substrait-python-commitlint", + "version": "0.0.0", + "license": "Apache-2.0", + "devDependencies": { + "@commitlint/cli": "21.2.3", + "@commitlint/config-conventional": "21.2.3" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@commitlint/cli": { + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-21.2.3.tgz", + "integrity": "sha512-5yOX6IRjcrIReCxpyAd04hgI/yhUMpVBJ/ouwFV0wk9yx5+fYRDWZWJ5h55Tbedgfol+5m2mU5nqzbB8g3v0vQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/config-conventional": "^21.2.3", + "@commitlint/format": "^21.2.3", + "@commitlint/lint": "^21.2.3", + "@commitlint/load": "^21.2.3", + "@commitlint/read": "^21.2.3", + "@commitlint/types": "^21.2.3", + "tinyexec": "^1.0.0", + "yargs": "^18.0.0" + }, + "bin": { + "commitlint": "cli.js" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/config-conventional": { + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-21.2.3.tgz", + "integrity": "sha512-EP2n5DN2GwRWNVrLX0Jx3mpQlW5PfFi9HnD9OJ8hN/H0xFqpCFyHeGDhg+0P8/21iMMcdkcQgbNqmVklebqYsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^21.2.3", + "conventional-changelog-conventionalcommits": "^10.0.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/config-validator": { + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-21.2.3.tgz", + "integrity": "sha512-JQ13v0GafSM4fBYX8UowSy++07Was20auq0NcTdnzSEq6/05Cq5GBUMIfKkqjzyBwC9sJFmPpKWgLLhH7cygkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^21.2.3", + "ajv": "^8.11.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/ensure": { + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-21.2.3.tgz", + "integrity": "sha512-gEjNKgRocbODI5/sMx2Qc9XOf2/zFTNV2aEK1QZ4gKDKxDC/VR7us3QtIX1C5d5xxHxx0I/tEbYbdSP1Am2LwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^21.2.3", + "es-toolkit": "^1.46.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/execute-rule": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-21.0.1.tgz", + "integrity": "sha512-RifH+FmImozKBE6mozhF4K3r2RRKP7SMi/Q/zLCmExtp5e05lhHOUYqGBlFBAGNHaZxU/WYw1XuugYK9jQzqnA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/format": { + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-21.2.3.tgz", + "integrity": "sha512-KKwCjXYqA8r295uhLnulDXL9yekdXmj2yp2Q0XsBPhxQ2iPuvRE8F43j7g7yexo69wTdmUQmFz15jpderluzUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^21.2.3", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/is-ignored": { + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-21.2.3.tgz", + "integrity": "sha512-Ng4nRj/LBAOvc+GQu7bsFW4/fL89LvZ14OOC/ERLbUpnG6QBwWRzY/1oXGwPs3C8YHWjJObin4kLYo2YeEn70w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^21.2.3", + "semver": "^7.6.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/lint": { + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-21.2.3.tgz", + "integrity": "sha512-lUZcSuVLLEDkhge9ERk8Rp+FXQtrUhCK+h328BFnzKXrTuXGdqiYMEpTlNWdZaOrjyMhMJaz354ZaWEGJxcLeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/is-ignored": "^21.2.3", + "@commitlint/parse": "^21.2.3", + "@commitlint/rules": "^21.2.3", + "@commitlint/types": "^21.2.3" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/load": { + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-21.2.3.tgz", + "integrity": "sha512-cDrL8lOo23Lk7knGzQdjbFcq7z2JgvjwV6PhbESVvEc+Fe21MeLjPKBJi8nKjg7j+jh79CVbVSUbZc104thXRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/config-validator": "^21.2.3", + "@commitlint/execute-rule": "^21.0.1", + "@commitlint/resolve-extends": "^21.2.3", + "@commitlint/types": "^21.2.3", + "cosmiconfig": "^9.0.1", + "cosmiconfig-typescript-loader": "^6.1.0", + "es-toolkit": "^1.46.0", + "is-plain-obj": "^4.1.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/message": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-21.2.0.tgz", + "integrity": "sha512-YxGoiXD/HXNXLJPrQwE5poXa+XH0CBEm+mdvbHQP0g6MV/dmJyUFCzPNzZbxL93GvZ70TmtTK0Z0/IBpAqHv8g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/parse": { + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-21.2.3.tgz", + "integrity": "sha512-Jt61QpF1xA88damCELe8I0FlDZPSpXNc8IhN7z5kZ0EcDYPjdZ+ZHPvsSXl69r2MIlLnNKeHhOn2cmVpziFE9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^21.2.3", + "conventional-changelog-angular": "^9.0.0", + "conventional-commits-parser": "^7.0.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/read": { + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-21.2.3.tgz", + "integrity": "sha512-szAepuLA1vTTr7fuudEg7jYyVHudf+FH+vptU91bhxE1WnE8TKrfTAi44HVllz8XpI8Pvp4GjR/iP5Nshgh+og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/top-level": "^21.2.0", + "@commitlint/types": "^21.2.3", + "@conventional-changelog/git-client": "^3.0.0", + "tinyexec": "^1.0.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/resolve-extends": { + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-21.2.3.tgz", + "integrity": "sha512-bqJdmAtXgAQel+l02uIsF7rHgKgx1AGZdGBjam7uK4XW54ZAQtB6XAIUXezYprQiCcRMpBh4fHs5JodXK4mVZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/config-validator": "^21.2.3", + "@commitlint/types": "^21.2.3", + "es-toolkit": "^1.46.0", + "global-directory": "^5.0.0", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/rules": { + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-21.2.3.tgz", + "integrity": "sha512-5+YnI/LuTx3JDl9GjqfP2z9x96M8KKDrd+4jOel/T0L1BB3oAmBlSN8xppf63QsudiVEgR8C0gRoAMrPVrms6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/ensure": "^21.2.3", + "@commitlint/message": "^21.2.0", + "@commitlint/to-lines": "^21.0.1", + "@commitlint/types": "^21.2.3" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/to-lines": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-21.0.1.tgz", + "integrity": "sha512-bd1BFII7p1EQZre9Kaj+kKaMFP3cFCdt21K7DItVux9XP5WjLgJ0/Uy1pJJh9aPwVJ6SKg62PxqlZaHI8hQAXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/top-level": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-21.2.0.tgz", + "integrity": "sha512-Y5gmQ+KxzqCrBFJfLvFEPvvwD3LDiNZoTT2yeFBm96M8qhmqSzQc5DvX3rheAaAMjyIvMXOCLS/mWfdpONsjyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/types": { + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-21.2.3.tgz", + "integrity": "sha512-sGEA473TlCvhCGNoTBY9OXZVWdscIXdGt0dm8EpB+2MRfmt8LNh/X56P/T3nCtEB+eH5qGEa3odphSAoUxSfSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "conventional-commits-parser": "^7.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@conventional-changelog/git-client": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-3.1.2.tgz", + "integrity": "sha512-jZqwnJwf7nboIlAcw/mkOjVa6DexCcUOgT2oOQgkoi3z9vR8tGFkcMy2BFcYwjhL9sYcDDXkRQDayiDieCoW7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-libs/child-process-utils": "^2.0.0", + "@simple-libs/stream-utils": "^2.0.0", + "semver": "^7.5.2" + }, + "engines": { + "node": ">=22" + }, + "peerDependencies": { + "conventional-commits-filter": "^6.0.1", + "conventional-commits-parser": "^7.1.2" + }, + "peerDependenciesMeta": { + "conventional-commits-filter": { + "optional": true + }, + "conventional-commits-parser": { + "optional": true + } + } + }, + "node_modules/@conventional-changelog/template": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@conventional-changelog/template/-/template-1.4.0.tgz", + "integrity": "sha512-aalGyl7dbB5PArRebDIX43ZvBlXrYm9uWzGJ26t+4SzJVPsOuvfILGGbw5X4yX7i50YEmJ8zvbiWnqH/AAnZqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22" + } + }, + "node_modules/@simple-libs/child-process-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@simple-libs/child-process-utils/-/child-process-utils-2.0.0.tgz", + "integrity": "sha512-dvNoRKLijXnD0XoJAz94pbNuB5GQgDr55UhpSPhffDkTT0Cmcqh9jSCOtwfT2d4H6MI9E7c4SgtMuJXZ6F3c6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-libs/stream-utils": "^2.0.0" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://ko-fi.com/dangreen" + } + }, + "node_modules/@simple-libs/stream-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@simple-libs/stream-utils/-/stream-utils-2.0.0.tgz", + "integrity": "sha512-fCTuZK4QBa+39Oz9l4OGfJfz+GpwCp3AqO7Zch3to99xHPgstVsRFpeQ8LNd2o1Gv8raL2mCFwiaHh7bFSp5DQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://ko-fi.com/dangreen" + } + }, + "node_modules/@types/node": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.2.tgz", + "integrity": "sha512-X1P21scMv4zGKLYqjdGjaKa7COa0RKVYYZZN/NfvLQ1JegxFhdhpZG/Lyn8AXx6CDUavKAd11v6BvfpkDByK8g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "undici-types": "~8.9.0" + } + }, + "node_modules/@typescript/typescript-aix-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", + "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "aix" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz", + "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz", + "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz", + "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz", + "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz", + "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz", + "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-loong64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz", + "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-mips64el": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz", + "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz", + "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-riscv64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz", + "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-s390x": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz", + "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz", + "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz", + "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz", + "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz", + "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz", + "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-sunos-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz", + "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "sunos" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz", + "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz", + "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/argue-cli": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/argue-cli/-/argue-cli-3.2.0.tgz", + "integrity": "sha512-VipTB0gXgGIFO2Rg9yEVN5wLt2AurJcZqDbgmYSwPwsykhLrQhs240/bfceev4w68lI8JshoOJIk9uW7tFzROw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://ko-fi.com/dangreen" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/conventional-changelog-angular": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-9.4.0.tgz", + "integrity": "sha512-HdxRxuS8bBXVIuo4V82gvSwAXT0vYQUizrjs/izmPg5JdDstr8v8I5hduGL3iQbG+o310dUDxC4+LetuS5hu9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@conventional-changelog/template": "^1.4.0" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/conventional-changelog-conventionalcommits": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-10.4.0.tgz", + "integrity": "sha512-Rriac6ZrAlVm6cy9Bz4NSp+WMHpwNXoPIYex+HjCgduAVUSbnew29DQjQw0C4g9u3HtSYzGiGY+pdBXAZo+4aA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@conventional-changelog/template": "^1.4.0" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/conventional-commits-parser": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-7.1.2.tgz", + "integrity": "sha512-O+x4N2yH+ijvqWlIyTHsXTAP+algNWgGbjY2duCe8w2vUMvUB95cLRslCPfTMQyLAKlet3bhZTdu6ozn4M+QJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-libs/stream-utils": "^2.0.0", + "argue-cli": "^3.1.0" + }, + "bin": { + "conventional-commits-parser": "dist/cli/index.js" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/cosmiconfig": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.2.tgz", + "integrity": "sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig-typescript-loader": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.3.0.tgz", + "integrity": "sha512-Akr82WH1Wfqatyiqpj8HDkO2o2KmJRu1FhKfSNJP3K4IdXwHfEyL7MOb62i1AGQVLtIQM+iCE9CGOtrfhR+mmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jiti": "2.6.1" + }, + "engines": { + "node": ">=v18" + }, + "peerDependencies": { + "@types/node": "*", + "cosmiconfig": ">=9", + "typescript": ">=5" + } + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-toolkit": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.52.0.tgz", + "integrity": "sha512-XTNEJQh1tY1ZJVcf6ayP/2n4ZPyaHlW2FWs7xvw5ddPuhUVjLD3olQVQS7kf58JbAB48iL0uL/jerTrjtV3lDA==", + "dev": true, + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks", + "tests/types", + "tests/browser-compat" + ] + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.7.0.tgz", + "integrity": "sha512-XjH1AECxf0giL2V1aU8vKyRR2ppRUb5c0EvT7zuJTokQ74bNo52zOtghqdWIqrhUD79fo3x0WfKZdOqxF6LG1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-directory": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-5.0.0.tgz", + "integrity": "sha512-1pgFdhK3J2LeM+dVf2Pd424yHx2ou338lC0ErNP2hPx4j8eW1Sp0XqSjNxtk6Tc4Kr5wlWtSvz8cn2yb7/SG/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "6.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ini": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", + "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.2.tgz", + "integrity": "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/tinyexec": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz", + "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/typescript": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc" + }, + "engines": { + "node": ">=16.20.0" + }, + "optionalDependencies": { + "@typescript/typescript-aix-ppc64": "7.0.2", + "@typescript/typescript-darwin-arm64": "7.0.2", + "@typescript/typescript-darwin-x64": "7.0.2", + "@typescript/typescript-freebsd-arm64": "7.0.2", + "@typescript/typescript-freebsd-x64": "7.0.2", + "@typescript/typescript-linux-arm": "7.0.2", + "@typescript/typescript-linux-arm64": "7.0.2", + "@typescript/typescript-linux-loong64": "7.0.2", + "@typescript/typescript-linux-mips64el": "7.0.2", + "@typescript/typescript-linux-ppc64": "7.0.2", + "@typescript/typescript-linux-riscv64": "7.0.2", + "@typescript/typescript-linux-s390x": "7.0.2", + "@typescript/typescript-linux-x64": "7.0.2", + "@typescript/typescript-netbsd-arm64": "7.0.2", + "@typescript/typescript-netbsd-x64": "7.0.2", + "@typescript/typescript-openbsd-arm64": "7.0.2", + "@typescript/typescript-openbsd-x64": "7.0.2", + "@typescript/typescript-sunos-x64": "7.0.2", + "@typescript/typescript-win32-arm64": "7.0.2", + "@typescript/typescript-win32-x64": "7.0.2" + } + }, + "node_modules/undici-types": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz", + "integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.2.0.tgz", + "integrity": "sha512-9OpKOLeaoNFecEp7P6iYbzze/5CqWoH7N3SMs/6y1XF4nMvFMspEGZzJ6uFi9MmQwXhyzqYoSEKO3tvA3Z/o2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^8.2.1", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..2836e069 --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "name": "substrait-python-commitlint", + "version": "0.0.0", + "private": true, + "description": "Pinned commitlint toolchain used to lint PR titles and descriptions in CI. Development tooling only; not a dependency of the published Python package.", + "license": "Apache-2.0", + "devDependencies": { + "@commitlint/cli": "21.2.3", + "@commitlint/config-conventional": "21.2.3" + } +} diff --git a/renovate.json b/renovate.json index 8a00cdc8..e6da6936 100644 --- a/renovate.json +++ b/renovate.json @@ -33,8 +33,8 @@ "semanticCommitScope": "deps-dev" }, { - "description": "Match the deps-dev scope dependabot used for development dependencies", - "matchDepTypes": ["dependency-groups"], + "description": "Match the deps-dev scope dependabot used for development dependencies, including the commitlint toolchain in package.json", + "matchDepTypes": ["dependency-groups", "devDependencies"], "semanticCommitScope": "deps-dev" }, { From ddb9420d6c8098bce4953c477a6de37887e52efc Mon Sep 17 00:00:00 2001 From: Niels Pardon Date: Wed, 23 Sep 2026 16:11:42 +0200 Subject: [PATCH 2/3] fix: decide the PR title check from the PR's current text The lint step read the title and body from the triggering event's payload. That payload can be stale: queue: max allows several runs to wait at once, the order they are released in is not guaranteed, and GitHub decides a required check from the most recent check run of that name -- so a corrected title could be overruled by an older run and leave the check stuck red with no further event to clear it. Fetch the PR's current title and body instead, so the verdict does not depend on run order, and hand them to the comment job as outputs so its freshness check compares against the text that was actually linted. --- .github/workflows/pr_title.yml | 57 +++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/.github/workflows/pr_title.yml b/.github/workflows/pr_title.yml index 9fbd6f6a..9d2b7807 100644 --- a/.github/workflows/pr_title.yml +++ b/.github/workflows/pr_title.yml @@ -33,8 +33,16 @@ jobs: commitlint: name: PR title / description conforms to semantic-release runs-on: ubuntu-latest + permissions: + # contents for the checkout below, pull-requests to read the PR's current + # title and body. A job-level permissions block replaces the workflow + # default outright rather than adding to it, so both must be listed. + contents: read + pull-requests: read outputs: outcome: ${{ steps.commitlint.outcome }} + title: ${{ steps.pr.outputs.title }} + body: ${{ steps.pr.outputs.body }} steps: - uses: actions/setup-node@v7 with: @@ -57,18 +65,39 @@ jobs: # neither a new commitlint release nor a compromised transitive dependency # can change what runs here. --ignore-scripts also blocks install hooks. - run: npm ci --ignore-scripts + # Lint the PR's text as it is now, not as the triggering event captured + # it. This job is the required status check, and GitHub decides it from + # the most recent check run of this name, so whichever run finishes last + # must not be deciding it from a payload that has since been superseded. + # queue: max lets several runs wait at once and the order they are + # released in is not guaranteed, so a title that has since been corrected + # could otherwise be overruled by an older run and leave the check stuck + # red, with no further event to clear it. Reading the current text here + # makes the verdict independent of run order in both directions. + - id: pr + uses: actions/github-script@v9 + with: + script: | + const { data: pr } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + }); + core.setOutput("title", pr.title); + core.setOutput("body", pr.body ?? ""); + // Written to a file rather than passed as an argument or a shell + // variable, so the untrusted text never reaches a command line. + require("node:fs").writeFileSync( + `${process.env.RUNNER_TEMP}/commit-msg.txt`, + `${pr.title}\n\n${pr.body ?? ""}`, + ); # continue-on-error keeps a lint failure distinguishable from an # infrastructure failure: only outcome == 'failure' means the title or # description is genuinely malformed, and only that should be commented on. # --no-install so this can only run the pinned local CLI, never fetch one. - id: commitlint continue-on-error: true - run: npx --no-install commitlint --verbose <<< "$COMMIT_MSG" - env: - COMMIT_MSG: > - ${{ github.event.pull_request.title }} - - ${{ github.event.pull_request.body }} + run: npx --no-install commitlint --verbose < "$RUNNER_TEMP/commit-msg.txt" # Fail this job, rather than the comment job, so that the check which goes # red is the one whose name describes what is wrong. - if: steps.commitlint.outcome == 'failure' @@ -88,16 +117,16 @@ jobs: steps: - uses: actions/github-script@v9 env: - # Passed through the environment rather than interpolated into the - # script, so a crafted title or body cannot inject JavaScript. - LINTED_TITLE: ${{ github.event.pull_request.title }} - LINTED_BODY: ${{ github.event.pull_request.body }} + # The text the lint job actually linted, passed through the + # environment rather than interpolated into the script so that a + # crafted title or body cannot inject JavaScript. + LINTED_TITLE: ${{ needs.commitlint.outputs.title }} + LINTED_BODY: ${{ needs.commitlint.outputs.body }} with: script: | - // queue: max lets two runs for one commit finish, and their order is - // not guaranteed, so an older run could otherwise overwrite a newer - // one's result. Skip if the PR text has moved on since this run's - // event fired; the run for that edit will handle it. + // Skip if the PR text has moved on since the lint job read it: + // the run for that edit will post or clear the comment, and an + // older run must not undo a newer one's result. const { data: pr } = await github.rest.pulls.get({ owner: context.repo.owner, repo: context.repo.repo, From 721cff02b945c9b766b82d3ae4b8a782b183489d Mon Sep 17 00:00:00 2001 From: Niels Pardon Date: Tue, 13 Oct 2026 08:24:56 +0200 Subject: [PATCH 3/3] build: drop the Renovate commitlint exception Renovate's PR descriptions already lint cleanly now that line-length limits are off, and the multiline match skipped the whole message, header included, for any body containing that line. --- commitlint.config.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/commitlint.config.js b/commitlint.config.js index 3f9ae9bd..3a294e23 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -1,10 +1,5 @@ module.exports = { extends: ["@commitlint/config-conventional"], - // Bot PR descriptions are not conventional-commit bodies, so do not lint them. - ignores: [ - // Renovate - (message) => /^This PR contains the following updates:$/m.test(message), - ], rules: { "body-max-line-length": [0, "always", Infinity], "footer-max-line-length": [0, "always", Infinity],