diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bc66a7fd02..81947b0dff 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,8 +18,8 @@ jobs: name: release runs-on: ubuntu-latest steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 with: cache: npm node-version: lts/* diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index e2273400ca..1304938835 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -15,22 +15,22 @@ jobs: id-token: write steps: - name: Checkout code - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: persist-credentials: false - name: Run analysis - uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3 + uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 with: results_file: results.sarif results_format: sarif publish_results: true - name: Upload artifact - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6 with: name: SARIF file path: results.sarif retention-days: 5 - name: Upload to code-scanning - uses: github/codeql-action/upload-sarif@f079b8493333aace61c81488f8bd40919487bd9f # v3.25.7 + uses: github/codeql-action/upload-sarif@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa # v3.26.0 with: sarif_file: results.sarif diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 94bf3de9db..5d23e594f7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -33,11 +33,11 @@ jobs: timeout-minutes: 5 steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - run: git config --global user.name github-actions - run: git config --global user.email github-actions@github.com - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 with: node-version: ${{ matrix.node-version }} cache: npm @@ -51,11 +51,11 @@ jobs: timeout-minutes: 5 steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - run: git config --global user.name github-actions - run: git config --global user.email github-actions@github.com - name: Use Node.js from .nvmrc - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 with: node-version-file: .nvmrc cache: npm diff --git a/README.md b/README.md index 4870be70fe..28458c3011 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ Join the community on GitHub Discussions - - Build states + + Build states OpenSSF Scorecard diff --git a/docs/developer-guide/plugin.md b/docs/developer-guide/plugin.md index febbfaaae7..46670ff616 100644 --- a/docs/developer-guide/plugin.md +++ b/docs/developer-guide/plugin.md @@ -241,7 +241,7 @@ if (env.GITHUB_TOKEN) { ## Logger -Use `context.logger` to provide debug logging in the plugin. +Use `context.logger` to provide debug logging in the plugin. Available logging functions: `log`, `warn`, `success`, `error`. ```js const { logger } = context; diff --git a/docs/extending/plugins-list.md b/docs/extending/plugins-list.md index 26d544355a..9467d71843 100644 --- a/docs/extending/plugins-list.md +++ b/docs/extending/plugins-list.md @@ -198,3 +198,5 @@ - `verifyConditions` Verify configuration options and existance of GitHub token. - `analyzeCommits` Determine the type of release by analyzing merged GitHub pull requests and their labels. - `generateNotes` Generates release notes using [GitHub release notes generator](https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes). +- [semantic-release-commits-lint](https://github.com/BondarenkoAlex/semantic-release-commits-lint) + - `analyzeCommits` Analyzing commit messages by [commitlint](https://github.com/conventional-changelog/commitlint). diff --git a/docs/support/FAQ.md b/docs/support/FAQ.md index fbf42e07fe..05528dc031 100644 --- a/docs/support/FAQ.md +++ b/docs/support/FAQ.md @@ -119,7 +119,7 @@ Here is a basic example to create [GitHub releases](https://help.github.com/arti **Note**: This is a theoretical example where the command `set-version` update the project version with the value passed as its first argument and `publish-package` publishes the package to a registry. -See the [package managers and languages recipes](../recipes/release-workflow/README.md#package-managers-and-languages) for more details on specific project types. +See the [package managers and languages recipes](../recipes/release-workflow/README.md#package-managers-and-languages) for more details on specific project types and the [available plugins list](../extending/plugins-list.md) to see if there are community-supported plugins already available for the stack you are interested in. ## Can I use semantic-release with any CI service? diff --git a/docs/usage/installation.md b/docs/usage/installation.md index b545d947cf..9361083c30 100644 --- a/docs/usage/installation.md +++ b/docs/usage/installation.md @@ -29,9 +29,8 @@ npx semantic-release 1. If you've globally installed **semantic-release** then we recommend that you set the major **semantic-release** version to install. For example, by using `npx semantic-release@18`. This way you control which major version of **semantic-release** is used by your build, and thus avoid breaking the build when there's a new major version of **semantic-release**. - This also means you, or a bot, must upgrade **semantic-release** when a new major version is released. 2. Pinning **semantic-release** to an exact version makes your releases even more deterministic. - But pinning also means you, or a bot, must update to newer versions of **semantic-release** more often. + But pinning also means you, or a bot, must upgrade **semantic-release** when a new version is released. 3. You can use [Renovate's regex manager](https://docs.renovatebot.com/modules/manager/regex/) to get automatic updates for **semantic-release** in either of the above scenarios. Put this in your Renovate configuration file: ```json diff --git a/index.d.ts b/index.d.ts index da405b9125..f2456a78e6 100644 --- a/index.d.ts +++ b/index.d.ts @@ -38,9 +38,9 @@ declare module "semantic-release" { /** * Signale console loger instance. * - * Has error, log and success methods. + * Has error, log, warn and success methods. */ - logger: Signale<"error" | "log" | "success">; + logger: Signale<"error" | "log" | "success" | "warn">; } /** diff --git a/lib/get-logger.js b/lib/get-logger.js index 889198f0c5..48c73d2079 100644 --- a/lib/get-logger.js +++ b/lib/get-logger.js @@ -14,5 +14,6 @@ export default ({ stdout, stderr }) => error: { badge: figures.cross, color: "red", label: "", stream: [stderr] }, log: { badge: figures.info, color: "magenta", label: "", stream: [stdout] }, success: { badge: figures.tick, color: "green", label: "", stream: [stdout] }, + warn: { badge: figures.warning, color: "yellow", label: "", stream: [stderr] }, }, }); diff --git a/package-lock.json b/package-lock.json index 98dea3facc..b45849930f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,25 +44,25 @@ }, "devDependencies": { "ava": "6.1.3", - "c8": "9.1.0", + "c8": "10.1.2", "clear-module": "4.1.2", "codecov": "3.8.3", "cz-conventional-changelog": "3.3.0", "dockerode": "4.0.2", "file-url": "4.0.0", "fs-extra": "11.2.0", - "got": "14.3.0", + "got": "14.4.2", "js-yaml": "4.1.0", - "lockfile-lint": "4.13.2", - "ls-engines": "0.9.1", + "lockfile-lint": "4.14.0", + "ls-engines": "0.9.3", "mockserver-client": "5.15.0", "nock": "13.5.4", - "npm-run-all2": "6.2.0", + "npm-run-all2": "6.2.2", "p-retry": "6.2.0", - "prettier": "3.2.5", - "publint": "0.2.8", + "prettier": "3.3.3", + "publint": "0.2.10", "sinon": "18.0.0", - "stream-buffers": "3.0.2", + "stream-buffers": "3.0.3", "tempy": "3.1.0", "testdouble": "3.20.2" }, @@ -71,12 +71,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", - "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "license": "MIT", "dependencies": { - "@babel/highlight": "^7.24.2", + "@babel/highlight": "^7.24.7", "picocolors": "^1.0.0" }, "engines": { @@ -84,21 +84,21 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", - "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", - "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.24.5", + "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -214,9 +214,9 @@ } }, "node_modules/@commitlint/load": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-19.2.0.tgz", - "integrity": "sha512-XvxxLJTKqZojCxaBQ7u92qQLFMMZc4+p9qrIq/9kJDy8DOrEa7P1yx7Tjdc2u2JxIalqT4KOGraVgCE7eCYJyQ==", + "version": "19.4.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-19.4.0.tgz", + "integrity": "sha512-I4lCWaEZYQJ1y+Y+gdvbGAx9pYPavqZAZ3/7/8BpWh+QjscAn8AjsUpLV2PycBsEx7gupq5gM4BViV9xwTIJuw==", "dev": true, "license": "MIT", "optional": true, @@ -366,9 +366,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true, "license": "MIT" }, @@ -538,6 +538,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-4.0.2.tgz", "integrity": "sha512-ncSWAawFhKMJDTdoAeOV+jyW1VCMj5QIAwULIBV0SSR7B/RLPPEQiknKcg/RIIZlUQrxELpsxMiTUoAQ4sIUyg==", + "deprecated": "This package is no longer supported.", "dev": true, "license": "ISC", "engines": { @@ -565,6 +566,7 @@ "version": "5.0.2", "resolved": "https://registry.npmjs.org/gauge/-/gauge-5.0.2.tgz", "integrity": "sha512-pMaFftXPtiGIHCJHdcUUx9Rby/rFT/Kkt3fIIGCs+9PMDIljSyRiqraTlxNtBReJRDfUefpa263RQ3vnp5G/LQ==", + "deprecated": "This package is no longer supported.", "dev": true, "license": "ISC", "dependencies": { @@ -615,9 +617,9 @@ } }, "node_modules/@npmcli/arborist/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", "dependencies": { @@ -650,6 +652,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-7.0.1.tgz", "integrity": "sha512-uJ0YFk/mCQpLBt+bxN88AKd+gyqZvZDbtiNxk6Waqcj2aPRyfVx8ITawkyQynxUagInjdYT1+qj4NfA5KJJUxg==", + "deprecated": "This package is no longer supported.", "dev": true, "license": "ISC", "dependencies": { @@ -793,32 +796,30 @@ } }, "node_modules/@npmcli/map-workspaces/node_modules/glob": { - "version": "10.3.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.15.tgz", - "integrity": "sha512-0c6RlJt1TICLyvJYIApxb8GsXoai0KUP7AxKKAtsYXdgJR1mGEUa7DgwShbdk1nly0PYoZj01xd4hzbq3fsjpw==", + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.6", - "minimatch": "^9.0.1", - "minipass": "^7.0.4", - "path-scurry": "^1.11.0" + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/@npmcli/map-workspaces/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", "dependencies": { @@ -912,24 +913,22 @@ } }, "node_modules/@npmcli/package-json/node_modules/glob": { - "version": "10.3.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.15.tgz", - "integrity": "sha512-0c6RlJt1TICLyvJYIApxb8GsXoai0KUP7AxKKAtsYXdgJR1mGEUa7DgwShbdk1nly0PYoZj01xd4hzbq3fsjpw==", + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.6", - "minimatch": "^9.0.1", - "minipass": "^7.0.4", - "path-scurry": "^1.11.0" + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -958,9 +957,9 @@ } }, "node_modules/@npmcli/package-json/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", "dependencies": { @@ -1109,9 +1108,9 @@ "license": "MIT" }, "node_modules/@octokit/plugin-paginate-rest": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.3.0.tgz", - "integrity": "sha512-n4znWfRinnUQF6TPyxs7EctSAA3yVSP4qlJP2YgI3g9d4Ae2n5F3XDOjbUluKRxPU3rfsgpOboI4O4VtPc6Ilg==", + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.3.3.tgz", + "integrity": "sha512-o4WRoOJZlKqEEgj+i9CpcmnByvtzoUYC6I8PD2SA95M+BJ2x8h7oLcVOg9qcowWXBOdcTRsMZiwvM3EyLm9AfA==", "license": "MIT", "dependencies": { "@octokit/types": "^13.5.0" @@ -1141,9 +1140,9 @@ } }, "node_modules/@octokit/plugin-throttling": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-9.3.0.tgz", - "integrity": "sha512-B5YTToSRTzNSeEyssnrT7WwGhpIdbpV9NKIs3KyTWHX6PhpYn7gqF/+lL3BvsASBM3Sg5BAUYk7KZx5p/Ec77w==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-9.3.1.tgz", + "integrity": "sha512-Qd91H4liUBhwLB2h6jZ99bsxoQdhgPk6TdwnClPyTBSDAdviGPceViEgUwj+pcQDmB/rfAXAXK7MTochpHM3yQ==", "license": "MIT", "dependencies": { "@octokit/types": "^13.0.0", @@ -1157,9 +1156,9 @@ } }, "node_modules/@octokit/request": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.1.1.tgz", - "integrity": "sha512-pyAguc0p+f+GbQho0uNetNQMmLG1e80WjkIaqqgUkihqUp0boRU6nKItXO4VWnr+nbZiLGEyy4TeKRwqaLvYgw==", + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.1.3.tgz", + "integrity": "sha512-V+TFhu5fdF3K58rs1pGUJIDH5RZLbZm5BI+MNF+6o/ssFNT4vWlCh/tVpF3NxGtP15HUxTTMUbsG5llAuU2CZA==", "license": "MIT", "dependencies": { "@octokit/endpoint": "^10.0.0", @@ -1172,9 +1171,9 @@ } }, "node_modules/@octokit/request-error": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.1.tgz", - "integrity": "sha512-1mw1gqT3fR/WFvnoVpY/zUM2o/XkMs/2AszUUG9I69xn0JFLv6PGkPhNk5lbfvROs79wiS0bqiJNxfCZcRJJdg==", + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.4.tgz", + "integrity": "sha512-VpAhIUxwhWZQImo/dWAN/NpPqqojR6PSLgLYAituLM6U+ddx9hCioFGwBr5Mi+oi5CLeJkcAs3gJ0PYYzU6wUg==", "license": "MIT", "dependencies": { "@octokit/types": "^13.0.0" @@ -1231,9 +1230,9 @@ "license": "ISC" }, "node_modules/@pnpm/npm-conf": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz", - "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.3.1.tgz", + "integrity": "sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==", "license": "MIT", "dependencies": { "@pnpm/config.env-replace": "^1.1.0", @@ -1278,9 +1277,9 @@ "license": "MIT" }, "node_modules/@semantic-release/commit-analyzer": { - "version": "13.0.0-beta.1", - "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-13.0.0-beta.1.tgz", - "integrity": "sha512-hCkPVtFQ2El8Ngb4TbYauG4D1ZgG9foLFPdGbLlRgweLhCEsCXk1+Ov+4fdzbnUG7qnPaagJZG8Q0s9yx3k0eQ==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-13.0.0.tgz", + "integrity": "sha512-KtXWczvTAB1ZFZ6B4O+w8HkfYm/OgQb1dUGNFZtDgQ0csggrmkq8sTxhd+lwGF8kMb59/RnG9o4Tn7M/I8dQ9Q==", "license": "MIT", "dependencies": { "conventional-changelog-angular": "^8.0.0", @@ -1299,50 +1298,6 @@ "semantic-release": ">=20.1.0" } }, - "node_modules/@semantic-release/commit-analyzer/node_modules/conventional-changelog-angular": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.0.0.tgz", - "integrity": "sha512-CLf+zr6St0wIxos4bmaKHRXWAcsCXrJU6F4VdNDrGRK3B8LDLKoX3zuMV5GhtbGkVR/LohZ6MT6im43vZLSjmA==", - "dependencies": { - "compare-func": "^2.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@semantic-release/commit-analyzer/node_modules/conventional-commits-filter": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-5.0.0.tgz", - "integrity": "sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==", - "engines": { - "node": ">=18" - } - }, - "node_modules/@semantic-release/commit-analyzer/node_modules/conventional-commits-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.0.0.tgz", - "integrity": "sha512-TbsINLp48XeMXR8EvGjTnKGsZqBemisPoyWESlpRyR8lif0lcwzqz+NMtYSj1ooF/WYjSuu7wX0CtdeeMEQAmA==", - "dependencies": { - "meow": "^13.0.0" - }, - "bin": { - "conventional-commits-parser": "dist/cli/index.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@semantic-release/commit-analyzer/node_modules/meow": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", - "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@semantic-release/error": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz", @@ -1353,9 +1308,9 @@ } }, "node_modules/@semantic-release/github": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-10.0.4.tgz", - "integrity": "sha512-eHCfW3jlzax5OKd5nTovlvoCdg+b9YBa31M2JGT1KmzmJR3TIalu2ahVU+V/xATVeOx+S8fbCiPnBBgMlzH5Vw==", + "version": "10.1.4", + "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-10.1.4.tgz", + "integrity": "sha512-dg+JTNp1XHazwAx9HgIuVewStfpv5g7QqwBF09aZVqwVkdTXw4agR/nhWSD0yxDbsx0YCeJTcjUOj92gf8/0Jw==", "license": "MIT", "dependencies": { "@octokit/core": "^6.0.0", @@ -1410,9 +1365,9 @@ } }, "node_modules/@semantic-release/release-notes-generator": { - "version": "14.0.0-beta.1", - "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-14.0.0-beta.1.tgz", - "integrity": "sha512-L2U1UCHaW7+K3wDhmrtDNV9WbrTZMTYBRUYVYdpX+YZd0yNDKCwOCkr+xBYW+UPWG686bkXXsx+PqhJTJRX2Ug==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-14.0.1.tgz", + "integrity": "sha512-K0w+5220TM4HZTthE5dDpIuFrnkN1NfTGPidJFm04ULT1DEZ9WG89VNXN7F0c+6nMEpWgqmPvb7vY7JkB2jyyA==", "license": "MIT", "dependencies": { "conventional-changelog-angular": "^8.0.0", @@ -1424,7 +1379,7 @@ "import-from-esm": "^1.0.3", "into-stream": "^7.0.0", "lodash-es": "^4.17.21", - "read-pkg-up": "^11.0.0" + "read-package-up": "^11.0.0" }, "engines": { "node": ">=20.8.1" @@ -1433,39 +1388,6 @@ "semantic-release": ">=20.1.0" } }, - "node_modules/@semantic-release/release-notes-generator/node_modules/conventional-changelog-angular": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.0.0.tgz", - "integrity": "sha512-CLf+zr6St0wIxos4bmaKHRXWAcsCXrJU6F4VdNDrGRK3B8LDLKoX3zuMV5GhtbGkVR/LohZ6MT6im43vZLSjmA==", - "dependencies": { - "compare-func": "^2.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@semantic-release/release-notes-generator/node_modules/conventional-commits-filter": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-5.0.0.tgz", - "integrity": "sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==", - "engines": { - "node": ">=18" - } - }, - "node_modules/@semantic-release/release-notes-generator/node_modules/conventional-commits-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.0.0.tgz", - "integrity": "sha512-TbsINLp48XeMXR8EvGjTnKGsZqBemisPoyWESlpRyR8lif0lcwzqz+NMtYSj1ooF/WYjSuu7wX0CtdeeMEQAmA==", - "dependencies": { - "meow": "^13.0.0" - }, - "bin": { - "conventional-commits-parser": "dist/cli/index.js" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/@semantic-release/release-notes-generator/node_modules/get-stream": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-7.0.1.tgz", @@ -1478,17 +1400,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@semantic-release/release-notes-generator/node_modules/meow": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", - "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@sigstore/bundle": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.1.0.tgz", @@ -1635,9 +1546,9 @@ } }, "node_modules/@sigstore/sign/node_modules/minipass-fetch/node_modules/minipass": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.1.tgz", - "integrity": "sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, "license": "ISC", "engines": { @@ -1659,13 +1570,13 @@ } }, "node_modules/@sindresorhus/is": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-6.3.1.tgz", - "integrity": "sha512-FX4MfcifwJyFOI2lPoX7PQxCqx8BG1HCho7WdiXwpEQx1Ycij0JxkfYtGK7yqNScrZGSlt6RE6sw8QYoH7eKnQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.0.0.tgz", + "integrity": "sha512-WDTlVTyvFivSOuyvMeedzg2hdoBLZ3f1uNVuEida2Rl9BrfjrIRjWA/VZIrMRLvSwJYCAlCRA3usDt1THytxWQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=16" + "node": ">=18" }, "funding": { "url": "https://github.com/sindresorhus/is?sponsor=1" @@ -1790,9 +1701,9 @@ } }, "node_modules/@tufjs/models/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", "dependencies": { @@ -1831,14 +1742,14 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.12.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", - "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", + "version": "22.2.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.2.0.tgz", + "integrity": "sha512-bm6EG6/pCpkxDf/0gDNDdtDILMOHgaQBVOJGdwsqClnxA3xL6jtMv76rLBc006RVMWbmaf0xbmom4Z/5o2nRkQ==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.13.0" } }, "node_modules/@types/normalize-package-data": { @@ -1857,7 +1768,8 @@ "node_modules/@types/semver": { "version": "7.5.8", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==" + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "license": "MIT" }, "node_modules/@vercel/nft": { "version": "0.26.5", @@ -1939,9 +1851,9 @@ "license": "ISC" }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, "license": "MIT", "bin": { @@ -1962,11 +1874,14 @@ } }, "node_modules/acorn-walk": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", - "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", + "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", "dev": true, "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, "engines": { "node": ">=0.4.0" } @@ -2013,16 +1928,16 @@ } }, "node_modules/ajv": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", - "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "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", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -2045,6 +1960,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -2088,6 +2016,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "deprecated": "This package is no longer supported.", "dev": true, "license": "ISC", "dependencies": { @@ -2124,6 +2053,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.5", @@ -2171,25 +2101,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array.prototype.group": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/array.prototype.group/-/array.prototype.group-1.1.3.tgz", - "integrity": "sha512-KTxUkHfgy7MCrt49X/L725+60MQjB8bEJUeY3WCYNolurk870IKDxjSf5BkUKP1Y3iG8gA/SadfXJCfJR8x0yw==", - "deprecated": "This proposal has been altered; please use https://npmjs.com/object.groupby instead!", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/array.prototype.map": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.7.tgz", @@ -2232,23 +2143,27 @@ } }, "node_modules/array.prototype.tosorted": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz", - "integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.1.0", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/arraybuffer.prototype.slice": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", @@ -2401,6 +2316,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" @@ -2519,12 +2435,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -2586,20 +2502,10 @@ "node": ">=10.0.0" } }, - "node_modules/builtins": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz", - "integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.0.0" - } - }, "node_modules/c8": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/c8/-/c8-9.1.0.tgz", - "integrity": "sha512-mBWcT5iqNir1zIkzSPyI3NCR9EZCVI3WUD+AVO17MVWTSFNyUueXE82qTeampNtTr+ilN/5Ua3j24LgbCKjDVg==", + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/c8/-/c8-10.1.2.tgz", + "integrity": "sha512-Qr6rj76eSshu5CgRYvktW0uM0CFY0yi4Fd5D0duDXO6sYinyopmftUiJVuzBQxQcwQLor7JWDVRP+dUfCmzgJw==", "dev": true, "license": "ISC", "dependencies": { @@ -2610,7 +2516,7 @@ "istanbul-lib-coverage": "^3.2.0", "istanbul-lib-report": "^3.0.1", "istanbul-reports": "^3.1.6", - "test-exclude": "^6.0.0", + "test-exclude": "^7.0.1", "v8-to-istanbul": "^9.0.0", "yargs": "^17.7.2", "yargs-parser": "^21.1.1" @@ -2619,7 +2525,15 @@ "c8": "bin/c8.js" }, "engines": { - "node": ">=14.14.0" + "node": ">=18" + }, + "peerDependencies": { + "monocart-coverage-reports": "^2" + }, + "peerDependenciesMeta": { + "monocart-coverage-reports": { + "optional": true + } } }, "node_modules/cacache": { @@ -2681,24 +2595,22 @@ } }, "node_modules/cacache/node_modules/glob": { - "version": "10.3.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.15.tgz", - "integrity": "sha512-0c6RlJt1TICLyvJYIApxb8GsXoai0KUP7AxKKAtsYXdgJR1mGEUa7DgwShbdk1nly0PYoZj01xd4hzbq3fsjpw==", + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.6", - "minimatch": "^9.0.1", - "minipass": "^7.0.4", - "path-scurry": "^1.11.0" + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -2724,9 +2636,9 @@ } }, "node_modules/cacache/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", "dependencies": { @@ -2815,6 +2727,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -2831,9 +2744,9 @@ } }, "node_modules/callsites": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-4.1.0.tgz", - "integrity": "sha512-aBMbD1Xxay75ViYezwT40aQONfr+pSXTHwNKvIXhXD6+LY3F1dLIcceoC5OZKBVHbXcysz1hL9D2w0JJIMXpUw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-4.2.0.tgz", + "integrity": "sha512-kfzR4zzQtAE9PC7CzZsjl3aBNbXWuXiSeOCdLcPpBfGW8YuCqQHcRPFDbr/BPVmd3EEPVpuFzLyuT/cUhPr4OQ==", "dev": true, "license": "MIT", "engines": { @@ -3538,16 +3451,15 @@ "license": "ISC" }, "node_modules/conventional-changelog-angular": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", - "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.0.0.tgz", + "integrity": "sha512-CLf+zr6St0wIxos4bmaKHRXWAcsCXrJU6F4VdNDrGRK3B8LDLKoX3zuMV5GhtbGkVR/LohZ6MT6im43vZLSjmA==", "license": "ISC", - "peer": true, "dependencies": { "compare-func": "^2.0.0" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/conventional-changelog-writer": { @@ -3569,25 +3481,6 @@ "node": ">=18" } }, - "node_modules/conventional-changelog-writer/node_modules/conventional-commits-filter": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-5.0.0.tgz", - "integrity": "sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==", - "engines": { - "node": ">=18" - } - }, - "node_modules/conventional-changelog-writer/node_modules/meow": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", - "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/conventional-commit-types": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-3.0.0.tgz", @@ -3596,32 +3489,27 @@ "license": "ISC" }, "node_modules/conventional-commits-filter": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-4.0.0.tgz", - "integrity": "sha512-rnpnibcSOdFcdclpFwWa+pPlZJhXE7l+XK04zxhbWrhgpR96h33QLz8hITTXbcYICxVr3HZFtbtUAQ+4LdBo9A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-5.0.0.tgz", + "integrity": "sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==", "license": "MIT", - "peer": true, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/conventional-commits-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", - "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.0.0.tgz", + "integrity": "sha512-TbsINLp48XeMXR8EvGjTnKGsZqBemisPoyWESlpRyR8lif0lcwzqz+NMtYSj1ooF/WYjSuu7wX0CtdeeMEQAmA==", "license": "MIT", - "peer": true, "dependencies": { - "is-text-path": "^2.0.0", - "JSONStream": "^1.3.5", - "meow": "^12.0.1", - "split2": "^4.0.0" + "meow": "^13.0.0" }, "bin": { - "conventional-commits-parser": "cli.mjs" + "conventional-commits-parser": "dist/cli/index.js" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/convert-hrtime": { @@ -3886,6 +3774,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.6", @@ -3903,6 +3792,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -3920,6 +3810,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.6", @@ -3947,9 +3838,9 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "license": "MIT", "dependencies": { "ms": "2.1.2" @@ -3969,17 +3860,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "license": "MIT" }, - "node_modules/debuglog": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, "node_modules/decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -4052,6 +3932,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -4069,6 +3950,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", @@ -4119,17 +4001,6 @@ "node": ">=8" } }, - "node_modules/dezalgo": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", - "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", - "dev": true, - "license": "ISC", - "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, "node_modules/diff": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", @@ -4425,6 +4296,18 @@ "node": ">=6" } }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/err-code": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", @@ -4445,6 +4328,7 @@ "version": "1.23.3", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dev": true, "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", @@ -4512,6 +4396,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4" @@ -4524,6 +4409,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -4554,6 +4440,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -4566,6 +4453,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4", @@ -4590,6 +4478,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, "license": "MIT", "dependencies": { "is-callable": "^1.1.4", @@ -4726,9 +4615,9 @@ } }, "node_modules/execa": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-9.1.0.tgz", - "integrity": "sha512-lSgHc4Elo2m6bUDhc3Hl/VxvUDJdQWI40RZ4KMY9bKRc+hgMOT7II/JjbNDhI8VnMtrCb7U/fhpJIkLORZozWw==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.3.0.tgz", + "integrity": "sha512-l6JFbqnHEadBoVAVpN5dl2yCyfX28WoBAGaoQcNmLLSedOxTxcn2Qa83s8I/PA5i56vWru2OHOtrwF7Om2vqlg==", "license": "MIT", "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", @@ -4745,7 +4634,7 @@ "yoctocolors": "^2.0.0" }, "engines": { - "node": ">=18" + "node": "^18.19.0 || >=20.5.0" }, "funding": { "url": "https://github.com/sindresorhus/execa?sponsor=1" @@ -4849,6 +4738,13 @@ "node": ">=8.6.0" } }, + "node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-url-parser": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", @@ -4859,13 +4755,6 @@ "punycode": "^1.3.2" } }, - "node_modules/fast-url-parser/node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", - "dev": true, - "license": "MIT" - }, "node_modules/fastq": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", @@ -4911,9 +4800,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -5005,15 +4894,16 @@ "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, "license": "MIT", "dependencies": { "is-callable": "^1.1.3" } }, "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dev": true, "license": "ISC", "dependencies": { @@ -5128,6 +5018,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5149,6 +5040,7 @@ "version": "1.1.6", "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -5167,6 +5059,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5176,6 +5069,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "deprecated": "This package is no longer supported.", "dev": true, "license": "ISC", "dependencies": { @@ -5265,1047 +5159,122 @@ } }, "node_modules/get-dep-tree": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/get-dep-tree/-/get-dep-tree-1.0.4.tgz", - "integrity": "sha512-ozEmO7BTbo7vAAaBKgs9PiqqvfrtfoD4uEqc7X3LOpoeWmjK0IF5myqDpJwcBxAARkMh8xNgJdD3zVFG2yGnag==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-dep-tree/-/get-dep-tree-2.0.0.tgz", + "integrity": "sha512-kEPR3I4I3mFvywlHd8UcCaZRjHTfMctp532faCk1afUQL7XGaTep/YSZ15E64/iS9oVzgbJAWO5OzLRZTnfYhA==", "dev": true, "license": "MIT", "dependencies": { - "@npmcli/arborist": "^5.6.3", - "array.prototype.flat": "^1.3.1", + "@npmcli/arborist": "^6.5.1", + "array.prototype.flat": "^1.3.2", "colors": "=1.4.0", "lockfile-info": "^1.0.0", - "pacote": "^13.6.2" + "pacote": "^15.2.0" }, "engines": { - "node": ">= 16 || ^14.15 || ^12.13" + "node": ">= 19 || ^18 || ^16.13 || ^14.18" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-dep-tree/node_modules/@npmcli/arborist": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-5.6.3.tgz", - "integrity": "sha512-/7hbqEM6YuRjwTcQXkK1+xKslEblY5kFQe0tZ7jKyMlIR6x4iOmhLErIkBBGtTKvYxRKdpcxnFXjCobg3UqmsA==", - "dev": true, - "license": "ISC", - "dependencies": { - "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/installed-package-contents": "^1.0.7", - "@npmcli/map-workspaces": "^2.0.3", - "@npmcli/metavuln-calculator": "^3.0.1", - "@npmcli/move-file": "^2.0.0", - "@npmcli/name-from-folder": "^1.0.1", - "@npmcli/node-gyp": "^2.0.0", - "@npmcli/package-json": "^2.0.0", - "@npmcli/query": "^1.2.0", - "@npmcli/run-script": "^4.1.3", - "bin-links": "^3.0.3", - "cacache": "^16.1.3", - "common-ancestor-path": "^1.0.1", - "hosted-git-info": "^5.2.1", - "json-parse-even-better-errors": "^2.3.1", - "json-stringify-nice": "^1.1.4", - "minimatch": "^5.1.0", - "mkdirp": "^1.0.4", - "mkdirp-infer-owner": "^2.0.0", - "nopt": "^6.0.0", - "npm-install-checks": "^5.0.0", - "npm-package-arg": "^9.0.0", - "npm-pick-manifest": "^7.0.2", - "npm-registry-fetch": "^13.0.0", - "npmlog": "^6.0.2", - "pacote": "^13.6.1", - "parse-conflict-json": "^2.0.1", - "proc-log": "^2.0.0", - "promise-all-reject-late": "^1.0.0", - "promise-call-limit": "^1.0.1", - "read-package-json-fast": "^2.0.2", - "readdir-scoped-modules": "^1.1.0", - "rimraf": "^3.0.2", - "semver": "^7.3.7", - "ssri": "^9.0.0", - "treeverse": "^2.0.0", - "walk-up-path": "^1.0.0" - }, - "bin": { - "arborist": "bin/index.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/@npmcli/fs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", - "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "@gar/promisify": "^1.1.3", - "semver": "^7.3.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/@npmcli/git": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-3.0.2.tgz", - "integrity": "sha512-CAcd08y3DWBJqJDpfuVL0uijlq5oaXaOJEKHKc4wqrjd00gkvTZB+nFuLn+doOOKddaQS9JfqtNoFCO2LCvA3w==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/promise-spawn": "^3.0.0", - "lru-cache": "^7.4.4", - "mkdirp": "^1.0.4", - "npm-pick-manifest": "^7.0.0", - "proc-log": "^2.0.0", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^2.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/@npmcli/installed-package-contents": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", - "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", - "dev": true, - "license": "ISC", - "dependencies": { - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" - }, - "bin": { - "installed-package-contents": "index.js" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/get-dep-tree/node_modules/@npmcli/map-workspaces": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-2.0.4.tgz", - "integrity": "sha512-bMo0aAfwhVwqoVM5UzX1DJnlvVvzDCHae821jv48L1EsrYwfOZChlqWYXEtto/+BkBXetPbEWgau++/brh4oVg==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/name-from-folder": "^1.0.1", - "glob": "^8.0.1", - "minimatch": "^5.0.1", - "read-package-json-fast": "^2.0.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/@npmcli/metavuln-calculator": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-3.1.1.tgz", - "integrity": "sha512-n69ygIaqAedecLeVH3KnO39M6ZHiJ2dEv5A7DGvcqCB8q17BGUgW8QaanIkbWUo2aYGZqJaOORTLAlIvKjNDKA==", - "dev": true, - "license": "ISC", - "dependencies": { - "cacache": "^16.0.0", - "json-parse-even-better-errors": "^2.3.1", - "pacote": "^13.0.3", - "semver": "^7.3.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/@npmcli/name-from-folder": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-1.0.1.tgz", - "integrity": "sha512-qq3oEfcLFwNfEYOQ8HLimRGKlD8WSeGEdtUa7hmzpR8Sa7haL1KVQrvgO6wqMjhWFFVjgtrh1gIxDz+P8sjUaA==", - "dev": true, - "license": "ISC" - }, - "node_modules/get-dep-tree/node_modules/@npmcli/node-gyp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-2.0.0.tgz", - "integrity": "sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A==", + "node_modules/get-east-asian-width": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", + "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", "dev": true, - "license": "ISC", + "license": "MIT", "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/@npmcli/package-json": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-2.0.0.tgz", - "integrity": "sha512-42jnZ6yl16GzjWSH7vtrmWyJDGVa/LXPdpN2rcUWolFjc9ON2N3uz0qdBbQACfmhuJZ2lbKYtmK5qx68ZPLHMA==", - "dev": true, - "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^2.3.1" + "node": ">=18" }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-dep-tree/node_modules/@npmcli/promise-spawn": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-3.0.0.tgz", - "integrity": "sha512-s9SgS+p3a9Eohe68cSI3fi+hpcZUmXq5P7w0kMlAsWVtR7XbK3ptkZqKT2cK1zLDObJ3sR+8P59sJE0w/KTL1g==", + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "infer-owner": "^1.0.4" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/@npmcli/query": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@npmcli/query/-/query-1.2.0.tgz", - "integrity": "sha512-uWglsUM3PjBLgTSmZ3/vygeGdvWEIZ3wTUnzGFbprC/RtvQSaT+GAXu1DXmSFj2bD3oOZdcRm1xdzsV2z1YWdw==", - "dev": true, - "license": "ISC", - "dependencies": { - "npm-package-arg": "^9.1.0", - "postcss-selector-parser": "^6.0.10", - "semver": "^7.3.7" + "node": ">= 0.4" }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-dep-tree/node_modules/@npmcli/run-script": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-4.2.1.tgz", - "integrity": "sha512-7dqywvVudPSrRCW5nTHpHgeWnbBtz8cFkOuKrecm6ih+oO9ciydhWt6OF7HlqupRRmB8Q/gECVdB9LMfToJbRg==", + "node_modules/get-json": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-json/-/get-json-1.1.0.tgz", + "integrity": "sha512-IjoEwpXyyEsRtwBSZ0SYA6By6oVBnakpftFHAAkSSlLYRZ1NPGFS/r+6fSgbk7t6njfEuYVMbD1pe4ex6vgLcw==", "dev": true, - "license": "ISC", + "license": "BSD-3-Clause", "dependencies": { - "@npmcli/node-gyp": "^2.0.0", - "@npmcli/promise-spawn": "^3.0.0", - "node-gyp": "^9.0.0", - "read-package-json-fast": "^2.0.3", - "which": "^2.0.2" + "jsonp": "^0.2.1", + "safe-buffer": "^5.2.1", + "safe-regex-test": "^1.0.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">= 0.4" } }, - "node_modules/get-dep-tree/node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "license": "MIT", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-dep-tree/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/get-dep-tree/node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "dev": true, - "license": "ISC", "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/bin-links": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-3.0.3.tgz", - "integrity": "sha512-zKdnMPWEdh4F5INR07/eBrodC7QrF5JKvqskjz/ZZRXg5YSAZIbn8zGhbhUrElzHBZ2fvEQdOU59RHcTG3GiwA==", - "dev": true, - "license": "ISC", - "dependencies": { - "cmd-shim": "^5.0.0", - "mkdirp-infer-owner": "^2.0.0", - "npm-normalize-package-bin": "^2.0.0", - "read-cmd-shim": "^3.0.0", - "rimraf": "^3.0.0", - "write-file-atomic": "^4.0.0" + "node": ">= 0.4" }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/bin-links/node_modules/npm-normalize-package-bin": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", - "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-dep-tree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/cacache": { - "version": "16.1.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", - "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/get-dep-tree/node_modules/cmd-shim": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-5.0.0.tgz", - "integrity": "sha512-qkCtZ59BidfEwHltnJwkyVZn+XQojdAySM1D1gSeh11Z4pW1Kpolkyo53L5noc0nrxmIvyFwTmJRo4xs7FFLPw==", - "dev": true, - "license": "ISC", - "dependencies": { - "mkdirp-infer-owner": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/get-dep-tree/node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/get-dep-tree/node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "dev": true, - "license": "ISC", - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/get-dep-tree/node_modules/hosted-git-info": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", - "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^7.5.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/ignore-walk": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-5.0.1.tgz", - "integrity": "sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw==", - "dev": true, - "license": "ISC", - "dependencies": { - "minimatch": "^5.0.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/get-dep-tree/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/get-dep-tree/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/get-dep-tree/node_modules/just-diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-5.2.0.tgz", - "integrity": "sha512-6ufhP9SHjb7jibNFrNxyFZ6od3g+An6Ai9mhGRvcYe8UJlH0prseN64M+6ZBBUoKYHZsitDP42gAJ8+eVWr3lw==", - "dev": true, - "license": "MIT" - }, - "node_modules/get-dep-tree/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/get-dep-tree/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/get-dep-tree/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/get-dep-tree/node_modules/nopt": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", - "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", - "dev": true, - "license": "ISC", - "dependencies": { - "abbrev": "^1.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/normalize-package-data": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-4.0.1.tgz", - "integrity": "sha512-EBk5QKKuocMJhB3BILuKhmaPjI8vNRSpIfO9woLC6NyHVkKKdVEdAO1mrT0ZfxNR1lKwCcTkuZfmGIFdizZ8Pg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^5.0.0", - "is-core-module": "^2.8.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/npm-bundled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", - "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "npm-normalize-package-bin": "^1.0.1" - } - }, - "node_modules/get-dep-tree/node_modules/npm-install-checks": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-5.0.0.tgz", - "integrity": "sha512-65lUsMI8ztHCxFz5ckCEC44DRvEGdZX5usQFriauxHEwt7upv1FKaQEmAtU0YnOAdwuNWCmk64xYiQABNrEyLA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "semver": "^7.1.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/npm-normalize-package-bin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", - "dev": true, - "license": "ISC" - }, - "node_modules/get-dep-tree/node_modules/npm-package-arg": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.2.tgz", - "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", - "dev": true, - "license": "ISC", - "dependencies": { - "hosted-git-info": "^5.0.0", - "proc-log": "^2.0.1", - "semver": "^7.3.5", - "validate-npm-package-name": "^4.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/npm-packlist": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-5.1.3.tgz", - "integrity": "sha512-263/0NGrn32YFYi4J533qzrQ/krmmrWwhKkzwTuM4f/07ug51odoaNjUexxO4vxlzURHcmYMH1QjvHjsNDKLVg==", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^8.0.1", - "ignore-walk": "^5.0.1", - "npm-bundled": "^2.0.0", - "npm-normalize-package-bin": "^2.0.0" - }, - "bin": { - "npm-packlist": "bin/index.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/npm-packlist/node_modules/npm-bundled": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-2.0.1.tgz", - "integrity": "sha512-gZLxXdjEzE/+mOstGDqR6b0EkhJ+kM6fxM6vUuckuctuVPh80Q6pw/rSZj9s4Gex9GxWtIicO1pc8DB9KZWudw==", - "dev": true, - "license": "ISC", - "dependencies": { - "npm-normalize-package-bin": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/npm-packlist/node_modules/npm-normalize-package-bin": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", - "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/npm-pick-manifest": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-7.0.2.tgz", - "integrity": "sha512-gk37SyRmlIjvTfcYl6RzDbSmS9Y4TOBXfsPnoYqTHARNgWbyDiCSMLUpmALDj4jjcTZpURiEfsSHJj9k7EV4Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "npm-install-checks": "^5.0.0", - "npm-normalize-package-bin": "^2.0.0", - "npm-package-arg": "^9.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/npm-pick-manifest/node_modules/npm-normalize-package-bin": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", - "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/npm-registry-fetch": { - "version": "13.3.1", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-13.3.1.tgz", - "integrity": "sha512-eukJPi++DKRTjSBRcDZSDDsGqRK3ehbxfFUcgaRd0Yp6kRwOwh2WVn0r+8rMB4nnuzvAk6rQVzl6K5CkYOmnvw==", - "dev": true, - "license": "ISC", - "dependencies": { - "make-fetch-happen": "^10.0.6", - "minipass": "^3.1.6", - "minipass-fetch": "^2.0.3", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.1.2", - "npm-package-arg": "^9.0.1", - "proc-log": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "dev": true, - "license": "ISC", - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-dep-tree/node_modules/pacote": { - "version": "13.6.2", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-13.6.2.tgz", - "integrity": "sha512-Gu8fU3GsvOPkak2CkbojR7vjs3k3P9cA6uazKTHdsdV0gpCEQq2opelnEv30KRQWgVzP5Vd/5umjcedma3MKtg==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/git": "^3.0.0", - "@npmcli/installed-package-contents": "^1.0.7", - "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/run-script": "^4.1.0", - "cacache": "^16.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "infer-owner": "^1.0.4", - "minipass": "^3.1.6", - "mkdirp": "^1.0.4", - "npm-package-arg": "^9.0.0", - "npm-packlist": "^5.1.0", - "npm-pick-manifest": "^7.0.0", - "npm-registry-fetch": "^13.0.1", - "proc-log": "^2.0.0", - "promise-retry": "^2.0.1", - "read-package-json": "^5.0.0", - "read-package-json-fast": "^2.0.3", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11" - }, - "bin": { - "pacote": "lib/bin.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/parse-conflict-json": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/parse-conflict-json/-/parse-conflict-json-2.0.2.tgz", - "integrity": "sha512-jDbRGb00TAPFsKWCpZZOT93SxVP9nONOSgES3AevqRq/CHvavEBvKAjxX9p5Y5F0RZLxH9Ufd9+RwtCsa+lFDA==", - "dev": true, - "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^2.3.1", - "just-diff": "^5.0.1", - "just-diff-apply": "^5.2.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/proc-log": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", - "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/read-cmd-shim": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-3.0.1.tgz", - "integrity": "sha512-kEmDUoYf/CDy8yZbLTmhB1X9kkjf9Q80PCNsDMb7ufrGd6zZSQA1+UyjrO+pZm5K/S4OXCWJeiIt1JA8kAsa6g==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/read-package-json": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-5.0.2.tgz", - "integrity": "sha512-BSzugrt4kQ/Z0krro8zhTwV1Kd79ue25IhNN/VtHFy1mG/6Tluyi+msc0UpwaoQzxSHa28mntAjIZY6kEgfR9Q==", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^8.0.1", - "json-parse-even-better-errors": "^2.3.1", - "normalize-package-data": "^4.0.0", - "npm-normalize-package-bin": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/read-package-json-fast": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", - "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^2.3.0", - "npm-normalize-package-bin": "^1.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/get-dep-tree/node_modules/read-package-json/node_modules/npm-normalize-package-bin": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", - "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/get-dep-tree/node_modules/ssri": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", - "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/get-dep-tree/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/get-dep-tree/node_modules/treeverse": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/treeverse/-/treeverse-2.0.0.tgz", - "integrity": "sha512-N5gJCkLu1aXccpOTtqV6ddSEi6ZmGkh3hjmbu1IjcavJK4qyOVQmi0myQKM7z5jVGmD68SJoliaVrMmVObhj6A==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/unique-filename": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", - "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", - "dev": true, - "license": "ISC", - "dependencies": { - "unique-slug": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/unique-slug": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", - "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/validate-npm-package-name": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz", - "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", - "dev": true, - "license": "ISC", - "dependencies": { - "builtins": "^5.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-dep-tree/node_modules/walk-up-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-1.0.0.tgz", - "integrity": "sha512-hwj/qMDUEjCU5h0xr90KGCf0tg0/LgJbmOWgrWKYlcJZM7XvquvUJZ0G/HMGr7F7OQMOUuPHWP9JpriinkAlkg==", - "dev": true, - "license": "ISC" - }, - "node_modules/get-dep-tree/node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", - "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-json": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-json/-/get-json-1.0.1.tgz", - "integrity": "sha512-buUOE2bLaxIsF6zGIrwvsTVlvgU85qwAWf0Hgq/EJBBoSssUqOauXWKpsh4wgPdTlZHEVllLtphiuIzFM4UEHQ==", - "dev": true, - "license": "BSD", - "dependencies": { - "is-node": "0.0.0", - "jsonp": "0.0.4", - "phin": "^2.2.6" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/git-log-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/git-log-parser/-/git-log-parser-1.2.0.tgz", - "integrity": "sha512-rnCVNfkTL8tdNryFuaY0fYiBWEBcgF748O6ZI61rslBvr2o7U65c2/6npCRqH40vuAhtgtDiqLTJjBVdrejCzA==", + "node_modules/git-log-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/git-log-parser/-/git-log-parser-1.2.1.tgz", + "integrity": "sha512-PI+sPDvHXNPl5WNOErAK05s3j0lgwUzMN6o8cyQrDaKfT3qd7TmNJKeXX+SknI5I0QhG5fVPAEwSY4tRGDtYoQ==", "license": "MIT", "dependencies": { "argv-formatter": "~1.0.0", "spawn-error-forwarder": "~1.0.0", "split2": "~1.0.0", - "stream-combiner2": "~1.1.1", - "through2": "~2.0.0", - "traverse": "~0.6.6" - } - }, - "node_modules/git-log-parser/node_modules/split2": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-1.0.0.tgz", - "integrity": "sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg==", - "license": "ISC", - "dependencies": { - "through2": "~2.0.0" + "stream-combiner2": "~1.1.1", + "through2": "~2.0.0", + "traverse": "0.6.8" } }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "license": "ISC", "dependencies": { @@ -6408,6 +5377,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, "license": "MIT", "dependencies": { "define-properties": "^1.2.1", @@ -6421,9 +5391,9 @@ } }, "node_modules/globby": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.1.tgz", - "integrity": "sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ==", + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", + "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", "license": "MIT", "dependencies": { "@sindresorhus/merge-streams": "^2.1.0", @@ -6468,6 +5438,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" @@ -6477,23 +5448,23 @@ } }, "node_modules/got": { - "version": "14.3.0", - "resolved": "https://registry.npmjs.org/got/-/got-14.3.0.tgz", - "integrity": "sha512-vZkrXdq5BtPWTXqvjXSpl6zky3zpHaOVfSug/RfFHu3YrtSsvYzopVMDqrh2do77WnGoCSSRCHW25zXOSAQ9zw==", + "version": "14.4.2", + "resolved": "https://registry.npmjs.org/got/-/got-14.4.2.tgz", + "integrity": "sha512-+Te/qEZ6hr7i+f0FNgXx/6WQteSM/QqueGvxeYQQFm0GDfoxLVJ/oiwUKYMTeioColWUTdewZ06hmrBjw6F7tw==", "dev": true, "license": "MIT", "dependencies": { - "@sindresorhus/is": "^6.3.1", + "@sindresorhus/is": "^7.0.0", "@szmarczak/http-timer": "^5.0.1", "cacheable-lookup": "^7.0.0", "cacheable-request": "^12.0.1", "decompress-response": "^6.0.0", "form-data-encoder": "^4.0.2", - "get-stream": "^8.0.1", "http2-wrapper": "^2.2.1", "lowercase-keys": "^3.0.0", "p-cancelable": "^4.0.1", - "responselike": "^3.0.0" + "responselike": "^3.0.0", + "type-fest": "^4.19.0" }, "engines": { "node": ">=20" @@ -6502,19 +5473,6 @@ "url": "https://github.com/sindresorhus/got?sponsor=1" } }, - "node_modules/got/node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -6546,6 +5504,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6564,6 +5523,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" @@ -6576,6 +5536,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -6588,6 +5549,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -6600,6 +5562,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -6622,6 +5585,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -6718,9 +5682,9 @@ } }, "node_modules/https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", "license": "MIT", "dependencies": { "agent-base": "^7.0.2", @@ -6926,6 +5890,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, "license": "ISC", "dependencies": { @@ -7115,6 +6080,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -7196,6 +6162,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -7218,6 +6185,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, "license": "MIT", "dependencies": { "has-bigints": "^1.0.1" @@ -7230,6 +6198,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -7246,6 +6215,7 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -7255,12 +6225,16 @@ } }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", + "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", + "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7270,6 +6244,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, "license": "MIT", "dependencies": { "is-typed-array": "^1.1.13" @@ -7285,6 +6260,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" @@ -7364,6 +6340,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -7385,13 +6362,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-node": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/is-node/-/is-node-0.0.0.tgz", - "integrity": "sha512-KUwX8L3QU5YheJw8FiFwBFf+gIZ3OX2wifID5sHjn1pWrFMfIaBZLSszs7vHtiJR9y7plGM+Y4jtfwrsCI1D8Q==", - "dev": true, - "license": "BSD" - }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -7405,6 +6375,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" @@ -7458,6 +6429,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -7497,6 +6469,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.7" @@ -7524,6 +6497,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" @@ -7539,6 +6513,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.2" @@ -7550,23 +6525,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-text-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", - "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", - "license": "MIT", - "peer": true, - "dependencies": { - "text-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/is-typed-array": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, "license": "MIT", "dependencies": { "which-typed-array": "^1.1.14" @@ -7608,6 +6571,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2" @@ -7630,6 +6594,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, "license": "MIT" }, "node_modules/isexe": { @@ -7639,9 +6604,9 @@ "license": "ISC" }, "node_modules/issue-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-7.0.0.tgz", - "integrity": "sha512-jgAw78HO3gs9UrKqJNQvfDj9Ouy8Mhu40fbEJ8yXff4MW8+/Fcn9iFjyWUQ6SKbX8ipPk3X5A3AyfYHRu6uVLw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-7.0.1.tgz", + "integrity": "sha512-3YZcUUR2Wt1WsapF+S/WiA2WmlW0cWAoPccMqne7AxEBhCdFeTPjfv/Axb8V2gyCgY3nRw+ksZ3xSUX+R47iAg==", "license": "MIT", "dependencies": { "lodash.capitalize": "^4.2.1", @@ -7734,17 +6699,14 @@ } }, "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, - "engines": { - "node": ">=14" - }, "funding": { "url": "https://github.com/sponsors/isaacs" }, @@ -7762,9 +6724,9 @@ } }, "node_modules/jiti": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", - "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", "dev": true, "license": "MIT", "optional": true, @@ -7868,6 +6830,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, "license": "ISC" }, "node_modules/jsonfile": { @@ -7883,40 +6846,41 @@ } }, "node_modules/jsonp": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/jsonp/-/jsonp-0.0.4.tgz", - "integrity": "sha512-Pyo6SxnTXngwXJbpZkv+936u4Pq3BGZ5tuA77rLLppWQC09KjBsopGsD7uQZmCCaXjLx5C/XqksUh0yGyr4wog==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/jsonp/-/jsonp-0.2.1.tgz", + "integrity": "sha512-pfog5gdDxPdV4eP7Kg87M8/bHgshlZ5pybl+yKxAnCZ5O7lCIn7Ixydj03wOlnDQesky2BPyA91SQ+5Y/mNwzw==", + "dev": true, + "dependencies": { + "debug": "^2.1.3" + } + }, + "node_modules/jsonp/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { - "debug": "*" + "ms": "2.0.0" } }, + "node_modules/jsonp/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, "node_modules/jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, "engines": [ "node >= 0.2.0" ], "license": "MIT" }, - "node_modules/JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "license": "(MIT OR Apache-2.0)", - "peer": true, - "dependencies": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - }, - "bin": { - "JSONStream": "bin.js" - }, - "engines": { - "node": "*" - } - }, "node_modules/just-diff": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-6.0.2.tgz", @@ -7997,15 +6961,15 @@ } }, "node_modules/lockfile-lint": { - "version": "4.13.2", - "resolved": "https://registry.npmjs.org/lockfile-lint/-/lockfile-lint-4.13.2.tgz", - "integrity": "sha512-yeg0vJ3NjC6OVMZtC+nSLLavu/e8LE5FZp9u0Itqyt7I0gYYCgGxAsJV3TJ7WtaJd4PahineJvHqSk/4sqzU8w==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/lockfile-lint/-/lockfile-lint-4.14.0.tgz", + "integrity": "sha512-uyXZ8X4J6EsicG87p0y4SHorJBwABLcaXOpI/j3h8SO/OX4fKTJ6Cqqi+U3zjgU0fo+u/4KbB7fl8ZzTewd0Ow==", "dev": true, "license": "Apache-2.0", "dependencies": { - "cosmiconfig": "^8.2.0", + "cosmiconfig": "^9.0.0", "debug": "^4.3.4", - "fast-glob": "^3.3.1", + "fast-glob": "^3.3.2", "lockfile-lint-api": "^5.9.1", "yargs": "^17.7.2" }, @@ -8031,33 +6995,6 @@ "node": ">=16.0.0" } }, - "node_modules/lockfile-lint/node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dev": true, - "license": "MIT", - "dependencies": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -8253,44 +7190,41 @@ } }, "node_modules/lru-cache": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", - "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", - "license": "ISC", - "engines": { - "node": "14 || >=16.14" - } + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" }, "node_modules/ls-engines": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/ls-engines/-/ls-engines-0.9.1.tgz", - "integrity": "sha512-w1BzDJP2qm9gIESA0SFuUQmNdCgyoUetRmE2xHMOx8EWF2QUaFV5moJ3yc3WceJMYNeygSuKm0AQYvXpzow/TQ==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/ls-engines/-/ls-engines-0.9.3.tgz", + "integrity": "sha512-vvaAldgMQpU646VlFmHq73f723UycwZW7FeJCeP1GLuAGvjX/K336JIFPvz8Eo0fUXcyLIgbpD4s7HY9C7yb/A==", "dev": true, "license": "MIT", "dependencies": { - "@npmcli/arborist": "^6.5.0", - "array.prototype.group": "^1.1.2", - "array.prototype.some": "^1.1.5", - "array.prototype.tosorted": "^1.1.2", + "@npmcli/arborist": "^6.5.1", + "array.prototype.some": "^1.1.6", + "array.prototype.tosorted": "^1.1.4", "colors": "=1.4.0", "fast_array_intersect": "^1.1.0", - "get-dep-tree": "^1.0.4", - "get-json": "^1.0.1", + "get-dep-tree": "^2.0.0", + "get-json": "^1.1.0", "json-file-plus": "^3.3.1", "lockfile-info": "^1.0.0", - "object.fromentries": "^2.0.7", - "object.values": "^1.1.7", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.0", "pacote": "^15.2.0", "promise.allsettled": "^1.0.7", - "semver": "^7.5.4", - "table": "^6.8.1", + "semver": "^7.6.3", + "table": "^6.8.2", "yargs": "^17.7.2" }, "bin": { "ls-engines": "bin/ls-engines" }, "engines": { - "node": ">= 19 || ^18 || ^16.13 || ^14.17", + "node": ">= 19 || ^18 || ^16.13 || ^14.18", "npm": ">=8" } }, @@ -8456,6 +7390,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "license": "ISC", "dependencies": { @@ -8615,15 +7550,15 @@ } }, "node_modules/marked-terminal": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-7.0.0.tgz", - "integrity": "sha512-sNEx8nn9Ktcm6pL0TnRz8tnXq/mSS0Q1FRSwJOAqw4lAB4l49UeDf85Gm1n9RPFm5qurCPjwi1StAQT2XExhZw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-7.1.0.tgz", + "integrity": "sha512-+pvwa14KZL74MVXjYdPR3nSInhGhNvPce/3mqLVZT2oUvt654sL1XImFuLZ1pkA866IYZ3ikDTOFUIC7XzpZZg==", "license": "MIT", "dependencies": { - "ansi-escapes": "^6.2.0", + "ansi-escapes": "^7.0.0", "chalk": "^5.3.0", "cli-highlight": "^2.1.11", - "cli-table3": "^0.6.3", + "cli-table3": "^0.6.5", "node-emoji": "^2.1.3", "supports-hyperlinks": "^3.0.0" }, @@ -8631,16 +7566,19 @@ "node": ">=16.0.0" }, "peerDependencies": { - "marked": ">=1 <13" + "marked": ">=1 <14" } }, "node_modules/marked-terminal/node_modules/ansi-escapes": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", - "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, "engines": { - "node": ">=14.16" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -8701,13 +7639,12 @@ } }, "node_modules/meow": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", - "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", + "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", "license": "MIT", - "peer": true, "engines": { - "node": ">=16.10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -8736,12 +7673,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -8761,9 +7698,9 @@ } }, "node_modules/mime": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/mime/-/mime-4.0.3.tgz", - "integrity": "sha512-KgUb15Oorc0NEKPbvfa0wRU+PItIEZmiv+pyAO2i0oTIVTJhlzMclU7w4RXWQrSOVH5ax/p/CkIO7KI4OyFJTQ==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-4.0.4.tgz", + "integrity": "sha512-v8yqInVjhXyqP6+Kw4fV3ZzeMRqEW6FotRsKXjRS5VMTNIuXsdRoAvklpoRgSqXm6o9VNH4/C0mgedko9DdLsQ==", "funding": [ "https://github.com/sponsors/broofa" ], @@ -8834,9 +7771,9 @@ } }, "node_modules/minipass": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.1.tgz", - "integrity": "sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, "license": "ISC", "engines": { @@ -8927,9 +7864,9 @@ } }, "node_modules/minipass-json-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", - "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.2.tgz", + "integrity": "sha512-myxeeTm57lYs8pH2nxPzmEEg8DGIgW+9mv6D4JZD2pa81I/OBjeU7PtICXV6c9eRGTA5JMDsuIPUZRCyBMYNhg==", "dev": true, "license": "MIT", "dependencies": { @@ -9049,21 +7986,6 @@ "dev": true, "license": "MIT" }, - "node_modules/mkdirp-infer-owner": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mkdirp-infer-owner/-/mkdirp-infer-owner-2.0.0.tgz", - "integrity": "sha512-sdqtiFt3lkOaYvTXSRIUjkIdPTcxgv5+fgqYE/5qgwdw12cOrAuzzgzvVExIkH/ul1oeHN3bCLOWSG3XOqbKKw==", - "dev": true, - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "infer-owner": "^1.0.4", - "mkdirp": "^1.0.3" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/mockserver-client": { "version": "5.15.0", "resolved": "https://registry.npmjs.org/mockserver-client/-/mockserver-client-5.15.0.tgz", @@ -9115,9 +8037,9 @@ } }, "node_modules/nan": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz", - "integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==", + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz", + "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==", "dev": true, "license": "MIT", "optional": true @@ -9280,6 +8202,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "deprecated": "This package is no longer supported.", "dev": true, "license": "ISC", "dependencies": { @@ -9301,6 +8224,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "deprecated": "This package is no longer supported.", "dev": true, "license": "ISC", "dependencies": { @@ -9347,6 +8271,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "deprecated": "This package is no longer supported.", "dev": true, "license": "ISC", "dependencies": { @@ -9486,9 +8411,9 @@ } }, "node_modules/npm": { - "version": "10.8.1", - "resolved": "https://registry.npmjs.org/npm/-/npm-10.8.1.tgz", - "integrity": "sha512-Dp1C6SvSMYQI7YHq/y2l94uvI+59Eqbu1EpuKQHQ8p16txXRuRit5gH3Lnaagk2aXDIjg/Iru9pd05bnneKgdw==", + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/npm/-/npm-10.8.2.tgz", + "integrity": "sha512-x/AIjFIKRllrhcb48dqUNAAZl0ig9+qMuN91RpZo3Cb2+zuibfh+KISl6+kVVyktDz230JKc208UkQwwMqyB+w==", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -9569,13 +8494,13 @@ ], "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^7.5.3", - "@npmcli/config": "^8.3.3", + "@npmcli/arborist": "^7.5.4", + "@npmcli/config": "^8.3.4", "@npmcli/fs": "^3.1.1", "@npmcli/map-workspaces": "^3.0.6", - "@npmcli/package-json": "^5.1.1", + "@npmcli/package-json": "^5.2.0", "@npmcli/promise-spawn": "^7.0.2", - "@npmcli/redact": "^2.0.0", + "@npmcli/redact": "^2.0.1", "@npmcli/run-script": "^8.1.0", "@sigstore/tuf": "^2.3.4", "abbrev": "^2.0.0", @@ -9586,7 +8511,7 @@ "cli-columns": "^4.0.0", "fastest-levenshtein": "^1.0.16", "fs-minipass": "^3.0.3", - "glob": "^10.4.1", + "glob": "^10.4.2", "graceful-fs": "^4.2.11", "hosted-git-info": "^7.0.2", "ini": "^4.1.3", @@ -9594,30 +8519,30 @@ "is-cidr": "^5.1.0", "json-parse-even-better-errors": "^3.0.2", "libnpmaccess": "^8.0.6", - "libnpmdiff": "^6.1.3", - "libnpmexec": "^8.1.2", - "libnpmfund": "^5.0.11", + "libnpmdiff": "^6.1.4", + "libnpmexec": "^8.1.3", + "libnpmfund": "^5.0.12", "libnpmhook": "^10.0.5", "libnpmorg": "^6.0.6", - "libnpmpack": "^7.0.3", + "libnpmpack": "^7.0.4", "libnpmpublish": "^9.0.9", "libnpmsearch": "^7.0.6", "libnpmteam": "^6.0.5", "libnpmversion": "^6.0.3", "make-fetch-happen": "^13.0.1", - "minimatch": "^9.0.4", + "minimatch": "^9.0.5", "minipass": "^7.1.1", "minipass-pipeline": "^1.2.4", "ms": "^2.1.2", "node-gyp": "^10.1.0", "nopt": "^7.2.1", - "normalize-package-data": "^6.0.1", + "normalize-package-data": "^6.0.2", "npm-audit-report": "^5.0.0", "npm-install-checks": "^6.3.0", "npm-package-arg": "^11.0.2", - "npm-pick-manifest": "^9.0.1", + "npm-pick-manifest": "^9.1.0", "npm-profile": "^10.0.0", - "npm-registry-fetch": "^17.0.1", + "npm-registry-fetch": "^17.1.0", "npm-user-validate": "^2.0.1", "p-map": "^4.0.0", "pacote": "^18.0.6", @@ -9757,9 +8682,9 @@ } }, "node_modules/npm-packlist/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", "dependencies": { @@ -9915,9 +8840,9 @@ } }, "node_modules/npm-registry-fetch/node_modules/minipass-fetch/node_modules/minipass": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.1.tgz", - "integrity": "sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, "license": "ISC", "engines": { @@ -9925,9 +8850,9 @@ } }, "node_modules/npm-run-all2": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-6.2.0.tgz", - "integrity": "sha512-wA7yVIkthe6qJBfiJ2g6aweaaRlw72itsFGF6HuwCHKwtwAx/4BY1vVpk6bw6lS8RLMsexoasOkd0aYOmsFG7Q==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-6.2.2.tgz", + "integrity": "sha512-Q+alQAGIW7ZhKcxLt8GcSi3h3ryheD6xnmXahkMRVM5LYmajcUrSITm8h+OPC9RYWMV2GR0Q1ntTUCfxaNoOJw==", "dev": true, "license": "MIT", "dependencies": { @@ -9946,7 +8871,7 @@ "run-s": "bin/run-s/index.js" }, "engines": { - "node": "^14.18.0 || >=16.0.0", + "node": "^14.18.0 || ^16.13.0 || >=18.0.0", "npm": ">= 8" } }, @@ -9961,9 +8886,9 @@ } }, "node_modules/npm-run-all2/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", "dependencies": { @@ -10086,7 +9011,7 @@ } }, "node_modules/npm/node_modules/@npmcli/arborist": { - "version": "7.5.3", + "version": "7.5.4", "inBundle": true, "license": "ISC", "dependencies": { @@ -10134,16 +9059,16 @@ } }, "node_modules/npm/node_modules/@npmcli/config": { - "version": "8.3.3", + "version": "8.3.4", "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/package-json": "^5.1.1", "ci-info": "^4.0.0", "ini": "^4.1.2", "nopt": "^7.2.1", "proc-log": "^4.2.0", - "read-package-json-fast": "^3.0.2", "semver": "^7.3.5", "walk-up-path": "^3.0.1" }, @@ -10163,11 +9088,12 @@ } }, "node_modules/npm/node_modules/@npmcli/git": { - "version": "5.0.7", + "version": "5.0.8", "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/promise-spawn": "^7.0.0", + "ini": "^4.1.3", "lru-cache": "^10.0.1", "npm-pick-manifest": "^9.0.0", "proc-log": "^4.0.0", @@ -10241,7 +9167,7 @@ } }, "node_modules/npm/node_modules/@npmcli/package-json": { - "version": "5.1.1", + "version": "5.2.0", "inBundle": true, "license": "ISC", "dependencies": { @@ -10280,7 +9206,7 @@ } }, "node_modules/npm/node_modules/@npmcli/redact": { - "version": "2.0.0", + "version": "2.0.1", "inBundle": true, "license": "ISC", "engines": { @@ -10652,7 +9578,7 @@ } }, "node_modules/npm/node_modules/debug": { - "version": "4.3.4", + "version": "4.3.5", "inBundle": true, "license": "MIT", "dependencies": { @@ -10726,7 +9652,7 @@ } }, "node_modules/npm/node_modules/foreground-child": { - "version": "3.1.1", + "version": "3.2.1", "inBundle": true, "license": "ISC", "dependencies": { @@ -10751,16 +9677,8 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm/node_modules/function-bind": { - "version": "1.1.2", - "inBundle": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/npm/node_modules/glob": { - "version": "10.4.1", + "version": "10.4.2", "inBundle": true, "license": "ISC", "dependencies": { @@ -10768,6 +9686,7 @@ "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { @@ -10785,17 +9704,6 @@ "inBundle": true, "license": "ISC" }, - "node_modules/npm/node_modules/hasown": { - "version": "2.0.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/npm/node_modules/hosted-git-info": { "version": "7.0.2", "inBundle": true, @@ -10825,7 +9733,7 @@ } }, "node_modules/npm/node_modules/https-proxy-agent": { - "version": "7.0.4", + "version": "7.0.5", "inBundle": true, "license": "MIT", "dependencies": { @@ -10934,17 +9842,6 @@ "node": ">=14" } }, - "node_modules/npm/node_modules/is-core-module": { - "version": "2.13.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/npm/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "inBundle": true, @@ -10964,7 +9861,7 @@ "license": "ISC" }, "node_modules/npm/node_modules/jackspeak": { - "version": "3.1.2", + "version": "3.4.0", "inBundle": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -11032,11 +9929,11 @@ } }, "node_modules/npm/node_modules/libnpmdiff": { - "version": "6.1.3", + "version": "6.1.4", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^7.5.3", + "@npmcli/arborist": "^7.5.4", "@npmcli/installed-package-contents": "^2.1.0", "binary-extensions": "^2.3.0", "diff": "^5.1.0", @@ -11050,11 +9947,11 @@ } }, "node_modules/npm/node_modules/libnpmexec": { - "version": "8.1.2", + "version": "8.1.3", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^7.5.3", + "@npmcli/arborist": "^7.5.4", "@npmcli/run-script": "^8.1.0", "ci-info": "^4.0.0", "npm-package-arg": "^11.0.2", @@ -11070,11 +9967,11 @@ } }, "node_modules/npm/node_modules/libnpmfund": { - "version": "5.0.11", + "version": "5.0.12", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^7.5.3" + "@npmcli/arborist": "^7.5.4" }, "engines": { "node": "^16.14.0 || >=18.0.0" @@ -11105,11 +10002,11 @@ } }, "node_modules/npm/node_modules/libnpmpack": { - "version": "7.0.3", + "version": "7.0.4", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^7.5.3", + "@npmcli/arborist": "^7.5.4", "@npmcli/run-script": "^8.1.0", "npm-package-arg": "^11.0.2", "pacote": "^18.0.6" @@ -11205,7 +10102,7 @@ } }, "node_modules/npm/node_modules/minimatch": { - "version": "9.0.4", + "version": "9.0.5", "inBundle": true, "license": "ISC", "dependencies": { @@ -11275,26 +10172,6 @@ "node": ">=8" } }, - "node_modules/npm/node_modules/minipass-json-stream": { - "version": "1.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" - } - }, - "node_modules/npm/node_modules/minipass-json-stream/node_modules/minipass": { - "version": "3.3.6", - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/npm/node_modules/minipass-pipeline": { "version": "1.2.4", "inBundle": true, @@ -11440,12 +10317,11 @@ } }, "node_modules/npm/node_modules/normalize-package-data": { - "version": "6.0.1", + "version": "6.0.2", "inBundle": true, "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^7.0.0", - "is-core-module": "^2.8.1", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4" }, @@ -11517,7 +10393,7 @@ } }, "node_modules/npm/node_modules/npm-pick-manifest": { - "version": "9.0.1", + "version": "9.1.0", "inBundle": true, "license": "ISC", "dependencies": { @@ -11543,15 +10419,15 @@ } }, "node_modules/npm/node_modules/npm-registry-fetch": { - "version": "17.0.1", + "version": "17.1.0", "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/redact": "^2.0.0", + "jsonparse": "^1.3.1", "make-fetch-happen": "^13.0.0", "minipass": "^7.0.2", "minipass-fetch": "^3.0.0", - "minipass-json-stream": "^1.0.1", "minizlib": "^2.1.2", "npm-package-arg": "^11.0.0", "proc-log": "^4.0.0" @@ -11582,6 +10458,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/npm/node_modules/package-json-from-dist": { + "version": "1.0.0", + "inBundle": true, + "license": "BlueOak-1.0.0" + }, "node_modules/npm/node_modules/pacote": { "version": "18.0.6", "inBundle": true, @@ -11852,13 +10733,13 @@ } }, "node_modules/npm/node_modules/socks-proxy-agent": { - "version": "8.0.3", + "version": "8.0.4", "inBundle": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.1", "debug": "^4.3.4", - "socks": "^2.7.1" + "socks": "^2.8.3" }, "engines": { "node": ">= 14" @@ -12249,6 +11130,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "deprecated": "This package is no longer supported.", "dev": true, "license": "ISC", "dependencies": { @@ -12278,10 +11160,14 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "dev": true, "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -12290,6 +11176,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -12299,6 +11186,7 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.5", @@ -12332,6 +11220,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/object.values": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", @@ -12645,6 +11548,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/pacote": { "version": "15.2.0", "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.2.0.tgz", @@ -12862,14 +11772,6 @@ "node": ">=8" } }, - "node_modules/phin": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/phin/-/phin-2.9.3.tgz", - "integrity": "sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "dev": true, - "license": "MIT" - }, "node_modules/picocolors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", @@ -13046,15 +11948,16 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/postcss-selector-parser": { - "version": "6.0.16", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", - "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz", + "integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==", "dev": true, "license": "MIT", "dependencies": { @@ -13066,9 +11969,9 @@ } }, "node_modules/prettier": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true, "license": "MIT", "bin": { @@ -13082,9 +11985,9 @@ } }, "node_modules/pretty-ms": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.0.0.tgz", - "integrity": "sha512-E9e9HJ9R9NasGOgPaPE8VMeiPKAyWR5jcFpNnwIejslIhWqdqOrb2wShBsncMPUb+BcCd2OPYfh7p2W6oemTng==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.1.0.tgz", + "integrity": "sha512-o1piW0n3tgKIKCwk2vpM/vOV13zjJzvP37Ioze54YlTHE06m4tjEbzg9WsKkvTuyYln2DHjo5pY4qrZGI0otpw==", "license": "MIT", "dependencies": { "parse-ms": "^4.0.0" @@ -13244,9 +12147,9 @@ "license": "ISC" }, "node_modules/publint": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/publint/-/publint-0.2.8.tgz", - "integrity": "sha512-C5MjGJ7gpanqaDpgBN+6QhjvXcoj0/YpbucoW29oO5729CGTMzfr3wZTIYcpzB1xl9ZfEqj4KL86P2Z50pt/JA==", + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/publint/-/publint-0.2.10.tgz", + "integrity": "sha512-5TzYaAFiGpgkYX/k6VaItRMT2uHI4zO5OWJ2k7Er0Ot3jutBCNTJB1qRHuy1lYq07JhRczzFs6HFPB4D+A47xA==", "dev": true, "license": "MIT", "dependencies": { @@ -13278,6 +12181,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "license": "ISC", "dependencies": { @@ -13374,19 +12278,17 @@ } }, "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } + "license": "MIT" }, "node_modules/q": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/q/-/q-2.0.3.tgz", "integrity": "sha512-gv6vLGcmAOg96/fgo3d9tvA4dJNZL3fMyBqVRrGxQ+Q/o4k9QzbJ3NQF9cOO/71wRodoXhaPgphvMFU68qVAJQ==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", "dev": true, "license": "MIT", "dependencies": { @@ -13486,6 +12388,7 @@ "version": "6.0.4", "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.4.tgz", "integrity": "sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw==", + "deprecated": "This package is no longer supported. Please use @npmcli/package-json instead.", "dev": true, "license": "ISC", "dependencies": { @@ -13523,32 +12426,30 @@ } }, "node_modules/read-package-json/node_modules/glob": { - "version": "10.3.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.15.tgz", - "integrity": "sha512-0c6RlJt1TICLyvJYIApxb8GsXoai0KUP7AxKKAtsYXdgJR1mGEUa7DgwShbdk1nly0PYoZj01xd4hzbq3fsjpw==", + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.6", - "minimatch": "^9.0.1", - "minipass": "^7.0.4", - "path-scurry": "^1.11.0" + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/read-package-json/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", "dependencies": { @@ -13578,18 +12479,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/read-package-up/node_modules/type-fest": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.18.2.tgz", - "integrity": "sha512-+suCYpfJLAe4OXS6+PPXjW3urOS4IoP9waSiLuXfLgqZODKw/aWwASvzqE886wA0kQgGy0mIWyhd87VpqIy6Xg==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/read-pkg": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", @@ -13609,44 +12498,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/read-pkg-up": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-11.0.0.tgz", - "integrity": "sha512-LOVbvF1Q0SZdjClSefZ0Nz5z8u+tIE7mV5NibzmE9VYmDe9CaBbAVtz1veOSZbofrdsilxuDAYnFenukZVp8/Q==", - "deprecated": "Renamed to read-package-up", - "license": "MIT", - "dependencies": { - "find-up-simple": "^1.0.0", - "read-pkg": "^9.0.0", - "type-fest": "^4.6.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.18.2.tgz", - "integrity": "sha512-+suCYpfJLAe4OXS6+PPXjW3urOS4IoP9waSiLuXfLgqZODKw/aWwASvzqE886wA0kQgGy0mIWyhd87VpqIy6Xg==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.1.tgz", - "integrity": "sha512-6rvCfeRW+OEZagAB4lMLSNuTNYZWLVtKccK79VSTf//yTY5VOCgcpH80O+bZK8Neps7pUnd5G+QlMg1yV/2iZQ==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^7.0.0", - "is-core-module": "^2.8.1", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4" }, @@ -13671,18 +12529,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/read-pkg/node_modules/type-fest": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.18.2.tgz", - "integrity": "sha512-+suCYpfJLAe4OXS6+PPXjW3urOS4IoP9waSiLuXfLgqZODKw/aWwASvzqE886wA0kQgGy0mIWyhd87VpqIy6Xg==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -13698,24 +12544,11 @@ "node": ">= 6" } }, - "node_modules/readdir-scoped-modules": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", - "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "dev": true, - "license": "ISC", - "dependencies": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } - }, "node_modules/regexp.prototype.flags": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.6", @@ -13883,6 +12716,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", "dependencies": { @@ -13955,6 +12789,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -13994,6 +12829,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.6", @@ -14015,17 +12851,17 @@ "license": "MIT" }, "node_modules/semantic-release": { - "version": "23.1.1", - "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-23.1.1.tgz", - "integrity": "sha512-qqJDBhbtHsjUEMsojWKGuL5lQFCJuPtiXKEIlFKyTzDDGTAE/oyvznaP8GeOr5PvcqBJ6LQz4JCENWPLeehSpA==", + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-24.0.0.tgz", + "integrity": "sha512-v46CRPw+9eI3ZuYGF2oAjqPqsfbnfFTwLBgQsv/lch4goD09ytwOTESMN4QIrx/wPLxUGey60/NMx+ANQtWRsA==", "license": "MIT", "peer": true, "dependencies": { - "@semantic-release/commit-analyzer": "^12.0.0", + "@semantic-release/commit-analyzer": "^13.0.0-beta.1", "@semantic-release/error": "^4.0.0", "@semantic-release/github": "^10.0.0", "@semantic-release/npm": "^12.0.0", - "@semantic-release/release-notes-generator": "^13.0.0", + "@semantic-release/release-notes-generator": "^14.0.0-beta.1", "aggregate-error": "^5.0.0", "cosmiconfig": "^9.0.0", "debug": "^4.0.0", @@ -14058,87 +12894,10 @@ "node": ">=20.8.1" } }, - "node_modules/semantic-release/node_modules/@semantic-release/commit-analyzer": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-12.0.0.tgz", - "integrity": "sha512-qG+md5gdes+xa8zP7lIo1fWE17zRdO8yMCaxh9lyL65TQleoSv8WHHOqRURfghTytUh+NpkSyBprQ5hrkxOKVQ==", - "peer": true, - "dependencies": { - "conventional-changelog-angular": "^7.0.0", - "conventional-commits-filter": "^4.0.0", - "conventional-commits-parser": "^5.0.0", - "debug": "^4.0.0", - "import-from-esm": "^1.0.3", - "lodash-es": "^4.17.21", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">=20.8.1" - }, - "peerDependencies": { - "semantic-release": ">=20.1.0" - } - }, - "node_modules/semantic-release/node_modules/@semantic-release/release-notes-generator": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-13.0.0.tgz", - "integrity": "sha512-LEeZWb340keMYuREMyxrODPXJJ0JOL8D/mCl74B4LdzbxhtXV2LrPN2QBEcGJrlQhoqLO0RhxQb6masHytKw+A==", - "peer": true, - "dependencies": { - "conventional-changelog-angular": "^7.0.0", - "conventional-changelog-writer": "^7.0.0", - "conventional-commits-filter": "^4.0.0", - "conventional-commits-parser": "^5.0.0", - "debug": "^4.0.0", - "get-stream": "^7.0.0", - "import-from-esm": "^1.0.3", - "into-stream": "^7.0.0", - "lodash-es": "^4.17.21", - "read-pkg-up": "^11.0.0" - }, - "engines": { - "node": ">=20.8.1" - }, - "peerDependencies": { - "semantic-release": ">=20.1.0" - } - }, - "node_modules/semantic-release/node_modules/@semantic-release/release-notes-generator/node_modules/get-stream": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-7.0.1.tgz", - "integrity": "sha512-3M8C1EOFN6r8AMUhwUAACIoXZJEOufDU5+0gFFN5uNs6XYOralD2Pqkl7m046va6x77FwposWXbAhPPIOus7mQ==", - "peer": true, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semantic-release/node_modules/conventional-changelog-writer": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-7.0.1.tgz", - "integrity": "sha512-Uo+R9neH3r/foIvQ0MKcsXkX642hdm9odUp7TqgFS7BsalTcjzRlIfWZrZR1gbxOozKucaKt5KAbjW8J8xRSmA==", - "peer": true, - "dependencies": { - "conventional-commits-filter": "^4.0.0", - "handlebars": "^4.7.7", - "json-stringify-safe": "^5.0.1", - "meow": "^12.0.1", - "semver": "^7.5.2", - "split2": "^4.0.0" - }, - "bin": { - "conventional-changelog-writer": "cli.mjs" - }, - "engines": { - "node": ">=16" - } - }, "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -14214,6 +12973,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -14231,6 +12991,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -14277,6 +13038,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -14513,9 +13275,9 @@ } }, "node_modules/sigstore/node_modules/minipass-fetch/node_modules/minipass": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.1.tgz", - "integrity": "sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, "license": "ISC", "engines": { @@ -14678,9 +13440,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.17", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", - "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", + "version": "3.0.18", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", + "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", "license": "CC0-1.0" }, "node_modules/split-ca": { @@ -14691,13 +13453,12 @@ "license": "ISC" }, "node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-1.0.0.tgz", + "integrity": "sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg==", "license": "ISC", - "peer": true, - "engines": { - "node": ">= 10.x" + "dependencies": { + "through2": "~2.0.0" } }, "node_modules/sprintf-js": { @@ -14775,9 +13536,9 @@ } }, "node_modules/stream-buffers": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-3.0.2.tgz", - "integrity": "sha512-DQi1h8VEBA/lURbSwFtEHnSTb9s2/pwLEaFuNhXwy1Dx3Sa0lOuYT2yNUr4/j2fs8oCAMANtrZ5OrPZtyVs3MQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-3.0.3.tgz", + "integrity": "sha512-pqMqwQCso0PBJt2PQmDO0cFj0lyqmiwOMiMSkVtRokl7e+ZTRYgDHKnuZNbqjiJXgsg4nuqtD/zxuo9KqTp0Yw==", "dev": true, "license": "Unlicense", "engines": { @@ -14851,9 +13612,9 @@ } }, "node_modules/string-width": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", - "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "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": { @@ -14928,6 +13689,7 @@ "version": "1.2.9", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -14946,6 +13708,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -14960,6 +13723,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -15518,18 +14282,65 @@ } }, "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", + "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", "dev": true, "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" + "glob": "^10.4.1", + "minimatch": "^9.0.4" }, "engines": { - "node": ">=8" + "node": ">=18" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/testdouble": { @@ -15548,19 +14359,6 @@ "node": ">= 16" } }, - "node_modules/text-extensions": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", - "integrity": "sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -15593,6 +14391,7 @@ "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, "license": "MIT" }, "node_modules/through2": { @@ -15699,15 +14498,10 @@ "license": "MIT" }, "node_modules/traverse": { - "version": "0.6.9", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.9.tgz", - "integrity": "sha512-7bBrcF+/LQzSgFmT0X5YclVqQxtv7TDJ1f8Wj7ibBu/U6BMLeOpUxuZjV7rMc44UtKxlnMFigdhFAIszSX1DMg==", + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.8.tgz", + "integrity": "sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA==", "license": "MIT", - "dependencies": { - "gopd": "^1.0.1", - "typedarray.prototype.slice": "^1.0.3", - "which-typed-array": "^1.1.15" - }, "engines": { "node": ">= 0.4" }, @@ -15726,9 +14520,9 @@ } }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", "dev": true, "license": "0BSD" }, @@ -15855,9 +14649,9 @@ } }, "node_modules/tuf-js/node_modules/minipass-fetch/node_modules/minipass": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.1.tgz", - "integrity": "sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, "license": "ISC", "engines": { @@ -15872,9 +14666,9 @@ "license": "Unlicense" }, "node_modules/type": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", - "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", "dev": true, "license": "ISC" }, @@ -15889,13 +14683,12 @@ } }, "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.24.0.tgz", + "integrity": "sha512-spAaHzc6qre0TlZQQ2aA/nGMe+2Z/wyGk5Z+Ru2VUfdNwT6kWO6TjevOlpebsATEG1EIQ2sOiDszud3lO5mt/Q==", "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=10" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -15905,6 +14698,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -15919,6 +14713,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -15938,6 +14733,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", @@ -15958,6 +14754,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -15984,30 +14781,10 @@ "is-typedarray": "^1.0.0" } }, - "node_modules/typedarray.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typedarray.prototype.slice/-/typedarray.prototype.slice-1.0.3.tgz", - "integrity": "sha512-8WbVAQAUlENo1q3c3zZYuy5k9VzBQvp8AX9WOtbvyWlLM1v5JaSRmjubLjzHF4JFtptjH/5c/i95yaElvcjC0A==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.0", - "es-errors": "^1.3.0", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-offset": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", "license": "Apache-2.0", "optional": true, "peer": true, @@ -16020,9 +14797,9 @@ } }, "node_modules/uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "version": "3.19.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.2.tgz", + "integrity": "sha512-S8KA6DDI47nQXJSi2ctQ629YzwOVs+bQML6DAtvy0wgNdpi+0ySpQK0g2pxBq2xfF2z3YCscu7NNA8nXT9PlIQ==", "license": "BSD-2-Clause", "optional": true, "bin": { @@ -16036,6 +14813,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -16048,9 +14826,9 @@ } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", + "integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==", "dev": true, "license": "MIT", "optional": true @@ -16132,16 +14910,6 @@ "node": ">= 10.0.0" } }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, "node_modules/url-join": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", @@ -16192,9 +14960,9 @@ } }, "node_modules/v8-to-istanbul": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", - "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, "license": "ISC", "dependencies": { @@ -16332,6 +15100,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, "license": "MIT", "dependencies": { "is-bigint": "^1.0.1", @@ -16348,6 +15117,7 @@ "version": "1.1.15", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", @@ -16801,9 +15571,9 @@ } }, "node_modules/yoctocolors": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.0.2.tgz", - "integrity": "sha512-Ct97huExsu7cWeEjmrXlofevF8CvzUglJ4iGUet5B8xn1oumtAZBpHU4GzYuoE6PVqcZ5hghtBrSlhwHuR1Jmw==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.1.tgz", + "integrity": "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==", "license": "MIT", "engines": { "node": ">=18" diff --git a/package.json b/package.json index 13aec0caab..e3880d32fa 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "ava": { "files": [ "test/**/*.test.js", - "!test/integration.test.js" + "!test/integration.test.js", + "!test/e2e.test.js" ], "nodeArguments": [ "--loader=testdouble", @@ -59,25 +60,25 @@ }, "devDependencies": { "ava": "6.1.3", - "c8": "9.1.0", + "c8": "10.1.2", "clear-module": "4.1.2", "codecov": "3.8.3", "cz-conventional-changelog": "3.3.0", "dockerode": "4.0.2", "file-url": "4.0.0", "fs-extra": "11.2.0", - "got": "14.3.0", + "got": "14.4.2", "js-yaml": "4.1.0", - "lockfile-lint": "4.13.2", - "ls-engines": "0.9.1", + "lockfile-lint": "4.14.0", + "ls-engines": "0.9.3", "mockserver-client": "5.15.0", "nock": "13.5.4", - "npm-run-all2": "6.2.0", + "npm-run-all2": "6.2.2", "p-retry": "6.2.0", - "prettier": "3.2.5", - "publint": "0.2.8", + "prettier": "3.3.3", + "publint": "0.2.10", "sinon": "18.0.0", - "stream-buffers": "3.0.2", + "stream-buffers": "3.0.3", "tempy": "3.1.0", "testdouble": "3.20.2" }, @@ -155,12 +156,13 @@ "semantic-release": "./bin/semantic-release.js", "test": "npm-run-all --print-label --parallel lint:* --parallel test:*", "test:unit": "c8 ava --verbose", - "test:integration": "ava --verbose test/integration.test.js" + "test:integration": "ava --verbose test/integration.test.js", + "test:e2e": "ava --verbose test/e2e.test.js" }, "renovate": { "extends": [ "github>semantic-release/.github:renovate-config" ] }, - "packageManager": "npm@10.8.1" + "packageManager": "npm@10.8.2" } diff --git a/test/e2e.test.js b/test/e2e.test.js new file mode 100644 index 0000000000..62d793259b --- /dev/null +++ b/test/e2e.test.js @@ -0,0 +1,742 @@ +import path from "node:path"; +import { setTimeout } from "node:timers/promises"; +import test from "ava"; +import * as td from "testdouble"; +import { escapeRegExp } from "lodash-es"; +import fsExtra from "fs-extra"; +import { execa } from "execa"; +import { WritableStreamBuffer } from "stream-buffers"; + +import getAuthUrl from "../lib/get-git-auth-url.js"; +import { SECRET_REPLACEMENT } from "../lib/definitions/constants.js"; +import { + gitCheckout, + gitCommits, + gitGetNote, + gitHead, + gitPush, + gitRemoteTagHead, + gitRepo, + gitTagHead, + merge, +} from "./helpers/git-utils.js"; +import { npmView } from "./helpers/npm-utils.js"; +import * as gitbox from "./helpers/gitbox.js"; +import * as mockServer from "./helpers/mockserver.js"; +import * as npmRegistry from "./helpers/npm-registry.js"; + +const { readJson, writeJson } = fsExtra; + +/* eslint camelcase: ["error", {properties: "never"}] */ + +// Environment variables used with semantic-release cli (similar to what a user would setup) +const { GITHUB_ACTION, GITHUB_ACTIONS, GITHUB_TOKEN, ...processEnvWithoutGitHubActionsVariables } = process.env; +let env; + +// Environment variables used only for the local npm command used to do verification +const npmTestEnv = { + ...processEnvWithoutGitHubActionsVariables, + ...npmRegistry.authEnv(), + npm_config_registry: npmRegistry.url, +}; + +const cli = path.resolve("./bin/semantic-release.js"); +const pluginError = path.resolve("./test/fixtures/plugin-error"); +const pluginInheritedError = path.resolve("./test/fixtures/plugin-error-inherited"); +const pluginLogEnv = path.resolve("./test/fixtures/plugin-log-env"); +const pluginEsmNamedExports = path.resolve("./test/fixtures/plugin-esm-named-exports"); + +test.before(async () => { + await Promise.all([gitbox.pull(), npmRegistry.pull(), mockServer.pull()]); + await Promise.all([gitbox.start(), npmRegistry.start(), mockServer.start()]); + + env = { + ...processEnvWithoutGitHubActionsVariables, + ...npmRegistry.authEnv(), + CI: "true", + GH_TOKEN: gitbox.gitCredential, + TRAVIS: "true", + TRAVIS_BRANCH: "master", + TRAVIS_PULL_REQUEST: "false", + GITHUB_API_URL: mockServer.url, + }; +}); + +test.after.always(async () => { + await Promise.all([gitbox.stop(), npmRegistry.stop(), mockServer.stop()]); +}); + +test.serial("Release patch, minor and major versions", async (t) => { + const packageName = "test-release"; + const owner = "git"; + // Create a git repository, set the current working directory at the root of the repo + t.log("Create git repository and package.json"); + const { cwd, repositoryUrl, authUrl } = await gitbox.createRepo(packageName); + // Create package.json in repository root + await writeJson(path.resolve(cwd, "package.json"), { + name: packageName, + version: "0.0.0-dev", + repository: { url: repositoryUrl }, + publishConfig: { registry: npmRegistry.url }, + release: { branches: ["master", "next"], success: false, fail: false }, + }); + // Create a npm-shrinkwrap.json file + await execa("npm", ["shrinkwrap"], { env: npmTestEnv, cwd, extendEnv: false }); + + /* No release */ + let verifyMock = await mockServer.mock( + `/repos/${owner}/${packageName}`, + { headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] }, + { body: { permissions: { push: true } }, method: "GET" } + ); + t.log("Commit a chore"); + await gitCommits(["chore: Init repository"], { cwd }); + t.log("$ semantic-release"); + let { stdout, exitCode } = await execa(cli, [], { env, cwd, extendEnv: false }); + t.regex(stdout, /There are no relevant changes, so no new version is released/); + t.is(exitCode, 0); + + /* Initial release */ + let version = "1.0.0"; + verifyMock = await mockServer.mock( + `/repos/${owner}/${packageName}`, + { headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] }, + { body: { permissions: { push: true } }, method: "GET" } + ); + let createReleaseMock = await mockServer.mock( + `/repos/${owner}/${packageName}/releases`, + { + body: { tag_name: `v${version}`, name: `v${version}` }, + headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }], + }, + { body: { html_url: `release-url/${version}` } } + ); + + t.log("Commit a feature"); + await gitCommits(["feat: Initial commit"], { cwd }); + t.log("$ semantic-release"); + ({ stdout, exitCode } = await execa(cli, [], { env, cwd, extendEnv: false })); + t.regex(stdout, new RegExp(`Published GitHub release: release-url/${version}`)); + t.regex(stdout, new RegExp(`Publishing version ${version} to npm registry`)); + t.is(exitCode, 0); + + // Verify package.json and npm-shrinkwrap.json have been updated + t.is((await readJson(path.resolve(cwd, "package.json"))).version, version); + t.is((await readJson(path.resolve(cwd, "npm-shrinkwrap.json"))).version, version); + + // Retrieve the published package from the registry and check version and gitHead + let { + "dist-tags": { latest: releasedVersion }, + } = await npmView(packageName, npmTestEnv); + let head = await gitHead({ cwd }); + t.is(releasedVersion, version); + t.is(await gitTagHead(`v${version}`, { cwd }), head); + t.is(await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), head); + t.log(`+ released ${releasedVersion}`); + + await mockServer.verify(verifyMock); + await mockServer.verify(createReleaseMock); + + /* Patch release */ + version = "1.0.1"; + verifyMock = await mockServer.mock( + `/repos/${owner}/${packageName}`, + { headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] }, + { body: { permissions: { push: true } }, method: "GET" } + ); + createReleaseMock = await mockServer.mock( + `/repos/${owner}/${packageName}/releases`, + { + body: { tag_name: `v${version}`, name: `v${version}` }, + headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }], + }, + { body: { html_url: `release-url/${version}` } } + ); + + t.log("Commit a fix"); + await gitCommits(["fix: bar"], { cwd }); + t.log("$ semantic-release"); + ({ stdout, exitCode } = await execa(cli, [], { env, cwd, extendEnv: false })); + t.regex(stdout, new RegExp(`Published GitHub release: release-url/${version}`)); + t.regex(stdout, new RegExp(`Publishing version ${version} to npm registry`)); + t.is(exitCode, 0); + + // Verify package.json and npm-shrinkwrap.json have been updated + t.is((await readJson(path.resolve(cwd, "package.json"))).version, version); + t.is((await readJson(path.resolve(cwd, "npm-shrinkwrap.json"))).version, version); + + // Retrieve the published package from the registry and check version and gitHead + ({ + "dist-tags": { latest: releasedVersion }, + } = await npmView(packageName, npmTestEnv)); + head = await gitHead({ cwd }); + t.is(releasedVersion, version); + t.is(await gitTagHead(`v${version}`, { cwd }), head); + t.is(await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), head); + t.log(`+ released ${releasedVersion}`); + + await mockServer.verify(verifyMock); + await mockServer.verify(createReleaseMock); + + /* Minor release */ + version = "1.1.0"; + verifyMock = await mockServer.mock( + `/repos/${owner}/${packageName}`, + { headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] }, + { body: { permissions: { push: true } }, method: "GET" } + ); + createReleaseMock = await mockServer.mock( + `/repos/${owner}/${packageName}/releases`, + { + body: { tag_name: `v${version}`, name: `v${version}` }, + headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }], + }, + { body: { html_url: `release-url/${version}` } } + ); + + t.log("Commit a feature"); + await gitCommits(["feat: baz"], { cwd }); + t.log("$ semantic-release"); + ({ stdout, exitCode } = await execa(cli, [], { env, cwd, extendEnv: false })); + t.regex(stdout, new RegExp(`Published GitHub release: release-url/${version}`)); + t.regex(stdout, new RegExp(`Publishing version ${version} to npm registry`)); + t.is(exitCode, 0); + + // Verify package.json and npm-shrinkwrap.json have been updated + t.is((await readJson(path.resolve(cwd, "package.json"))).version, version); + t.is((await readJson(path.resolve(cwd, "npm-shrinkwrap.json"))).version, version); + + // Retrieve the published package from the registry and check version and gitHead + ({ + "dist-tags": { latest: releasedVersion }, + } = await npmView(packageName, npmTestEnv)); + head = await gitHead({ cwd }); + t.is(releasedVersion, version); + t.is(await gitTagHead(`v${version}`, { cwd }), head); + t.is(await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), head); + t.log(`+ released ${releasedVersion}`); + + await mockServer.verify(verifyMock); + await mockServer.verify(createReleaseMock); + + /* Major release on next */ + version = "2.0.0"; + verifyMock = await mockServer.mock( + `/repos/${owner}/${packageName}`, + { headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] }, + { body: { permissions: { push: true } }, method: "GET" } + ); + createReleaseMock = await mockServer.mock( + `/repos/${owner}/${packageName}/releases`, + { + body: { tag_name: `v${version}`, name: `v${version}` }, + headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }], + }, + { body: { html_url: `release-url/${version}` } } + ); + + t.log("Commit a breaking change on next"); + await gitCheckout("next", true, { cwd }); + await gitPush("origin", "next", { cwd }); + await gitCommits(["feat: foo\n\n BREAKING CHANGE: bar"], { cwd }); + t.log("$ semantic-release"); + ({ stdout, exitCode } = await execa(cli, [], { env: { ...env, TRAVIS_BRANCH: "next" }, cwd, extendEnv: false })); + t.regex(stdout, new RegExp(`Published GitHub release: release-url/${version}`)); + t.regex(stdout, new RegExp(`Publishing version ${version} to npm registry`)); + t.is(exitCode, 0); + + // Verify package.json and npm-shrinkwrap.json have been updated + t.is((await readJson(path.resolve(cwd, "package.json"))).version, version); + t.is((await readJson(path.resolve(cwd, "npm-shrinkwrap.json"))).version, version); + + // Retrieve the published package from the registry and check version and gitHead + ({ + "dist-tags": { next: releasedVersion }, + } = await npmView(packageName, npmTestEnv)); + head = await gitHead({ cwd }); + t.is(releasedVersion, version); + t.is(await gitGetNote(`v${version}`, { cwd }), '{"channels":["next"]}'); + t.is(await gitTagHead(`v${version}`, { cwd }), head); + t.is(await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), head); + t.log(`+ released ${releasedVersion} on @next`); + + await mockServer.verify(verifyMock); + await mockServer.verify(createReleaseMock); + + /* Merge next into master */ + version = "2.0.0"; + const releaseId = 1; + verifyMock = await mockServer.mock( + `/repos/${owner}/${packageName}`, + { headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] }, + { body: { permissions: { push: true } }, method: "GET" } + ); + const getReleaseMock = await mockServer.mock( + `/repos/${owner}/${packageName}/releases/tags/v2.0.0`, + { headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] }, + { body: { id: releaseId }, method: "GET" } + ); + const updateReleaseMock = await mockServer.mock( + `/repos/${owner}/${packageName}/releases/${releaseId}`, + { + body: { name: `v${version}`, prerelease: false }, + headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }], + }, + { body: { html_url: `release-url/${version}` }, method: "PATCH" } + ); + + t.log("Merge next into master"); + await gitCheckout("master", false, { cwd }); + await merge("next", { cwd }); + await gitPush("origin", "master", { cwd }); + t.log("$ semantic-release"); + ({ stdout, exitCode } = await execa(cli, [], { env, cwd, extendEnv: false })); + t.regex(stdout, new RegExp(`Updated GitHub release: release-url/${version}`)); + t.regex(stdout, new RegExp(`Adding version ${version} to npm registry on dist-tag latest`)); + t.is(exitCode, 0); + + // Wait for 3s as the change of dist-tag takes time to be reflected in the registry + await setTimeout(3000); + // Retrieve the published package from the registry and check version and gitHead + ({ + "dist-tags": { latest: releasedVersion }, + } = await npmView(packageName, npmTestEnv)); + t.is(releasedVersion, version); + t.is(await gitGetNote(`v${version}`, { cwd }), '{"channels":["next",null]}'); + t.is(await gitTagHead(`v${version}`, { cwd }), await gitTagHead(`v${version}`, { cwd })); + t.is( + await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), + await gitRemoteTagHead(authUrl, `v${version}`, { cwd }) + ); + t.log(`+ added ${releasedVersion}`); + + await mockServer.verify(verifyMock); + await mockServer.verify(getReleaseMock); + await mockServer.verify(updateReleaseMock); +}); + +test.serial("Exit with 1 if a plugin is not found", async (t) => { + const packageName = "test-plugin-not-found"; + const owner = "test-repo"; + // Create a git repository, set the current working directory at the root of the repo + t.log("Create git repository"); + const { cwd } = await gitRepo(); + await writeJson(path.resolve(cwd, "package.json"), { + name: packageName, + version: "0.0.0-dev", + repository: { url: `git+https://github.com/${owner}/${packageName}` }, + release: { analyzeCommits: "non-existing-path", success: false, fail: false }, + }); + + const { exitCode, stderr } = await t.throwsAsync(execa(cli, [], { env, cwd, extendEnv: false })); + t.is(exitCode, 1); + t.regex(stderr, /Cannot find module/); +}); + +test.serial("Exit with 1 if a shareable config is not found", async (t) => { + const packageName = "test-config-not-found"; + const owner = "test-repo"; + // Create a git repository, set the current working directory at the root of the repo + t.log("Create git repository"); + const { cwd } = await gitRepo(); + await writeJson(path.resolve(cwd, "package.json"), { + name: packageName, + version: "0.0.0-dev", + repository: { url: `git+https://github.com/${owner}/${packageName}` }, + release: { extends: "non-existing-path", success: false, fail: false }, + }); + + const { exitCode, stderr } = await t.throwsAsync(execa(cli, [], { env, cwd, extendEnv: false })); + t.is(exitCode, 1); + t.regex(stderr, /Cannot find module/); +}); + +test.serial("Exit with 1 if a shareable config reference a not found plugin", async (t) => { + const packageName = "test-config-ref-not-found"; + const owner = "test-repo"; + const shareable = { analyzeCommits: "non-existing-path" }; + + // Create a git repository, set the current working directory at the root of the repo + t.log("Create git repository"); + const { cwd } = await gitRepo(); + await writeJson(path.resolve(cwd, "package.json"), { + name: packageName, + version: "0.0.0-dev", + repository: { url: `git+https://github.com/${owner}/${packageName}` }, + release: { extends: "./shareable.json", success: false, fail: false }, + }); + await writeJson(path.resolve(cwd, "shareable.json"), shareable); + + const { exitCode, stderr } = await t.throwsAsync(execa(cli, [], { env, cwd, extendEnv: false })); + t.is(exitCode, 1); + t.regex(stderr, /Cannot find module/); +}); + +test.serial("Dry-run", async (t) => { + const packageName = "test-dry-run"; + const owner = "git"; + // Create a git repository, set the current working directory at the root of the repo + t.log("Create git repository and package.json"); + const { cwd, repositoryUrl } = await gitbox.createRepo(packageName); + // Create package.json in repository root + await writeJson(path.resolve(cwd, "package.json"), { + name: packageName, + version: "0.0.0-dev", + repository: { url: repositoryUrl }, + publishConfig: { registry: npmRegistry.url }, + release: { success: false, fail: false }, + }); + + /* Initial release */ + const verifyMock = await mockServer.mock( + `/repos/${owner}/${packageName}`, + { headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] }, + { body: { permissions: { push: true } }, method: "GET" } + ); + const version = "1.0.0"; + t.log("Commit a feature"); + await gitCommits(["feat: Initial commit"], { cwd }); + t.log("$ semantic-release -d"); + const { stdout, exitCode } = await execa(cli, ["-d"], { env, cwd, extendEnv: false }); + t.regex(stdout, new RegExp(`There is no previous release, the next release version is ${version}`)); + t.regex(stdout, new RegExp(`Release note for version ${version}`)); + t.regex(stdout, /Initial commit/); + t.is(exitCode, 0); + + // Verify package.json and has not been modified + t.is((await readJson(path.resolve(cwd, "package.json"))).version, "0.0.0-dev"); + await mockServer.verify(verifyMock); +}); + +test.serial('Allow local releases with "noCi" option', async (t) => { + const envNoCi = { ...env }; + delete envNoCi.CI; + const packageName = "test-no-ci"; + const owner = "git"; + // Create a git repository, set the current working directory at the root of the repo + t.log("Create git repository and package.json"); + const { cwd, repositoryUrl, authUrl } = await gitbox.createRepo(packageName); + // Create package.json in repository root + await writeJson(path.resolve(cwd, "package.json"), { + name: packageName, + version: "0.0.0-dev", + repository: { url: repositoryUrl }, + publishConfig: { registry: npmRegistry.url }, + release: { success: false, fail: false }, + }); + + /* Initial release */ + const version = "1.0.0"; + const verifyMock = await mockServer.mock( + `/repos/${owner}/${packageName}`, + { headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] }, + { body: { permissions: { push: true } }, method: "GET" } + ); + const createReleaseMock = await mockServer.mock( + `/repos/${owner}/${packageName}/releases`, + { + body: { tag_name: `v${version}`, name: `v${version}` }, + headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }], + }, + { body: { html_url: `release-url/${version}` } } + ); + + t.log("Commit a feature"); + await gitCommits(["feat: Initial commit"], { cwd }); + t.log("$ semantic-release --no-ci"); + const { stdout, exitCode } = await execa(cli, ["--no-ci"], { env: envNoCi, cwd, extendEnv: false }); + t.regex(stdout, new RegExp(`Published GitHub release: release-url/${version}`)); + t.regex(stdout, new RegExp(`Publishing version ${version} to npm registry`)); + t.is(exitCode, 0); + + // Verify package.json and has been updated + t.is((await readJson(path.resolve(cwd, "package.json"))).version, version); + + // Retrieve the published package from the registry and check version and gitHead + const { version: releasedVersion, gitHead: releasedGitHead } = await npmView(packageName, npmTestEnv); + + const head = await gitHead({ cwd }); + t.is(releasedVersion, version); + t.is(releasedGitHead, head); + t.is(await gitTagHead(`v${version}`, { cwd }), head); + t.is(await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), head); + t.log(`+ released ${releasedVersion} with head ${releasedGitHead}`); + + await mockServer.verify(verifyMock); + await mockServer.verify(createReleaseMock); +}); + +test.serial("Pass options via CLI arguments", async (t) => { + const packageName = "test-cli"; + // Create a git repository, set the current working directory at the root of the repo + t.log("Create git repository and package.json"); + const { cwd, repositoryUrl, authUrl } = await gitbox.createRepo(packageName); + // Create package.json in repository root + await writeJson(path.resolve(cwd, "package.json"), { + name: packageName, + version: "0.0.0-dev", + repository: { url: repositoryUrl }, + publishConfig: { registry: npmRegistry.url }, + }); + + /* Initial release */ + const version = "1.0.0"; + t.log("Commit a feature"); + await gitCommits(["feat: Initial commit"], { cwd }); + t.log("$ semantic-release"); + const { stdout, exitCode } = await execa( + cli, + [ + "--verify-conditions", + "@semantic-release/npm", + "--publish", + "@semantic-release/npm", + `--success`, + false, + `--fail`, + false, + "--debug", + ], + { env, cwd, extendEnv: false } + ); + t.regex(stdout, new RegExp(`Publishing version ${version} to npm registry`)); + t.is(exitCode, 0); + + // Verify package.json and has been updated + t.is((await readJson(path.resolve(cwd, "package.json"))).version, version); + + // Retrieve the published package from the registry and check version and gitHead + const { version: releasedVersion, gitHead: releasedGitHead } = await npmView(packageName, npmTestEnv); + const head = await gitHead({ cwd }); + t.is(releasedVersion, version); + t.is(releasedGitHead, head); + t.is(await gitTagHead(`v${version}`, { cwd }), head); + t.is(await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), head); + t.log(`+ released ${releasedVersion} with head ${releasedGitHead}`); +}); + +test.serial("Run via JS API", async (t) => { + await td.replaceEsm("../lib/logger", null, { log: () => {}, error: () => {}, stdout: () => {} }); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); + const semanticRelease = (await import("../index.js")).default; + const packageName = "test-js-api"; + const owner = "git"; + // Create a git repository, set the current working directory at the root of the repo + t.log("Create git repository and package.json"); + const { cwd, repositoryUrl, authUrl } = await gitbox.createRepo(packageName); + // Create package.json in repository root + await writeJson(path.resolve(cwd, "package.json"), { + name: packageName, + version: "0.0.0-dev", + repository: { url: repositoryUrl }, + publishConfig: { registry: npmRegistry.url }, + release: { + fail: false, + success: false, + }, + }); + + /* Initial release */ + const version = "1.0.0"; + const verifyMock = await mockServer.mock( + `/repos/${owner}/${packageName}`, + { headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] }, + { body: { permissions: { push: true } }, method: "GET" } + ); + const createReleaseMock = await mockServer.mock( + `/repos/${owner}/${packageName}/releases`, + { + body: { tag_name: `v${version}`, name: `v${version}` }, + headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }], + }, + { body: { html_url: `release-url/${version}` } } + ); + + t.log("Commit a feature"); + await gitCommits(["feat: Initial commit"], { cwd }); + t.log("$ Call semantic-release via API"); + await semanticRelease(undefined, { + cwd, + env, + stdout: new WritableStreamBuffer(), + stderr: new WritableStreamBuffer(), + }); + + // Verify package.json and has been updated + t.is((await readJson(path.resolve(cwd, "package.json"))).version, version); + + // Retrieve the published package from the registry and check version and gitHead + const { version: releasedVersion, gitHead: releasedGitHead } = await npmView(packageName, npmTestEnv); + const head = await gitHead({ cwd }); + t.is(releasedVersion, version); + t.is(releasedGitHead, head); + t.is(await gitTagHead(`v${version}`, { cwd }), head); + t.is(await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), head); + t.log(`+ released ${releasedVersion} with head ${releasedGitHead}`); + + await mockServer.verify(verifyMock); + await mockServer.verify(createReleaseMock); +}); + +test.serial("Log unexpected errors from plugins and exit with 1", async (t) => { + const packageName = "test-unexpected-error"; + // Create a git repository, set the current working directory at the root of the repo + t.log("Create git repository and package.json"); + const { cwd, repositoryUrl } = await gitbox.createRepo(packageName); + // Create package.json in repository root + await writeJson(path.resolve(cwd, "package.json"), { + name: packageName, + version: "0.0.0-dev", + repository: { url: repositoryUrl }, + release: { verifyConditions: pluginError, fail: false, success: false }, + }); + + /* Initial release */ + t.log("Commit a feature"); + await gitCommits(["feat: Initial commit"], { cwd }); + t.log("$ semantic-release"); + const { stderr, exitCode } = await execa(cli, [], { env, cwd, reject: false, extendEnv: false }); + // Verify the type and message are logged + t.regex(stderr, /Error: a/); + // Verify the stacktrace is logged + t.regex(stderr, new RegExp(process.platform === "win32" ? pluginError.replace(/\\/g, "\\\\") : pluginError)); + // Verify the Error properties are logged + t.regex(stderr, /errorProperty: 'errorProperty'/); + t.is(exitCode, 1); +}); + +test.serial("Log errors inheriting SemanticReleaseError and exit with 1", async (t) => { + const packageName = "test-inherited-error"; + // Create a git repository, set the current working directory at the root of the repo + t.log("Create git repository and package.json"); + const { cwd, repositoryUrl } = await gitbox.createRepo(packageName); + // Create package.json in repository root + await writeJson(path.resolve(cwd, "package.json"), { + name: packageName, + version: "0.0.0-dev", + repository: { url: repositoryUrl }, + release: { verifyConditions: pluginInheritedError, fail: false, success: false }, + }); + + /* Initial release */ + t.log("Commit a feature"); + await gitCommits(["feat: Initial commit"], { cwd }); + t.log("$ semantic-release"); + const { stderr, exitCode } = await execa(cli, [], { env, cwd, reject: false, extendEnv: false }); + // Verify the type and message are logged + t.regex(stderr, /EINHERITED Inherited error/); + t.is(exitCode, 1); +}); + +test.serial("Exit with 1 if missing permission to push to the remote repository", async (t) => { + const packageName = "unauthorized"; + // Create a git repository, set the current working directory at the root of the repo + t.log("Create git repository"); + const { cwd } = await gitbox.createRepo(packageName); + await writeJson(path.resolve(cwd, "package.json"), { name: packageName, version: "0.0.0-dev" }); + + /* Initial release */ + t.log("Commit a feature"); + await gitCommits(["feat: Initial commit"], { cwd }); + await gitPush("origin", "master", { cwd }); + t.log("$ semantic-release"); + const { stderr, exitCode } = await execa( + cli, + ["--repository-url", "http://user:wrong_pass@localhost:2080/git/unauthorized.git"], + { env: { ...env, GH_TOKEN: "user:wrong_pass" }, cwd, reject: false, extendEnv: false } + ); + // Verify the type and message are logged + t.regex(stderr, /EGITNOPERMISSION/); + t.is(exitCode, 1); +}); + +test.serial("Hide sensitive environment variable values from the logs", async (t) => { + const packageName = "log-secret"; + // Create a git repository, set the current working directory at the root of the repo + t.log("Create git repository"); + const { cwd, repositoryUrl } = await gitbox.createRepo(packageName); + await writeJson(path.resolve(cwd, "package.json"), { + name: packageName, + version: "0.0.0-dev", + repository: { url: repositoryUrl }, + release: { verifyConditions: [pluginLogEnv], fail: false, success: false }, + }); + + t.log("$ semantic-release"); + const { stdout, stderr } = await execa(cli, [], { + env: { ...env, MY_TOKEN: "secret token" }, + cwd, + reject: false, + extendEnv: false, + }); + + t.regex(stdout, new RegExp(`Console: Exposing token ${escapeRegExp(SECRET_REPLACEMENT)}`)); + t.regex(stdout, new RegExp(`Log: Exposing token ${escapeRegExp(SECRET_REPLACEMENT)}`)); + t.regex(stderr, new RegExp(`Error: Console token ${escapeRegExp(SECRET_REPLACEMENT)}`)); + t.regex(stderr, new RegExp(`Throw error: Exposing ${escapeRegExp(SECRET_REPLACEMENT)}`)); +}); + +test.serial("Use the valid git credentials when multiple are provided", async (t) => { + const { cwd, authUrl } = await gitbox.createRepo("test-auth"); + + t.is( + await getAuthUrl({ + cwd, + env: { + GITHUB_TOKEN: "dummy", + GITLAB_TOKEN: "trash", + BB_TOKEN_BASIC_AUTH: gitbox.gitCredential, + GIT_ASKPASS: "echo", + GIT_TERMINAL_PROMPT: 0, + GIT_CONFIG_PARAMETERS: "'credential.helper='", + }, + branch: { name: "master" }, + options: { repositoryUrl: "http://toto@localhost:2080/git/test-auth.git" }, + }), + authUrl + ); +}); + +test.serial("Use the repository URL as is if none of the given git credentials are valid", async (t) => { + const { cwd } = await gitbox.createRepo("test-invalid-auth"); + const dummyUrl = "http://toto@localhost:2080/git/test-invalid-auth.git"; + + t.is( + await getAuthUrl({ + cwd, + env: { + GITHUB_TOKEN: "dummy", + GITLAB_TOKEN: "trash", + GIT_ASKPASS: "echo", + GIT_TERMINAL_PROMPT: 0, + GIT_CONFIG_PARAMETERS: "'credential.helper='", + }, + branch: { name: "master" }, + options: { repositoryUrl: dummyUrl }, + }), + dummyUrl + ); +}); + +test.serial("ESM Plugin with named exports", async (t) => { + const packageName = "plugin-exports"; + // Create a git repository, set the current working directory at the root of the repo + t.log("Create git repository"); + const { cwd, repositoryUrl } = await gitbox.createRepo(packageName); + await writeJson(path.resolve(cwd, "package.json"), { + name: packageName, + version: "0.0.0-dev", + repository: { url: repositoryUrl }, + release: { plugins: [pluginEsmNamedExports] }, + }); + + t.log("$ semantic-release"); + const { stdout, stderr } = await execa(cli, [], { + env: { ...env, MY_TOKEN: "secret token" }, + cwd, + reject: false, + extendEnv: false, + }); + + t.regex(stdout, new RegExp(`verifyConditions called`)); +}); diff --git a/test/get-logger.test.js b/test/get-logger.test.js index f6a946e06a..eb1ce4a3d6 100644 --- a/test/get-logger.test.js +++ b/test/get-logger.test.js @@ -2,7 +2,7 @@ import test from "ava"; import { spy } from "sinon"; import getLogger from "../lib/get-logger.js"; -test('Expose "error", "success" and "log" functions', (t) => { +test('Expose "error", "success", warn and "log" functions', (t) => { const stdout = spy(); const stderr = spy(); const logger = getLogger({ stdout: { write: stdout }, stderr: { write: stderr } }); @@ -10,8 +10,10 @@ test('Expose "error", "success" and "log" functions', (t) => { logger.log("test log"); logger.success("test success"); logger.error("test error"); + logger.warn("test warn"); t.regex(stdout.args[0][0], /.*test log/); t.regex(stdout.args[1][0], /.*test success/); t.regex(stderr.args[0][0], /.*test error/); + t.regex(stderr.args[1][0], /.*test warn/); }); diff --git a/test/index.test.js b/test/index.test.js deleted file mode 100644 index 4d0e00e8eb..0000000000 --- a/test/index.test.js +++ /dev/null @@ -1,1997 +0,0 @@ -import test from "ava"; -import { escapeRegExp, isString, omit, sortBy } from "lodash-es"; -import * as td from "testdouble"; -import { spy, stub } from "sinon"; -import { WritableStreamBuffer } from "stream-buffers"; -import AggregateError from "aggregate-error"; -import SemanticReleaseError from "@semantic-release/error"; -import { COMMIT_EMAIL, COMMIT_NAME, SECRET_REPLACEMENT } from "../lib/definitions/constants.js"; -import { - gitAddNote, - gitCheckout, - gitCommits, - gitGetNote, - gitHead as getGitHead, - gitPush, - gitRemoteTagHead, - gitRepo, - gitShallowClone, - gitTagHead, - gitTagVersion, - merge, - mergeFf, - rebase, -} from "./helpers/git-utils.js"; -import pluginNoop from "./fixtures/plugin-noop.cjs"; - -test.beforeEach((t) => { - // Stub the logger functions - t.context.log = spy(); - t.context.error = spy(); - t.context.success = spy(); - t.context.warn = spy(); - t.context.logger = { - log: t.context.log, - error: t.context.error, - success: t.context.success, - warn: t.context.warn, - scope: () => t.context.logger, - }; -}); - -test.afterEach.always((t) => { - td.reset(); -}); - -test.serial("Plugins are called with expected values", async (t) => { - // Create a git repository, set the current working directory at the root of the repo - const { cwd, repositoryUrl } = await gitRepo(true); - // Add commits to the master branch - let commits = await gitCommits(["First"], { cwd }); - // Create the tag corresponding to version 1.0.0 - await gitTagVersion("v1.0.0", undefined, { cwd }); - await gitAddNote(JSON.stringify({ channels: ["next"] }), "v1.0.0", { cwd }); - commits = (await gitCommits(["Second"], { cwd })).concat(commits); - await gitCheckout("next", true, { cwd }); - await gitPush(repositoryUrl, "next", { cwd }); - await gitCheckout("master", false, { cwd }); - await gitPush(repositoryUrl, "master", { cwd }); - - const lastRelease = { - version: "1.0.0", - gitHead: commits[commits.length - 1].hash, - gitTag: "v1.0.0", - name: "v1.0.0", - channels: ["next"], - }; - const nextRelease = { - name: "v1.1.0", - type: "minor", - version: "1.1.0", - gitHead: await getGitHead({ cwd }), - gitTag: "v1.1.0", - channel: null, - }; - const notes1 = "Release notes 1"; - const notes2 = "Release notes 2"; - const notes3 = "Release notes 3"; - const verifyConditions1 = stub().resolves(); - const verifyConditions2 = stub().resolves(); - const analyzeCommits = stub().resolves(nextRelease.type); - const verifyRelease = stub().resolves(); - const generateNotes1 = stub().resolves(notes1); - const generateNotes2 = stub().resolves(notes2); - const generateNotes3 = stub().resolves(notes3); - const release1 = { name: "Release 1", url: "https://release1.com" }; - const release2 = { name: "Release 2", url: "https://release2.com" }; - const addChannel = stub().resolves(release1); - const prepare = stub().resolves(); - const publish = stub().resolves(release2); - const success = stub().resolves(); - const env = {}; - const config = { - branches: [{ name: "master" }, { name: "next" }], - repositoryUrl, - originalRepositoryURL: repositoryUrl, - globalOpt: "global", - tagFormat: `v\${version}`, - }; - const branches = [ - { - channel: undefined, - name: "master", - range: ">=1.0.0", - accept: ["patch", "minor", "major"], - tags: [{ channels: ["next"], gitTag: "v1.0.0", version: "1.0.0" }], - type: "release", - main: true, - }, - { - channel: "next", - name: "next", - range: ">=1.0.0", - accept: ["patch", "minor", "major"], - tags: [{ channels: ["next"], gitTag: "v1.0.0", version: "1.0.0" }], - type: "release", - main: false, - }, - ]; - const branch = branches[0]; - const options = { - ...config, - plugins: false, - verifyConditions: [verifyConditions1, verifyConditions2], - analyzeCommits, - verifyRelease, - addChannel, - generateNotes: [generateNotes1, generateNotes2, generateNotes3], - prepare, - publish: [publish, pluginNoop], - success, - }; - const envCiResults = { branch: "master", isCi: true, isPr: false }; - - const releases = [ - { - ...omit(lastRelease, "channels"), - ...release1, - type: "major", - version: "1.0.0", - channel: null, - gitTag: "v1.0.0", - notes: `${notes1}\n\n${notes2}\n\n${notes3}`, - pluginName: "[Function: functionStub]", - }, - { - ...nextRelease, - ...release2, - notes: `${notes1}\n\n${notes2}\n\n${notes3}`, - pluginName: "[Function: functionStub]", - }, - { ...nextRelease, notes: `${notes1}\n\n${notes2}\n\n${notes3}`, pluginName: "[Function: noop]" }, - ]; - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - const envCi = (await td.replaceEsm("env-ci")).default; - td.when(envCi({ env, cwd })).thenReturn(envCiResults); - const semanticRelease = (await import("../index.js")).default; - const result = await semanticRelease(options, { - cwd, - env, - stdout: new WritableStreamBuffer(), - stderr: new WritableStreamBuffer(), - }); - - t.is(verifyConditions1.callCount, 1); - t.deepEqual(verifyConditions1.args[0][0], config); - t.deepEqual(verifyConditions1.args[0][1].cwd, cwd); - t.deepEqual(verifyConditions1.args[0][1].options, options); - t.deepEqual(verifyConditions1.args[0][1].branch, branch); - t.deepEqual(verifyConditions1.args[0][1].branches, branches); - t.deepEqual(verifyConditions1.args[0][1].logger, t.context.logger); - t.deepEqual(verifyConditions1.args[0][1].envCi, envCiResults); - t.is(verifyConditions2.callCount, 1); - t.deepEqual(verifyConditions2.args[0][0], config); - t.deepEqual(verifyConditions2.args[0][1].cwd, cwd); - t.deepEqual(verifyConditions2.args[0][1].options, options); - t.deepEqual(verifyConditions2.args[0][1].branch, branch); - t.deepEqual(verifyConditions2.args[0][1].branches, branches); - t.deepEqual(verifyConditions2.args[0][1].logger, t.context.logger); - t.deepEqual(verifyConditions2.args[0][1].envCi, envCiResults); - - t.is(generateNotes1.callCount, 2); - t.is(generateNotes2.callCount, 2); - t.is(generateNotes3.callCount, 2); - - t.deepEqual(generateNotes1.args[0][0], config); - t.deepEqual(generateNotes1.args[0][1].options, options); - t.deepEqual(generateNotes1.args[0][1].branch, branch); - t.deepEqual(generateNotes1.args[0][1].branches, branches); - t.deepEqual(generateNotes1.args[0][1].logger, t.context.logger); - t.deepEqual(generateNotes1.args[0][1].lastRelease, {}); - t.deepEqual(generateNotes1.args[0][1].commits[0].hash, commits[1].hash); - t.deepEqual(generateNotes1.args[0][1].commits[0].message, commits[1].message); - t.deepEqual(generateNotes1.args[0][1].nextRelease, { - ...omit(lastRelease, "channels"), - type: "major", - version: "1.0.0", - channel: null, - gitTag: "v1.0.0", - name: "v1.0.0", - }); - t.deepEqual(generateNotes2.args[0][1].envCi, envCiResults); - - t.deepEqual(generateNotes2.args[0][0], config); - t.deepEqual(generateNotes2.args[0][1].options, options); - t.deepEqual(generateNotes2.args[0][1].branch, branch); - t.deepEqual(generateNotes2.args[0][1].branches, branches); - t.deepEqual(generateNotes2.args[0][1].logger, t.context.logger); - t.deepEqual(generateNotes2.args[0][1].lastRelease, {}); - t.deepEqual(generateNotes2.args[0][1].commits[0].hash, commits[1].hash); - t.deepEqual(generateNotes2.args[0][1].commits[0].message, commits[1].message); - t.deepEqual(generateNotes2.args[0][1].nextRelease, { - ...omit(lastRelease, "channels"), - type: "major", - version: "1.0.0", - channel: null, - gitTag: "v1.0.0", - name: "v1.0.0", - notes: notes1, - }); - t.deepEqual(generateNotes2.args[0][1].envCi, envCiResults); - - t.deepEqual(generateNotes3.args[0][0], config); - t.deepEqual(generateNotes3.args[0][1].options, options); - t.deepEqual(generateNotes3.args[0][1].branch, branch); - t.deepEqual(generateNotes3.args[0][1].branches, branches); - t.deepEqual(generateNotes3.args[0][1].logger, t.context.logger); - t.deepEqual(generateNotes3.args[0][1].lastRelease, {}); - t.deepEqual(generateNotes3.args[0][1].commits[0].hash, commits[1].hash); - t.deepEqual(generateNotes3.args[0][1].commits[0].message, commits[1].message); - t.deepEqual(generateNotes3.args[0][1].nextRelease, { - ...omit(lastRelease, "channels"), - type: "major", - version: "1.0.0", - channel: null, - gitTag: "v1.0.0", - name: "v1.0.0", - notes: `${notes1}\n\n${notes2}`, - }); - t.deepEqual(generateNotes3.args[0][1].envCi, envCiResults); - - branch.tags.push({ - version: "1.0.0", - channel: null, - gitTag: "v1.0.0", - gitHead: commits[commits.length - 1].hash, - }); - - t.is(addChannel.callCount, 1); - t.deepEqual(addChannel.args[0][0], config); - t.deepEqual(addChannel.args[0][1].options, options); - t.deepEqual(addChannel.args[0][1].branch, branch); - t.deepEqual(addChannel.args[0][1].branches, branches); - t.deepEqual(addChannel.args[0][1].logger, t.context.logger); - t.deepEqual(addChannel.args[0][1].lastRelease, {}); - t.deepEqual(addChannel.args[0][1].currentRelease, { ...lastRelease, type: "major" }); - t.deepEqual(addChannel.args[0][1].nextRelease, { - ...omit(lastRelease, "channels"), - type: "major", - version: "1.0.0", - channel: null, - gitTag: "v1.0.0", - name: "v1.0.0", - notes: `${notes1}\n\n${notes2}\n\n${notes3}`, - }); - t.deepEqual(addChannel.args[0][1].commits[0].hash, commits[1].hash); - t.deepEqual(addChannel.args[0][1].commits[0].message, commits[1].message); - t.deepEqual(addChannel.args[0][1].envCi, envCiResults); - - t.is(analyzeCommits.callCount, 1); - t.deepEqual(analyzeCommits.args[0][0], config); - t.deepEqual(analyzeCommits.args[0][1].options, options); - t.deepEqual(analyzeCommits.args[0][1].branch, branch); - t.deepEqual(analyzeCommits.args[0][1].branches, branches); - t.deepEqual(analyzeCommits.args[0][1].logger, t.context.logger); - t.deepEqual(analyzeCommits.args[0][1].lastRelease, lastRelease); - t.deepEqual(analyzeCommits.args[0][1].commits[0].hash, commits[0].hash); - t.deepEqual(analyzeCommits.args[0][1].commits[0].message, commits[0].message); - t.deepEqual(analyzeCommits.args[0][1].envCi, envCiResults); - - t.is(verifyRelease.callCount, 1); - t.deepEqual(verifyRelease.args[0][0], config); - t.deepEqual(verifyRelease.args[0][1].options, options); - t.deepEqual(verifyRelease.args[0][1].branch, branch); - t.deepEqual(verifyRelease.args[0][1].branches, branches); - t.deepEqual(verifyRelease.args[0][1].logger, t.context.logger); - t.deepEqual(verifyRelease.args[0][1].lastRelease, lastRelease); - t.deepEqual(verifyRelease.args[0][1].commits[0].hash, commits[0].hash); - t.deepEqual(verifyRelease.args[0][1].commits[0].message, commits[0].message); - t.deepEqual(verifyRelease.args[0][1].nextRelease, nextRelease); - t.deepEqual(verifyRelease.args[0][1].envCi, envCiResults); - - t.deepEqual(generateNotes1.args[1][0], config); - t.deepEqual(generateNotes1.args[1][1].options, options); - t.deepEqual(generateNotes1.args[1][1].branch, branch); - t.deepEqual(generateNotes1.args[1][1].branches, branches); - t.deepEqual(generateNotes1.args[1][1].logger, t.context.logger); - t.deepEqual(generateNotes1.args[1][1].lastRelease, lastRelease); - t.deepEqual(generateNotes1.args[1][1].commits[0].hash, commits[0].hash); - t.deepEqual(generateNotes1.args[1][1].commits[0].message, commits[0].message); - t.deepEqual(generateNotes1.args[1][1].nextRelease, nextRelease); - t.deepEqual(generateNotes1.args[1][1].envCi, envCiResults); - - t.deepEqual(generateNotes2.args[1][0], config); - t.deepEqual(generateNotes2.args[1][1].options, options); - t.deepEqual(generateNotes2.args[1][1].branch, branch); - t.deepEqual(generateNotes2.args[1][1].branches, branches); - t.deepEqual(generateNotes2.args[1][1].logger, t.context.logger); - t.deepEqual(generateNotes2.args[1][1].lastRelease, lastRelease); - t.deepEqual(generateNotes2.args[1][1].commits[0].hash, commits[0].hash); - t.deepEqual(generateNotes2.args[1][1].commits[0].message, commits[0].message); - t.deepEqual(generateNotes2.args[1][1].nextRelease, { ...nextRelease, notes: notes1 }); - t.deepEqual(generateNotes2.args[1][1].envCi, envCiResults); - - t.deepEqual(generateNotes3.args[1][0], config); - t.deepEqual(generateNotes3.args[1][1].options, options); - t.deepEqual(generateNotes3.args[1][1].branch, branch); - t.deepEqual(generateNotes3.args[1][1].branches, branches); - t.deepEqual(generateNotes3.args[1][1].logger, t.context.logger); - t.deepEqual(generateNotes3.args[1][1].lastRelease, lastRelease); - t.deepEqual(generateNotes3.args[1][1].commits[0].hash, commits[0].hash); - t.deepEqual(generateNotes3.args[1][1].commits[0].message, commits[0].message); - t.deepEqual(generateNotes3.args[1][1].nextRelease, { ...nextRelease, notes: `${notes1}\n\n${notes2}` }); - t.deepEqual(generateNotes3.args[1][1].envCi, envCiResults); - - t.is(prepare.callCount, 1); - t.deepEqual(prepare.args[0][0], config); - t.deepEqual(prepare.args[0][1].options, options); - t.deepEqual(prepare.args[0][1].branch, branch); - t.deepEqual(prepare.args[0][1].branches, branches); - t.deepEqual(prepare.args[0][1].logger, t.context.logger); - t.deepEqual(prepare.args[0][1].lastRelease, lastRelease); - t.deepEqual(prepare.args[0][1].commits[0].hash, commits[0].hash); - t.deepEqual(prepare.args[0][1].commits[0].message, commits[0].message); - t.deepEqual(prepare.args[0][1].nextRelease, { ...nextRelease, notes: `${notes1}\n\n${notes2}\n\n${notes3}` }); - t.deepEqual(prepare.args[0][1].envCi, envCiResults); - - t.is(publish.callCount, 1); - t.deepEqual(publish.args[0][0], config); - t.deepEqual(publish.args[0][1].options, options); - t.deepEqual(publish.args[0][1].branch, branch); - t.deepEqual(publish.args[0][1].branches, branches); - t.deepEqual(publish.args[0][1].logger, t.context.logger); - t.deepEqual(publish.args[0][1].lastRelease, lastRelease); - t.deepEqual(publish.args[0][1].commits[0].hash, commits[0].hash); - t.deepEqual(publish.args[0][1].commits[0].message, commits[0].message); - t.deepEqual(publish.args[0][1].nextRelease, { ...nextRelease, notes: `${notes1}\n\n${notes2}\n\n${notes3}` }); - t.deepEqual(publish.args[0][1].envCi, envCiResults); - - t.is(success.callCount, 2); - t.deepEqual(success.args[0][0], config); - t.deepEqual(success.args[0][1].options, options); - t.deepEqual(success.args[0][1].branch, branch); - t.deepEqual(success.args[0][1].branches, branches); - t.deepEqual(success.args[0][1].logger, t.context.logger); - t.deepEqual(success.args[0][1].lastRelease, {}); - t.deepEqual(success.args[0][1].commits[0].hash, commits[1].hash); - t.deepEqual(success.args[0][1].commits[0].message, commits[1].message); - t.deepEqual(success.args[0][1].nextRelease, { - ...omit(lastRelease, "channels"), - type: "major", - version: "1.0.0", - channel: null, - gitTag: "v1.0.0", - name: "v1.0.0", - notes: `${notes1}\n\n${notes2}\n\n${notes3}`, - }); - t.deepEqual(success.args[0][1].releases, [releases[0]]); - t.deepEqual(success.args[0][1].envCi, envCiResults); - - t.deepEqual(success.args[1][0], config); - t.deepEqual(success.args[1][1].options, options); - t.deepEqual(success.args[1][1].branch, branch); - t.deepEqual(success.args[1][1].branches, branches); - t.deepEqual(success.args[1][1].logger, t.context.logger); - t.deepEqual(success.args[1][1].lastRelease, lastRelease); - t.deepEqual(success.args[1][1].commits[0].hash, commits[0].hash); - t.deepEqual(success.args[1][1].commits[0].message, commits[0].message); - t.deepEqual(success.args[1][1].nextRelease, { ...nextRelease, notes: `${notes1}\n\n${notes2}\n\n${notes3}` }); - t.deepEqual(success.args[1][1].releases, [releases[1], releases[2]]); - t.deepEqual(success.args[1][1].envCi, envCiResults); - - t.deepEqual(result, { - lastRelease, - commits: [{ ...commits[0], gitTags: "(HEAD -> master, next)" }], - nextRelease: { ...nextRelease, notes: `${notes1}\n\n${notes2}\n\n${notes3}` }, - releases, - }); - - // Verify the tag has been created on the local and remote repo and reference the gitHead - t.is(await gitTagHead(nextRelease.gitTag, { cwd }), nextRelease.gitHead); - t.is(await gitRemoteTagHead(repositoryUrl, nextRelease.gitTag, { cwd }), nextRelease.gitHead); - - // Verify the author/commiter name and email have been set - t.is(env.GIT_AUTHOR_NAME, COMMIT_NAME); - t.is(env.GIT_AUTHOR_EMAIL, COMMIT_EMAIL); - t.is(env.GIT_COMMITTER_NAME, COMMIT_NAME); - t.is(env.GIT_COMMITTER_EMAIL, COMMIT_EMAIL); -}); - -test.serial("Use custom tag format", async (t) => { - const { cwd, repositoryUrl } = await gitRepo(true); - await gitCommits(["First"], { cwd }); - await gitTagVersion("test-1.0.0", undefined, { cwd }); - await gitCommits(["Second"], { cwd }); - await gitPush(repositoryUrl, "master", { cwd }); - - const nextRelease = { - name: "test-2.0.0", - type: "major", - version: "2.0.0", - gitHead: await getGitHead({ cwd }), - gitTag: "test-2.0.0", - }; - const notes = "Release notes"; - const config = { branches: "master", repositoryUrl, globalOpt: "global", tagFormat: `test-\${version}` }; - const options = { - ...config, - verifyConditions: stub().resolves(), - analyzeCommits: stub().resolves(nextRelease.type), - verifyRelease: stub().resolves(), - generateNotes: stub().resolves(notes), - addChannel: stub().resolves(), - prepare: stub().resolves(), - publish: stub().resolves(), - success: stub().resolves(), - fail: stub().resolves(), - }; - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); - const semanticRelease = (await import("../index.js")).default; - t.truthy( - await semanticRelease(options, { - cwd, - env: {}, - stdout: new WritableStreamBuffer(), - stderr: new WritableStreamBuffer(), - }) - ); - - // Verify the tag has been created on the local and remote repo and reference the gitHead - t.is(await gitTagHead(nextRelease.gitTag, { cwd }), nextRelease.gitHead); - t.is(await gitRemoteTagHead(repositoryUrl, nextRelease.gitTag, { cwd }), nextRelease.gitHead); -}); - -test.serial("Use new gitHead, and recreate release notes if a prepare plugin create a commit", async (t) => { - // Create a git repository, set the current working directory at the root of the repo - const { cwd, repositoryUrl } = await gitRepo(true); - // Add commits to the master branch - let commits = await gitCommits(["First"], { cwd }); - // Create the tag corresponding to version 1.0.0 - await gitTagVersion("v1.0.0", undefined, { cwd }); - // Add new commits to the master branch - commits = (await gitCommits(["Second"], { cwd })).concat(commits); - await gitPush(repositoryUrl, "master", { cwd }); - - const nextRelease = { - name: "v2.0.0", - type: "major", - version: "2.0.0", - gitHead: await getGitHead({ cwd }), - gitTag: "v2.0.0", - channel: null, - }; - const notes = "Release notes"; - - const generateNotes = stub().resolves(notes); - const prepare1 = stub().callsFake(async () => { - commits = (await gitCommits(["Third"], { cwd })).concat(commits); - }); - const prepare2 = stub().resolves(); - const publish = stub().resolves(); - const options = { - branches: ["master"], - repositoryUrl, - verifyConditions: stub().resolves(), - analyzeCommits: stub().resolves(nextRelease.type), - verifyRelease: stub().resolves(), - generateNotes, - addChannel: stub().resolves(), - prepare: [prepare1, prepare2], - publish, - success: stub().resolves(), - fail: stub().resolves(), - }; - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); - const semanticRelease = (await import("../index.js")).default; - - t.truthy( - await semanticRelease(options, { - cwd, - env: {}, - stdout: new WritableStreamBuffer(), - stderr: new WritableStreamBuffer(), - }) - ); - - t.is(generateNotes.callCount, 2); - t.deepEqual(generateNotes.args[0][1].nextRelease, nextRelease); - t.is(prepare1.callCount, 1); - t.deepEqual(prepare1.args[0][1].nextRelease, { ...nextRelease, notes }); - - nextRelease.gitHead = await getGitHead({ cwd }); - - t.deepEqual(generateNotes.args[1][1].nextRelease, { ...nextRelease, notes }); - t.is(prepare2.callCount, 1); - t.deepEqual(prepare2.args[0][1].nextRelease, { ...nextRelease, notes }); - - t.is(publish.callCount, 1); - t.deepEqual(publish.args[0][1].nextRelease, { ...nextRelease, notes }); - - // Verify the tag has been created on the local and remote repo and reference the last gitHead - t.is(await gitTagHead(nextRelease.gitTag, { cwd }), commits[0].hash); - t.is(await gitRemoteTagHead(repositoryUrl, nextRelease.gitTag, { cwd }), commits[0].hash); -}); - -test.serial("Make a new release when a commit is forward-ported to an upper branch", async (t) => { - const { cwd, repositoryUrl } = await gitRepo(true); - await gitCommits(["feat: initial release"], { cwd }); - await gitTagVersion("v1.0.0", undefined, { cwd }); - await gitAddNote(JSON.stringify({ channels: [null, "1.0.x"] }), "v1.0.0", { cwd }); - await gitCheckout("1.0.x", true, { cwd }); - await gitCommits(["fix: fix on maintenance version 1.0.x"], { cwd }); - await gitTagVersion("v1.0.1", undefined, { cwd }); - await gitAddNote(JSON.stringify({ channels: ["1.0.x"] }), "v1.0.1", { cwd }); - await gitPush("origin", "1.0.x", { cwd }); - await gitCheckout("master", false, { cwd }); - await gitCommits(["feat: new feature on master"], { cwd }); - await gitTagVersion("v1.1.0", undefined, { cwd }); - await merge("1.0.x", { cwd }); - await gitPush("origin", "master", { cwd }); - - const verifyConditions = stub().resolves(); - const verifyRelease = stub().resolves(); - const addChannel = stub().resolves(); - const prepare = stub().resolves(); - const publish = stub().resolves(); - const success = stub().resolves(); - - const config = { branches: [{ name: "1.0.x" }, { name: "master" }], repositoryUrl, tagFormat: `v\${version}` }; - const options = { - ...config, - verifyConditions, - verifyRelease, - addChannel, - prepare, - publish, - success, - }; - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); - const semanticRelease = (await import("../index.js")).default; - t.truthy(await semanticRelease(options, { cwd, env: {}, stdout: { write: () => {} }, stderr: { write: () => {} } })); - - t.is(addChannel.callCount, 0); - t.is(publish.callCount, 1); - // The release 1.1.1, triggered by the forward-port of "fix: fix on maintenance version 1.0.x" has been published from master - t.is(publish.args[0][1].nextRelease.version, "1.1.1"); - t.is(success.callCount, 1); -}); - -test.serial("Publish a pre-release version", async (t) => { - const { cwd, repositoryUrl } = await gitRepo(true); - await gitCommits(["feat: initial commit"], { cwd }); - await gitTagVersion("v1.0.0", undefined, { cwd }); - await gitPush(repositoryUrl, "master", { cwd }); - await gitCheckout("beta", true, { cwd }); - await gitCommits(["feat: a feature"], { cwd }); - await gitPush(repositoryUrl, "beta", { cwd }); - - const config = { branches: ["master", { name: "beta", prerelease: true }], repositoryUrl }; - const options = { - ...config, - verifyConditions: stub().resolves(), - verifyRelease: stub().resolves(), - generateNotes: stub().resolves(""), - addChannel: false, - prepare: stub().resolves(), - publish: stub().resolves(), - success: stub().resolves(), - fail: stub().resolves(), - }; - - const env = {}; - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - const envCi = (await td.replaceEsm("env-ci")).default; - td.when(envCi({ env, cwd })).thenReturn({ isCi: true, branch: "beta", isPr: false }); - const semanticRelease = (await import("../index.js")).default; - let { releases } = await semanticRelease(options, { - cwd, - env: {}, - stdout: { write: () => {} }, - stderr: { write: () => {} }, - }); - - t.is(releases.length, 1); - t.is(releases[0].version, "1.1.0-beta.1"); - t.is(releases[0].gitTag, "v1.1.0-beta.1"); - t.is(await gitGetNote("v1.1.0-beta.1", { cwd }), '{"channels":["beta"]}'); - - await gitCommits(["fix: a fix"], { cwd }); - ({ releases } = await semanticRelease(options, { - cwd, - env, - stdout: { write: () => {} }, - stderr: { write: () => {} }, - })); - - t.is(releases.length, 1); - t.is(releases[0].version, "1.1.0-beta.2"); - t.is(releases[0].gitTag, "v1.1.0-beta.2"); - t.is(await gitGetNote("v1.1.0-beta.2", { cwd }), '{"channels":["beta"]}'); -}); - -test.serial("Publish releases from different branch on the same channel", async (t) => { - const { cwd, repositoryUrl } = await gitRepo(true); - await gitCommits(["feat: initial commit"], { cwd }); - await gitTagVersion("v1.0.0", undefined, { cwd }); - await gitPush(repositoryUrl, "master", { cwd }); - await gitCheckout("next-major", true, { cwd }); - await gitPush(repositoryUrl, "next-major", { cwd }); - await gitCheckout("next", true, { cwd }); - await gitCommits(["feat: a feature"], { cwd }); - await gitPush(repositoryUrl, "next", { cwd }); - - const config = { - branches: ["master", { name: "next", channel: false }, { name: "next-major", channel: false }], - repositoryUrl, - }; - const addChannel = stub().resolves({}); - const options = { - ...config, - verifyConditions: stub().resolves(), - verifyRelease: stub().resolves(), - generateNotes: stub().resolves(""), - addChannel, - prepare: stub().resolves(), - publish: stub().resolves(), - success: stub().resolves(), - fail: stub().resolves(), - }; - - const env = {}; - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - const envCi = (await td.replaceEsm("env-ci")).default; - td.when(envCi({ env, cwd })).thenReturn({ isCi: true, branch: "next", isPr: false }); - let semanticRelease = (await import("../index.js")).default; - let { releases } = await semanticRelease(options, { - cwd, - env, - stdout: { write: () => {} }, - stderr: { write: () => {} }, - }); - - t.is(releases.length, 1); - t.is(releases[0].version, "1.1.0"); - t.is(releases[0].gitTag, "v1.1.0"); - - await gitCommits(["fix: a fix"], { cwd }); - ({ releases } = await semanticRelease(options, { - cwd, - env, - stdout: { write: () => {} }, - stderr: { write: () => {} }, - })); - - t.is(releases.length, 1); - t.is(releases[0].version, "1.1.1"); - t.is(releases[0].gitTag, "v1.1.1"); - - await gitCheckout("master", false, { cwd }); - await merge("next", { cwd }); - await gitPush("origin", "master", { cwd }); - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); - semanticRelease = (await import("../index.js")).default; - - t.falsy(await semanticRelease(options, { cwd, env: {}, stdout: { write: () => {} }, stderr: { write: () => {} } })); - t.is(addChannel.callCount, 0); -}); - -test.serial("Publish pre-releases the same channel as regular releases", async (t) => { - const { cwd, repositoryUrl } = await gitRepo(true); - await gitCommits(["feat: initial commit"], { cwd }); - await gitTagVersion("v1.0.0", undefined, { cwd }); - await gitPush(repositoryUrl, "master", { cwd }); - await gitCheckout("beta", true, { cwd }); - await gitCommits(["feat: a feature"], { cwd }); - await gitPush(repositoryUrl, "beta", { cwd }); - - const config = { - branches: ["master", { name: "beta", channel: false, prerelease: true }], - repositoryUrl, - }; - const options = { - ...config, - verifyConditions: stub().resolves(), - verifyRelease: stub().resolves(), - generateNotes: stub().resolves(""), - addChannel: false, - prepare: stub().resolves(), - publish: stub().resolves(), - success: stub().resolves(), - fail: stub().resolves(), - }; - - const env = {}; - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - const envCi = (await td.replaceEsm("env-ci")).default; - td.when(envCi({ cwd, env })).thenReturn({ isCi: true, branch: "beta", isPr: false }); - const semanticRelease = (await import("../index.js")).default; - let { releases } = await semanticRelease(options, { - cwd, - env, - stdout: { write: () => {} }, - stderr: { write: () => {} }, - }); - - t.is(releases.length, 1); - t.is(releases[0].version, "1.1.0-beta.1"); - t.is(releases[0].gitTag, "v1.1.0-beta.1"); - - await gitCommits(["fix: a fix"], { cwd }); - ({ releases } = await semanticRelease(options, { - cwd, - env, - stdout: { write: () => {} }, - stderr: { write: () => {} }, - })); - - t.is(releases.length, 1); - t.is(releases[0].version, "1.1.0-beta.2"); - t.is(releases[0].gitTag, "v1.1.0-beta.2"); -}); - -test.serial("Do not add pre-releases to a different channel", async (t) => { - const { cwd, repositoryUrl } = await gitRepo(true); - await gitCommits(["feat: initial release"], { cwd }); - await gitTagVersion("v1.0.0", undefined, { cwd }); - await gitAddNote(JSON.stringify({ channels: [null, "beta"] }), "v1.0.0", { cwd }); - await gitCheckout("beta", true, { cwd }); - await gitCommits(["feat: breaking change/n/nBREAKING CHANGE: break something"], { cwd }); - await gitTagVersion("v2.0.0-beta.1", undefined, { cwd }); - await gitAddNote(JSON.stringify({ channels: ["beta"] }), "v2.0.0-beta.1", { cwd }); - await gitCommits(["fix: a fix"], { cwd }); - await gitTagVersion("v2.0.0-beta.2", undefined, { cwd }); - await gitAddNote(JSON.stringify({ channels: ["beta"] }), "v2.0.0-beta.2", { cwd }); - await gitPush("origin", "beta", { cwd }); - await gitCheckout("master", false, { cwd }); - await merge("beta", { cwd }); - await gitPush("origin", "master", { cwd }); - - const verifyConditions = stub().resolves(); - const verifyRelease = stub().resolves(); - const generateNotes = stub().resolves("Release notes"); - const release1 = { name: "Release 1", url: "https://release1.com" }; - const addChannel = stub().resolves(release1); - const prepare = stub().resolves(); - const publish = stub().resolves(); - const success = stub().resolves(); - - const config = { - branches: [{ name: "master" }, { name: "beta", prerelease: "beta" }], - repositoryUrl, - tagFormat: `v\${version}`, - }; - - const options = { - ...config, - verifyConditions, - verifyRelease, - addChannel, - generateNotes, - prepare, - publish, - success, - }; - - const env = {}; - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - const envCi = (await td.replaceEsm("env-ci")).default; - td.when(envCi({ cwd, env })).thenReturn({ isCi: true, branch: "master", isPr: false }); - const semanticRelease = (await import("../index.js")).default; - t.truthy(await semanticRelease(options, { cwd, env, stdout: { write: () => {} }, stderr: { write: () => {} } })); - - t.is(addChannel.callCount, 0); -}); - -async function addChannelMacro(t, mergeFunction) { - const { cwd, repositoryUrl } = await gitRepo(true); - const commits = await gitCommits(["feat: initial release"], { cwd }); - await gitTagVersion("v1.0.0", undefined, { cwd }); - await gitAddNote(JSON.stringify({ channels: [null, "next"] }), "v1.0.0", { cwd }); - await gitCheckout("next", true, { cwd }); - commits.push(...(await gitCommits(["feat: breaking change/n/nBREAKING CHANGE: break something"], { cwd }))); - await gitTagVersion("v2.0.0", undefined, { cwd }); - await gitAddNote(JSON.stringify({ channels: ["next"] }), "v2.0.0", { cwd }); - - commits.push(...(await gitCommits(["fix: a fix"], { cwd }))); - await gitTagVersion("v2.0.1", undefined, { cwd }); - await gitAddNote(JSON.stringify({ channels: ["next"] }), "v2.0.1", { cwd }); - commits.push(...(await gitCommits(["feat: a feature"], { cwd }))); - await gitTagVersion("v2.1.0", undefined, { cwd }); - await gitAddNote(JSON.stringify({ channels: ["next"] }), "v2.1.0", { cwd }); - await gitPush("origin", "next", { cwd }); - await gitCheckout("master", false, { cwd }); - // Merge all commits but last one from next to master - await mergeFunction("next~1", { cwd }); - await gitPush("origin", "master", { cwd }); - - const notes = "Release notes"; - const verifyConditions = stub().resolves(); - const verifyRelease = stub().resolves(); - const generateNotes = stub().resolves(notes); - const release1 = { name: "Release 1", url: "https://release1.com" }; - const addChannel1 = stub().resolves(release1); - const addChannel2 = stub().resolves(); - const prepare = stub().resolves(); - const publish = stub().resolves(); - const success = stub().resolves(); - - const config = { - branches: [ - { name: "master", channel: "latest" }, - { name: "next", channel: "next" }, - ], - repositoryUrl, - tagFormat: `v\${version}`, - }; - const options = { - ...config, - verifyConditions, - verifyRelease, - addChannel: [addChannel1, addChannel2], - generateNotes, - prepare, - publish, - success, - }; - const nextRelease = { - name: "v2.0.1", - type: "patch", - version: "2.0.1", - channel: "latest", - gitTag: "v2.0.1", - gitHead: commits[2].hash, - }; - - const env = {}; - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - const envCi = (await td.replaceEsm("env-ci")).default; - td.when(envCi({ env, cwd })).thenReturn({ isCi: true, branch: "master", isPr: false }); - const semanticRelease = (await import("../index.js")).default; - const result = await semanticRelease(options, { cwd, env, stdout: { write: () => {} }, stderr: { write: () => {} } }); - - t.deepEqual(result.releases, [ - { ...nextRelease, ...release1, notes, pluginName: "[Function: functionStub]" }, - { ...nextRelease, notes, pluginName: "[Function: functionStub]" }, - ]); - - // Verify the tag has been created on the local and remote repo and reference - t.is(await gitTagHead(nextRelease.gitTag, { cwd }), nextRelease.gitHead); - t.is(await gitRemoteTagHead(repositoryUrl, nextRelease.gitTag, { cwd }), nextRelease.gitHead); -} - -addChannelMacro.title = (providedTitle) => `Add version to a channel after a merge (${providedTitle})`; - -test.serial("fast-forward", addChannelMacro, mergeFf); -test.serial("non fast-forward", addChannelMacro, merge); -test.serial("rebase", addChannelMacro, rebase); - -test.serial('Call all "success" plugins even if one errors out', async (t) => { - // Create a git repository, set the current working directory at the root of the repo - const { cwd, repositoryUrl } = await gitRepo(true); - // Add commits to the master branch - await gitCommits(["First"], { cwd }); - // Create the tag corresponding to version 1.0.0 - await gitTagVersion("v1.0.0", undefined, { cwd }); - // Add new commits to the master branch - await gitCommits(["Second"], { cwd }); - await gitPush(repositoryUrl, "master", { cwd }); - - const nextRelease = { - name: "v2.0.0", - type: "major", - version: "2.0.0", - gitHead: await getGitHead({ cwd }), - gitTag: "v2.0.0", - channel: null, - }; - const notes = "Release notes"; - const verifyConditions1 = stub().resolves(); - const verifyConditions2 = stub().resolves(); - const analyzeCommits = stub().resolves(nextRelease.type); - const generateNotes = stub().resolves(notes); - const release = { name: "Release", url: "https://release.com" }; - const publish = stub().resolves(release); - const success1 = stub().rejects(); - const success2 = stub().resolves(); - const config = { - branches: [{ name: "master" }], - repositoryUrl, - globalOpt: "global", - tagFormat: `v\${version}`, - }; - const options = { - ...config, - verifyConditions: [verifyConditions1, verifyConditions2], - analyzeCommits, - generateNotes, - addChannel: stub().resolves(), - prepare: stub().resolves(), - publish, - success: [success1, success2], - }; - - const env = {}; - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - const envCi = (await td.replaceEsm("env-ci")).default; - td.when(envCi({ cwd, env })).thenReturn({ isCi: true, branch: "master", isPr: false }); - const semanticRelease = (await import("../index.js")).default; - - await t.throwsAsync( - semanticRelease(options, { cwd, env, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer() }) - ); - - t.is(success1.callCount, 1); - t.deepEqual(success1.args[0][0], config); - t.deepEqual(success1.args[0][1].releases, [ - { ...nextRelease, ...release, notes, pluginName: "[Function: functionStub]" }, - ]); - - t.is(success2.callCount, 1); - t.deepEqual(success2.args[0][1].releases, [ - { ...nextRelease, ...release, notes, pluginName: "[Function: functionStub]" }, - ]); -}); - -test.serial('Log all "verifyConditions" errors', async (t) => { - // Create a git repository, set the current working directory at the root of the repo - const { cwd, repositoryUrl } = await gitRepo(true); - // Add commits to the master branch - await gitCommits(["First"], { cwd }); - await gitPush(repositoryUrl, "master", { cwd }); - - const error1 = new Error("error 1"); - const error2 = new SemanticReleaseError("error 2", "ERR2"); - const error3 = new SemanticReleaseError("error 3", "ERR3"); - const fail = stub().resolves(); - const config = { - branches: [{ name: "master" }], - repositoryUrl, - originalRepositoryURL: repositoryUrl, - tagFormat: `v\${version}`, - }; - const options = { - ...config, - plugins: false, - verifyConditions: [stub().rejects(new AggregateError([error1, error2])), stub().rejects(error3)], - fail, - }; - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); - const semanticRelease = (await import("../index.js")).default; - const errors = [ - ...( - await t.throwsAsync( - semanticRelease(options, { - cwd, - env: {}, - stdout: new WritableStreamBuffer(), - stderr: new WritableStreamBuffer(), - }) - ) - ).errors, - ]; - - t.deepEqual(sortBy(errors, ["message"]), sortBy([error1, error2, error3], ["message"])); - t.true(t.context.error.calledWith("An error occurred while running semantic-release: %O", error1)); - t.true(t.context.error.calledWith("ERR2 error 2")); - t.true(t.context.error.calledWith("ERR3 error 3")); - t.true(t.context.error.calledAfter(t.context.log)); - t.is(fail.callCount, 1); - t.deepEqual(fail.args[0][0], config); - t.deepEqual(fail.args[0][1].options, options); - t.deepEqual(fail.args[0][1].logger, t.context.logger); - t.deepEqual(fail.args[0][1].errors, [error2, error3]); -}); - -test.serial('Log all "verifyRelease" errors', async (t) => { - // Create a git repository, set the current working directory at the root of the repo - const { cwd, repositoryUrl } = await gitRepo(true); - // Add commits to the master branch - await gitCommits(["First"], { cwd }); - // Create the tag corresponding to version 1.0.0 - await gitTagVersion("v1.0.0", undefined, { cwd }); - // Add new commits to the master branch - await gitCommits(["Second"], { cwd }); - await gitPush(repositoryUrl, "master", { cwd }); - - const error1 = new SemanticReleaseError("error 1", "ERR1"); - const error2 = new SemanticReleaseError("error 2", "ERR2"); - const fail = stub().resolves(); - const config = { branches: [{ name: "master" }], repositoryUrl, tagFormat: `v\${version}` }; - const options = { - ...config, - verifyConditions: stub().resolves(), - analyzeCommits: stub().resolves("major"), - verifyRelease: [stub().rejects(error1), stub().rejects(error2)], - fail, - }; - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); - const semanticRelease = (await import("../index.js")).default; - const errors = [ - ...( - await t.throwsAsync( - semanticRelease(options, { - cwd, - env: {}, - stdout: new WritableStreamBuffer(), - stderr: new WritableStreamBuffer(), - }) - ) - ).errors, - ]; - - t.deepEqual(sortBy(errors, ["message"]), sortBy([error1, error2], ["message"])); - t.true(t.context.error.calledWith("ERR1 error 1")); - t.true(t.context.error.calledWith("ERR2 error 2")); - t.is(fail.callCount, 1); - t.deepEqual(fail.args[0][0], config); - t.deepEqual(fail.args[0][1].errors, [error1, error2]); -}); - -test.serial("Dry-run skips addChannel, prepare, publish and success", async (t) => { - const { cwd, repositoryUrl } = await gitRepo(true); - await gitCommits(["First"], { cwd }); - await gitTagVersion("v1.0.0", undefined, { cwd }); - await gitAddNote(JSON.stringify({ channels: [null, "next"] }), "v1.0.0", { cwd }); - await gitCommits(["Second"], { cwd }); - await gitTagVersion("v1.1.0", undefined, { cwd }); - await gitAddNote(JSON.stringify({ channels: ["next"] }), "v1.1.0", { cwd }); - - await gitPush(repositoryUrl, "master", { cwd }); - await gitCheckout("next", true, { cwd }); - await gitPush("origin", "next", { cwd }); - - const verifyConditions = stub().resolves(); - const analyzeCommits = stub().resolves("minor"); - const verifyRelease = stub().resolves(); - const generateNotes = stub().resolves(); - const addChannel = stub().resolves(); - const prepare = stub().resolves(); - const publish = stub().resolves(); - const success = stub().resolves(); - - const options = { - dryRun: true, - branches: ["master", "next"], - repositoryUrl, - verifyConditions, - analyzeCommits, - verifyRelease, - generateNotes, - addChannel, - prepare, - publish, - success, - }; - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); - const semanticRelease = (await import("../index.js")).default; - t.truthy( - await semanticRelease(options, { - cwd, - env: {}, - stdout: new WritableStreamBuffer(), - stderr: new WritableStreamBuffer(), - }) - ); - - t.not(t.context.warn.args[0][0], "This run was not triggered in a known CI environment, running in dry-run mode."); - t.is(verifyConditions.callCount, 1); - t.is(analyzeCommits.callCount, 1); - t.is(verifyRelease.callCount, 1); - t.is(generateNotes.callCount, 2); - t.is(addChannel.callCount, 0); - t.true( - t.context.warn.calledWith(`Skip step "addChannel" of plugin "[Function: ${addChannel.name}]" in dry-run mode`) - ); - t.is(prepare.callCount, 0); - t.true(t.context.warn.calledWith(`Skip step "prepare" of plugin "[Function: ${prepare.name}]" in dry-run mode`)); - t.is(publish.callCount, 0); - t.true(t.context.warn.calledWith(`Skip step "publish" of plugin "[Function: ${publish.name}]" in dry-run mode`)); - t.is(success.callCount, 0); - t.true(t.context.warn.calledWith(`Skip step "success" of plugin "[Function: ${success.name}]" in dry-run mode`)); -}); - -test.serial("Dry-run skips fail", async (t) => { - // Create a git repository, set the current working directory at the root of the repo - const { cwd, repositoryUrl } = await gitRepo(true); - // Add commits to the master branch - await gitCommits(["First"], { cwd }); - // Create the tag corresponding to version 1.0.0 - await gitTagVersion("v1.0.0", undefined, { cwd }); - // Add new commits to the master branch - await gitCommits(["Second"], { cwd }); - await gitPush(repositoryUrl, "master", { cwd }); - - const error1 = new SemanticReleaseError("error 1", "ERR1"); - const error2 = new SemanticReleaseError("error 2", "ERR2"); - const fail = stub().resolves(); - - const options = { - dryRun: true, - branches: ["master"], - repositoryUrl, - verifyConditions: [stub().rejects(error1), stub().rejects(error2)], - fail, - }; - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); - const semanticRelease = (await import("../index.js")).default; - const errors = [ - ...( - await t.throwsAsync( - semanticRelease(options, { - cwd, - env: {}, - stdout: new WritableStreamBuffer(), - stderr: new WritableStreamBuffer(), - }) - ) - ).errors, - ]; - - t.deepEqual(sortBy(errors, ["message"]), sortBy([error1, error2], ["message"])); - t.true(t.context.error.calledWith("ERR1 error 1")); - t.true(t.context.error.calledWith("ERR2 error 2")); - t.is(fail.callCount, 0); - t.true(t.context.warn.calledWith(`Skip step "fail" of plugin "[Function: ${fail.name}]" in dry-run mode`)); -}); - -test.serial('Force a dry-run if not on a CI and "noCi" is not explicitly set', async (t) => { - // Create a git repository, set the current working directory at the root of the repo - const { cwd, repositoryUrl } = await gitRepo(true); - // Add commits to the master branch - await gitCommits(["First"], { cwd }); - // Create the tag corresponding to version 1.0.0 - await gitTagVersion("v1.0.0", undefined, { cwd }); - // Add new commits to the master branch - await gitCommits(["Second"], { cwd }); - await gitPush(repositoryUrl, "master", { cwd }); - - const nextRelease = { - name: "v2.0.0", - type: "major", - version: "2.0.0", - gitHead: await getGitHead({ cwd }), - gitTag: "v2.0.0", - channel: undefined, - }; - const notes = "Release notes"; - - const verifyConditions = stub().resolves(); - const analyzeCommits = stub().resolves(nextRelease.type); - const verifyRelease = stub().resolves(); - const generateNotes = stub().resolves(notes); - const publish = stub().resolves(); - const success = stub().resolves(); - - const options = { - dryRun: false, - branches: ["master"], - repositoryUrl, - verifyConditions, - analyzeCommits, - verifyRelease, - generateNotes, - addChannel: stub().resolves(), - prepare: stub().resolves(), - publish, - success, - fail: stub().resolves(), - }; - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: false, branch: "master" })); - const semanticRelease = (await import("../index.js")).default; - t.truthy( - await semanticRelease(options, { - cwd, - env: {}, - stdout: new WritableStreamBuffer(), - stderr: new WritableStreamBuffer(), - }) - ); - - t.true(t.context.warn.calledWith("This run was not triggered in a known CI environment, running in dry-run mode.")); - t.is(verifyConditions.callCount, 1); - t.is(analyzeCommits.callCount, 1); - t.is(verifyRelease.callCount, 1); - t.is(generateNotes.callCount, 1); - t.is(publish.callCount, 0); - t.is(success.callCount, 0); -}); - -test.serial('Dry-run does not print changelog if "generateNotes" return "undefined"', async (t) => { - // Create a git repository, set the current working directory at the root of the repo - const { cwd, repositoryUrl } = await gitRepo(true); - // Add commits to the master branch - await gitCommits(["First"], { cwd }); - // Create the tag corresponding to version 1.0.0 - await gitTagVersion("v1.0.0", undefined, { cwd }); - // Add new commits to the master branch - await gitCommits(["Second"], { cwd }); - await gitPush(repositoryUrl, "master", { cwd }); - - const nextRelease = { type: "major", version: "2.0.0", gitHead: await getGitHead({ cwd }), gitTag: "v2.0.0" }; - const analyzeCommits = stub().resolves(nextRelease.type); - const generateNotes = stub().resolves(); - - const options = { - dryRun: true, - branches: ["master"], - repositoryUrl, - verifyConditions: false, - analyzeCommits, - verifyRelease: false, - generateNotes, - prepare: false, - publish: false, - success: false, - }; - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); - const semanticRelease = (await import("../index.js")).default; - t.truthy( - await semanticRelease(options, { - cwd, - env: {}, - stdout: new WritableStreamBuffer(), - stderr: new WritableStreamBuffer(), - }) - ); - - t.deepEqual(t.context.log.args[t.context.log.args.length - 1], ["Release note for version 2.0.0:"]); -}); - -test.serial('Allow local releases with "noCi" option', async (t) => { - // Create a git repository, set the current working directory at the root of the repo - const { cwd, repositoryUrl } = await gitRepo(true); - // Add commits to the master branch - await gitCommits(["First"], { cwd }); - // Create the tag corresponding to version 1.0.0 - await gitTagVersion("v1.0.0", undefined, { cwd }); - // Add new commits to the master branch - await gitCommits(["Second"], { cwd }); - await gitPush(repositoryUrl, "master", { cwd }); - - const nextRelease = { - name: "v2.0.0", - type: "major", - version: "2.0.0", - gitHead: await getGitHead({ cwd }), - gitTag: "v2.0.0", - channel: undefined, - }; - const notes = "Release notes"; - - const verifyConditions = stub().resolves(); - const analyzeCommits = stub().resolves(nextRelease.type); - const verifyRelease = stub().resolves(); - const generateNotes = stub().resolves(notes); - const publish = stub().resolves(); - const success = stub().resolves(); - - const options = { - noCi: true, - branches: ["master"], - repositoryUrl, - verifyConditions, - analyzeCommits, - verifyRelease, - generateNotes, - addChannel: stub().resolves(), - prepare: stub().resolves(), - publish, - success, - fail: stub().resolves(), - }; - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: false, branch: "master", isPr: false })); - const semanticRelease = (await import("../index.js")).default; - t.truthy( - await semanticRelease(options, { - cwd, - env: {}, - stdout: new WritableStreamBuffer(), - stderr: new WritableStreamBuffer(), - }) - ); - - t.not(t.context.log.args[0][0], "This run was not triggered in a known CI environment, running in dry-run mode."); - t.not( - t.context.log.args[0][0], - "This run was triggered by a pull request and therefore a new version won't be published." - ); - t.is(verifyConditions.callCount, 1); - t.is(analyzeCommits.callCount, 1); - t.is(verifyRelease.callCount, 1); - t.is(generateNotes.callCount, 1); - t.is(publish.callCount, 1); - t.is(success.callCount, 1); -}); - -test.serial( - 'Accept "undefined" value returned by "generateNotes" and "false" by "publish" and "addChannel"', - async (t) => { - const { cwd, repositoryUrl } = await gitRepo(true); - await gitCommits(["First"], { cwd }); - await gitTagVersion("v1.0.0", undefined, { cwd }); - await gitAddNote(JSON.stringify({ channels: [null, "next"] }), "v1.0.0", { cwd }); - await gitCommits(["Second"], { cwd }); - await gitTagVersion("v1.1.0", undefined, { cwd }); - await gitAddNote(JSON.stringify({ channels: ["next"] }), "v1.1.0", { cwd }); - await gitPush(repositoryUrl, "master", { cwd }); - await gitCheckout("next", true, { cwd }); - await gitPush("origin", "next", { cwd }); - await gitCheckout("master", false, { cwd }); - - const nextRelease = { - name: "v1.2.0", - type: "minor", - version: "1.2.0", - gitHead: await getGitHead({ cwd }), - gitTag: "v1.2.0", - channel: null, - }; - const analyzeCommits = stub().resolves(nextRelease.type); - const verifyRelease = stub().resolves(); - const generateNotes1 = stub().resolves(); - const notes2 = "Release notes 2"; - const generateNotes2 = stub().resolves(notes2); - const publish = stub().resolves(false); - const addChannel = stub().resolves(false); - const success = stub().resolves(); - - const options = { - branches: ["master", "next"], - repositoryUrl, - verifyConditions: stub().resolves(), - analyzeCommits, - verifyRelease, - generateNotes: [generateNotes1, generateNotes2], - addChannel, - prepare: stub().resolves(), - publish, - success, - fail: stub().resolves(), - }; - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); - const semanticRelease = (await import("../index.js")).default; - t.truthy( - await semanticRelease(options, { - cwd, - env: {}, - stdout: new WritableStreamBuffer(), - stderr: new WritableStreamBuffer(), - }) - ); - - t.is(analyzeCommits.callCount, 1); - t.is(verifyRelease.callCount, 1); - t.is(generateNotes1.callCount, 2); - t.is(generateNotes2.callCount, 2); - t.is(addChannel.callCount, 1); - t.is(publish.callCount, 1); - t.is(success.callCount, 2); - t.deepEqual(publish.args[0][1].nextRelease, { ...nextRelease, notes: notes2 }); - t.deepEqual(success.args[0][1].releases, [{ pluginName: "[Function: functionStub]" }]); - t.deepEqual(success.args[1][1].releases, [{ pluginName: "[Function: functionStub]" }]); - } -); - -test.serial("Returns false if triggered by a PR", async (t) => { - // Create a git repository, set the current working directory at the root of the repo - const { cwd, repositoryUrl } = await gitRepo(true); - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", prBranch: "patch-1", isPr: true })); - const semanticRelease = (await import("../index.js")).default; - - t.false( - await semanticRelease( - { cwd, repositoryUrl }, - { cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer() } - ) - ); - t.is( - t.context.log.args[t.context.log.args.length - 1][0], - "This run was triggered by a pull request and therefore a new version won't be published." - ); -}); - -test.serial( - 'Throws "EINVALIDNEXTVERSION" if next release is out of range of the current maintenance branch', - async (t) => { - const { cwd, repositoryUrl } = await gitRepo(true); - await gitCommits(["feat: initial commit"], { cwd }); - await gitTagVersion("v1.0.0", undefined, { cwd }); - await gitAddNote(JSON.stringify({ channels: [null, "1.x"] }), "v1.0.0", { cwd }); - await gitCheckout("1.x", true, { cwd }); - await gitPush("origin", "1.x", { cwd }); - await gitCheckout("master", false, { cwd }); - await gitCommits(["feat: new feature on master"], { cwd }); - await gitTagVersion("v1.1.0", undefined, { cwd }); - await gitCheckout("1.x", false, { cwd }); - await gitCommits(["feat: feature on maintenance version 1.x"], { cwd }); - await gitPush("origin", "master", { cwd }); - - const verifyConditions = stub().resolves(); - const verifyRelease = stub().resolves(); - const addChannel = stub().resolves(); - const prepare = stub().resolves(); - const publish = stub().resolves(); - const success = stub().resolves(); - - const config = { - branches: [{ name: "1.x" }, { name: "master" }], - repositoryUrl, - tagFormat: `v\${version}`, - }; - const options = { - ...config, - verifyConditions, - verifyRelease, - addChannel, - prepare, - publish, - success, - }; - - const env = {}; - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - const envCi = (await td.replaceEsm("env-ci")).default; - td.when(envCi({ cwd, env })).thenReturn({ isCi: true, branch: "1.x", isPr: false }); - const semanticRelease = (await import("../index.js")).default; - - const error = await t.throwsAsync( - semanticRelease(options, { cwd, env, stdout: { write: () => {} }, stderr: { write: () => {} } }) - ); - - t.is(error.code, "EINVALIDNEXTVERSION"); - t.is(error.name, "SemanticReleaseError"); - t.is(error.message, "The release `1.1.0` on branch `1.x` cannot be published as it is out of range."); - t.regex(error.details, /A valid branch could be `master`./); - } -); - -test.serial('Throws "EINVALIDNEXTVERSION" if next release is out of range of the current release branch', async (t) => { - const { cwd, repositoryUrl } = await gitRepo(true); - await gitCommits(["feat: initial commit"], { cwd }); - await gitTagVersion("v1.0.0", undefined, { cwd }); - await gitCheckout("next", true, { cwd }); - await gitCommits(["feat: new feature on next"], { cwd }); - await gitTagVersion("v1.1.0", undefined, { cwd }); - await gitAddNote(JSON.stringify({ channels: ["next"] }), "v1.1.0", { cwd }); - await gitPush("origin", "next", { cwd }); - await gitCheckout("next-major", true, { cwd }); - await gitPush("origin", "next-major", { cwd }); - await gitCheckout("master", false, { cwd }); - await gitCommits(["feat: new feature on master", "fix: new fix on master"], { cwd }); - await gitPush("origin", "master", { cwd }); - - const verifyConditions = stub().resolves(); - const verifyRelease = stub().resolves(); - const addChannel = stub().resolves(); - const prepare = stub().resolves(); - const publish = stub().resolves(); - const success = stub().resolves(); - - const config = { - branches: [{ name: "master" }, { name: "next" }, { name: "next-major" }], - repositoryUrl, - tagFormat: `v\${version}`, - }; - const options = { - ...config, - verifyConditions, - verifyRelease, - addChannel, - prepare, - publish, - success, - }; - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); - const semanticRelease = (await import("../index.js")).default; - - const error = await t.throwsAsync( - semanticRelease(options, { cwd, env: {}, stdout: { write: () => {} }, stderr: { write: () => {} } }) - ); - - t.is(error.code, "EINVALIDNEXTVERSION"); - t.is(error.name, "SemanticReleaseError"); - t.is(error.message, "The release `1.1.0` on branch `master` cannot be published as it is out of range."); - t.regex(error.details, /A valid branch could be `next` or `next-major`./); -}); - -test.serial('Throws "EINVALIDMAINTENANCEMERGE" if merge an out of range release in a maintenance branch', async (t) => { - const { cwd, repositoryUrl } = await gitRepo(true); - await gitCommits(["First"], { cwd }); - await gitTagVersion("v1.0.0", undefined, { cwd }); - await gitAddNote(JSON.stringify({ channels: [null, "1.1.x"] }), "v1.0.0", { cwd }); - await gitCommits(["Second"], { cwd }); - await gitTagVersion("v1.1.0", undefined, { cwd }); - await gitAddNote(JSON.stringify({ channels: [null, "1.1.x"] }), "v1.1.0", { cwd }); - await gitCheckout("1.1.x", "master", { cwd }); - await gitPush("origin", "1.1.x", { cwd }); - await gitCheckout("master", false, { cwd }); - await gitCommits(["Third"], { cwd }); - await gitTagVersion("v1.1.1", undefined, { cwd }); - await gitCommits(["Fourth"], { cwd }); - await gitTagVersion("v1.2.0", undefined, { cwd }); - await gitPush("origin", "master", { cwd }); - await gitCheckout("1.1.x", false, { cwd }); - await merge("master", { cwd }); - await gitPush("origin", "1.1.x", { cwd }); - - const notes = "Release notes"; - const verifyConditions = stub().resolves(); - const analyzeCommits = stub().resolves(); - const verifyRelease = stub().resolves(); - const generateNotes = stub().resolves(notes); - const addChannel = stub().resolves(); - const prepare = stub().resolves(); - const publish = stub().resolves(); - const success = stub().resolves(); - const fail = stub().resolves(); - - const config = { branches: [{ name: "master" }, { name: "1.1.x" }], repositoryUrl, tagFormat: `v\${version}` }; - const options = { - ...config, - verifyConditions, - analyzeCommits, - verifyRelease, - addChannel, - generateNotes, - prepare, - publish, - success, - fail, - }; - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "1.1.x", isPr: false })); - const semanticRelease = (await import("../index.js")).default; - const errors = [ - ...( - await t.throwsAsync( - semanticRelease(options, { cwd, env: {}, stdout: { write: () => {} }, stderr: { write: () => {} } }) - ) - ).errors, - ]; - - t.is(addChannel.callCount, 0); - - t.is(publish.callCount, 0); - - t.is(success.callCount, 0); - - t.is(fail.callCount, 1); - t.deepEqual(fail.args[0][1].errors, errors); - - t.is(errors[0].code, "EINVALIDMAINTENANCEMERGE"); - t.is(errors[0].name, "SemanticReleaseError"); - t.truthy(errors[0].message); - t.truthy(errors[0].details); -}); - -test.serial("Returns false value if triggered on an outdated clone", async (t) => { - // Create a git repository, set the current working directory at the root of the repo - let { cwd, repositoryUrl } = await gitRepo(true); - const repoDir = cwd; - // Add commits to the master branch - await gitCommits(["First"], { cwd }); - await gitCommits(["Second"], { cwd }); - await gitPush(repositoryUrl, "master", { cwd }); - cwd = await gitShallowClone(repositoryUrl); - await gitCommits(["Third"], { cwd }); - await gitPush(repositoryUrl, "master", { cwd }); - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); - const semanticRelease = (await import("../index.js")).default; - - t.false( - await semanticRelease( - { repositoryUrl }, - { cwd: repoDir, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer() } - ) - ); - t.deepEqual(t.context.log.args[t.context.log.args.length - 1], [ - "The local branch master is behind the remote one, therefore a new version won't be published.", - ]); -}); - -test.serial("Returns false if not running from the configured branch", async (t) => { - // Create a git repository, set the current working directory at the root of the repo - const { cwd, repositoryUrl } = await gitRepo(true); - const options = { - branches: ["master"], - repositoryUrl, - verifyConditions: stub().resolves(), - analyzeCommits: stub().resolves(), - verifyRelease: stub().resolves(), - generateNotes: stub().resolves(), - addChannel: stub().resolves(), - prepare: stub().resolves(), - publish: stub().resolves(), - success: stub().resolves(), - fail: stub().resolves(), - }; - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "other-branch", isPr: false })); - const semanticRelease = (await import("../index.js")).default; - - t.false( - await semanticRelease(options, { - cwd, - env: {}, - stdout: new WritableStreamBuffer(), - stderr: new WritableStreamBuffer(), - }) - ); - t.is( - t.context.log.args[1][0], - "This test run was triggered on the branch other-branch, while semantic-release is configured to only publish from master, therefore a new version won’t be published." - ); -}); - -test.serial("Returns false if there is no relevant changes", async (t) => { - // Create a git repository, set the current working directory at the root of the repo - const { cwd, repositoryUrl } = await gitRepo(true); - // Add commits to the master branch - await gitCommits(["First"], { cwd }); - await gitPush(repositoryUrl, "master", { cwd }); - - const analyzeCommits = stub().resolves(); - const verifyRelease = stub().resolves(); - const generateNotes = stub().resolves(); - const publish = stub().resolves(); - - const options = { - branches: ["master"], - repositoryUrl, - verifyConditions: [stub().resolves()], - analyzeCommits, - verifyRelease, - generateNotes, - addChannel: stub().resolves(), - prepare: stub().resolves(), - publish, - success: stub().resolves(), - fail: stub().resolves(), - }; - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); - const semanticRelease = (await import("../index.js")).default; - - t.false( - await semanticRelease(options, { - cwd, - env: {}, - stdout: new WritableStreamBuffer(), - stderr: new WritableStreamBuffer(), - }) - ); - t.is(analyzeCommits.callCount, 1); - t.is(verifyRelease.callCount, 0); - t.is(generateNotes.callCount, 0); - t.is(publish.callCount, 0); - t.is( - t.context.log.args[t.context.log.args.length - 1][0], - "There are no relevant changes, so no new version is released." - ); -}); - -test.serial("Exclude commits with [skip release] or [release skip] from analysis", async (t) => { - // Create a git repository, set the current working directory at the root of the repo - const { cwd, repositoryUrl } = await gitRepo(true); - // Add commits to the master branch - const commits = await gitCommits( - [ - "Test commit", - "Test commit [skip release]", - "Test commit [release skip]", - "Test commit [Release Skip]", - "Test commit [Skip Release]", - "Test commit [skip release]", - "Test commit\n\n commit body\n[skip release]", - "Test commit\n\n commit body\n[release skip]", - ], - { cwd } - ); - await gitPush(repositoryUrl, "master", { cwd }); - const analyzeCommits = stub().resolves(); - const config = { branches: ["master"], repositoryUrl, globalOpt: "global" }; - const options = { - ...config, - verifyConditions: [stub().resolves(), stub().resolves()], - analyzeCommits, - verifyRelease: stub().resolves(), - generateNotes: stub().resolves(), - addChannel: stub().resolves(), - prepare: stub().resolves(), - publish: stub().resolves(), - success: stub().resolves(), - fail: stub().resolves(), - }; - - const env = {}; - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - const envCi = (await td.replaceEsm("env-ci")).default; - td.when(envCi({ env, cwd })).thenReturn({ isCi: true, branch: "master", isPr: false }); - const semanticRelease = (await import("../index.js")).default; - await semanticRelease(options, { - cwd, - env, - stdout: new WritableStreamBuffer(), - stderr: new WritableStreamBuffer(), - }); - - t.is(analyzeCommits.callCount, 1); - t.is(analyzeCommits.args[0][1].commits.length, 2); - t.deepEqual(analyzeCommits.args[0][1].commits[0], commits[commits.length - 1]); -}); - -test.serial('Log both plugins errors and errors thrown by "fail" plugin', async (t) => { - const { cwd, repositoryUrl } = await gitRepo(true); - const pluginError = new SemanticReleaseError("Plugin error", "ERR"); - const failError1 = new Error("Fail error 1"); - const failError2 = new Error("Fail error 2"); - - const options = { - branches: ["master"], - repositoryUrl, - verifyConditions: stub().rejects(pluginError), - fail: [stub().rejects(failError1), stub().rejects(failError2)], - }; - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); - const semanticRelease = (await import("../index.js")).default; - - await t.throwsAsync( - semanticRelease(options, { cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer() }) - ); - - t.is(t.context.error.args[t.context.error.args.length - 1][0], "ERR Plugin error"); - t.is(t.context.error.args[t.context.error.args.length - 3][1], failError1); - t.is(t.context.error.args[t.context.error.args.length - 2][1], failError2); -}); - -test.serial('Call "fail" only if a plugin returns a SemanticReleaseError', async (t) => { - const { cwd, repositoryUrl } = await gitRepo(true); - const pluginError = new Error("Plugin error"); - const fail = stub().resolves(); - - const options = { - branches: ["master"], - repositoryUrl, - verifyConditions: stub().rejects(pluginError), - fail, - }; - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); - const semanticRelease = (await import("../index.js")).default; - - await t.throwsAsync( - semanticRelease(options, { cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer() }) - ); - - t.true(fail.notCalled); - t.is(t.context.error.args[t.context.error.args.length - 1][1], pluginError); -}); - -test.serial( - "Throw SemanticReleaseError if repositoryUrl is not set and cannot be found from repo config", - async (t) => { - // Create a git repository, set the current working directory at the root of the repo - const { cwd } = await gitRepo(); - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); - const semanticRelease = (await import("../index.js")).default; - const errors = [ - ...( - await t.throwsAsync( - semanticRelease({}, { cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer() }) - ) - ).errors, - ]; - - // Verify error code and type - t.is(errors[0].code, "ENOREPOURL"); - t.is(errors[0].name, "SemanticReleaseError"); - t.truthy(errors[0].message); - t.truthy(errors[0].details); - } -); - -test.serial("Throw an Error if plugin returns an unexpected value", async (t) => { - // Create a git repository, set the current working directory at the root of the repo - const { cwd, repositoryUrl } = await gitRepo(true); - // Add commits to the master branch - await gitCommits(["First"], { cwd }); - // Create the tag corresponding to version 1.0.0 - await gitTagVersion("v1.0.0", undefined, { cwd }); - // Add new commits to the master branch - await gitCommits(["Second"], { cwd }); - await gitPush(repositoryUrl, "master", { cwd }); - - const verifyConditions = stub().resolves(); - const analyzeCommits = stub().resolves("string"); - - const options = { - branches: ["master"], - repositoryUrl, - verifyConditions: [verifyConditions], - analyzeCommits, - success: stub().resolves(), - fail: stub().resolves(), - }; - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); - const semanticRelease = (await import("../index.js")).default; - - let error; - try { - await semanticRelease(options, { - cwd, - env: {}, - stdout: new WritableStreamBuffer(), - stderr: new WritableStreamBuffer(), - }); - } catch (e) { - error = e; - } - t.is(error.code, "EANALYZECOMMITSOUTPUT"); - t.regex(error.details, /string/); -}); - -test.serial('Hide sensitive information passed to "fail" plugin', async (t) => { - const { cwd, repositoryUrl } = await gitRepo(true); - - const fail = stub().resolves(); - const env = { MY_TOKEN: "secret token" }; - const options = { - branch: "master", - repositoryUrl, - verifyConditions: stub().throws( - new SemanticReleaseError( - `Message: Exposing token ${env.MY_TOKEN}`, - "ERR", - `Details: Exposing token ${env.MY_TOKEN}` - ) - ), - success: stub().resolves(), - fail, - }; - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); - const semanticRelease = (await import("../index.js")).default; - await t.throwsAsync( - semanticRelease(options, { cwd, env, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer() }) - ); - - const error = fail.args[0][1].errors[0]; - - t.is(error.message, `Message: Exposing token ${SECRET_REPLACEMENT}`); - t.is(error.details, `Details: Exposing token ${SECRET_REPLACEMENT}`); - - Object.getOwnPropertyNames(error).forEach((prop) => { - if (isString(error[prop])) { - t.notRegex(error[prop], new RegExp(escapeRegExp(env.MY_TOKEN))); - } - }); -}); - -test.serial('Hide sensitive information passed to "success" plugin', async (t) => { - const { cwd, repositoryUrl } = await gitRepo(true); - await gitCommits(["feat: initial release"], { cwd }); - await gitTagVersion("v1.0.0", undefined, { cwd }); - await gitCommits(["feat: new feature"], { cwd }); - await gitPush(repositoryUrl, "master", { cwd }); - - const success = stub().resolves(); - const env = { MY_TOKEN: "secret token" }; - const options = { - branch: "master", - repositoryUrl, - verifyConditions: false, - verifyRelease: false, - prepare: false, - generateNotes: stub().resolves(`Exposing token ${env.MY_TOKEN}`), - publish: stub().resolves({ - name: `Name: Exposing token ${env.MY_TOKEN}`, - url: `URL: Exposing token ${env.MY_TOKEN}`, - }), - addChannel: false, - success, - fail: stub().resolves(), - }; - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); - const semanticRelease = (await import("../index.js")).default; - await semanticRelease(options, { cwd, env, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer() }); - - const release = success.args[0][1].releases[0]; - - t.is(release.name, `Name: Exposing token ${SECRET_REPLACEMENT}`); - t.is(release.url, `URL: Exposing token ${SECRET_REPLACEMENT}`); - - Object.getOwnPropertyNames(release).forEach((prop) => { - if (isString(release[prop])) { - t.notRegex(release[prop], new RegExp(escapeRegExp(env.MY_TOKEN))); - } - }); -}); - -test.serial("Get all commits including the ones not in the shallow clone", async (t) => { - let { cwd, repositoryUrl } = await gitRepo(true); - await gitTagVersion("v1.0.0", undefined, { cwd }); - await gitCommits(["First", "Second", "Third"], { cwd }); - await gitPush(repositoryUrl, "master", { cwd }); - - cwd = await gitShallowClone(repositoryUrl); - - const nextRelease = { - name: "v2.0.0", - type: "major", - version: "2.0.0", - gitHead: await getGitHead({ cwd }), - gitTag: "v2.0.0", - channel: undefined, - }; - const notes = "Release notes"; - const analyzeCommits = stub().resolves(nextRelease.type); - - const config = { branches: ["master"], repositoryUrl, globalOpt: "global" }; - const options = { - ...config, - verifyConditions: stub().resolves(), - analyzeCommits, - verifyRelease: stub().resolves(), - generateNotes: stub().resolves(notes), - prepare: stub().resolves(), - publish: stub().resolves(), - success: stub().resolves(), - fail: stub().resolves(), - }; - - await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); - await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); - const semanticRelease = (await import("../index.js")).default; - t.truthy( - await semanticRelease(options, { - cwd, - env: {}, - stdout: new WritableStreamBuffer(), - stderr: new WritableStreamBuffer(), - }) - ); - - t.is(analyzeCommits.args[0][1].commits.length, 3); -}); diff --git a/test/integration.test.js b/test/integration.test.js index b7faa91813..4d0e00e8eb 100644 --- a/test/integration.test.js +++ b/test/integration.test.js @@ -1,742 +1,1997 @@ -import path from "node:path"; -import { setTimeout } from "node:timers/promises"; import test from "ava"; +import { escapeRegExp, isString, omit, sortBy } from "lodash-es"; import * as td from "testdouble"; -import { escapeRegExp } from "lodash-es"; -import fsExtra from "fs-extra"; -import { execa } from "execa"; +import { spy, stub } from "sinon"; import { WritableStreamBuffer } from "stream-buffers"; - -import getAuthUrl from "../lib/get-git-auth-url.js"; -import { SECRET_REPLACEMENT } from "../lib/definitions/constants.js"; +import AggregateError from "aggregate-error"; +import SemanticReleaseError from "@semantic-release/error"; +import { COMMIT_EMAIL, COMMIT_NAME, SECRET_REPLACEMENT } from "../lib/definitions/constants.js"; import { + gitAddNote, gitCheckout, gitCommits, gitGetNote, - gitHead, + gitHead as getGitHead, gitPush, gitRemoteTagHead, gitRepo, + gitShallowClone, gitTagHead, + gitTagVersion, merge, + mergeFf, + rebase, } from "./helpers/git-utils.js"; -import { npmView } from "./helpers/npm-utils.js"; -import * as gitbox from "./helpers/gitbox.js"; -import * as mockServer from "./helpers/mockserver.js"; -import * as npmRegistry from "./helpers/npm-registry.js"; - -const { readJson, writeJson } = fsExtra; - -/* eslint camelcase: ["error", {properties: "never"}] */ - -// Environment variables used with semantic-release cli (similar to what a user would setup) -const { GITHUB_ACTION, GITHUB_ACTIONS, GITHUB_TOKEN, ...processEnvWithoutGitHubActionsVariables } = process.env; -let env; - -// Environment variables used only for the local npm command used to do verification -const npmTestEnv = { - ...processEnvWithoutGitHubActionsVariables, - ...npmRegistry.authEnv(), - npm_config_registry: npmRegistry.url, -}; - -const cli = path.resolve("./bin/semantic-release.js"); -const pluginError = path.resolve("./test/fixtures/plugin-error"); -const pluginInheritedError = path.resolve("./test/fixtures/plugin-error-inherited"); -const pluginLogEnv = path.resolve("./test/fixtures/plugin-log-env"); -const pluginEsmNamedExports = path.resolve("./test/fixtures/plugin-esm-named-exports"); - -test.before(async () => { - await Promise.all([gitbox.pull(), npmRegistry.pull(), mockServer.pull()]); - await Promise.all([gitbox.start(), npmRegistry.start(), mockServer.start()]); - - env = { - ...processEnvWithoutGitHubActionsVariables, - ...npmRegistry.authEnv(), - CI: "true", - GH_TOKEN: gitbox.gitCredential, - TRAVIS: "true", - TRAVIS_BRANCH: "master", - TRAVIS_PULL_REQUEST: "false", - GITHUB_API_URL: mockServer.url, +import pluginNoop from "./fixtures/plugin-noop.cjs"; + +test.beforeEach((t) => { + // Stub the logger functions + t.context.log = spy(); + t.context.error = spy(); + t.context.success = spy(); + t.context.warn = spy(); + t.context.logger = { + log: t.context.log, + error: t.context.error, + success: t.context.success, + warn: t.context.warn, + scope: () => t.context.logger, }; }); -test.after.always(async () => { - await Promise.all([gitbox.stop(), npmRegistry.stop(), mockServer.stop()]); +test.afterEach.always((t) => { + td.reset(); }); -test("Release patch, minor and major versions", async (t) => { - const packageName = "test-release"; - const owner = "git"; +test.serial("Plugins are called with expected values", async (t) => { // Create a git repository, set the current working directory at the root of the repo - t.log("Create git repository and package.json"); - const { cwd, repositoryUrl, authUrl } = await gitbox.createRepo(packageName); - // Create package.json in repository root - await writeJson(path.resolve(cwd, "package.json"), { - name: packageName, - version: "0.0.0-dev", - repository: { url: repositoryUrl }, - publishConfig: { registry: npmRegistry.url }, - release: { branches: ["master", "next"], success: false, fail: false }, - }); - // Create a npm-shrinkwrap.json file - await execa("npm", ["shrinkwrap"], { env: npmTestEnv, cwd, extendEnv: false }); - - /* No release */ - let verifyMock = await mockServer.mock( - `/repos/${owner}/${packageName}`, - { headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] }, - { body: { permissions: { push: true } }, method: "GET" } - ); - t.log("Commit a chore"); - await gitCommits(["chore: Init repository"], { cwd }); - t.log("$ semantic-release"); - let { stdout, exitCode } = await execa(cli, [], { env, cwd, extendEnv: false }); - t.regex(stdout, /There are no relevant changes, so no new version is released/); - t.is(exitCode, 0); - - /* Initial release */ - let version = "1.0.0"; - verifyMock = await mockServer.mock( - `/repos/${owner}/${packageName}`, - { headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] }, - { body: { permissions: { push: true } }, method: "GET" } - ); - let createReleaseMock = await mockServer.mock( - `/repos/${owner}/${packageName}/releases`, + const { cwd, repositoryUrl } = await gitRepo(true); + // Add commits to the master branch + let commits = await gitCommits(["First"], { cwd }); + // Create the tag corresponding to version 1.0.0 + await gitTagVersion("v1.0.0", undefined, { cwd }); + await gitAddNote(JSON.stringify({ channels: ["next"] }), "v1.0.0", { cwd }); + commits = (await gitCommits(["Second"], { cwd })).concat(commits); + await gitCheckout("next", true, { cwd }); + await gitPush(repositoryUrl, "next", { cwd }); + await gitCheckout("master", false, { cwd }); + await gitPush(repositoryUrl, "master", { cwd }); + + const lastRelease = { + version: "1.0.0", + gitHead: commits[commits.length - 1].hash, + gitTag: "v1.0.0", + name: "v1.0.0", + channels: ["next"], + }; + const nextRelease = { + name: "v1.1.0", + type: "minor", + version: "1.1.0", + gitHead: await getGitHead({ cwd }), + gitTag: "v1.1.0", + channel: null, + }; + const notes1 = "Release notes 1"; + const notes2 = "Release notes 2"; + const notes3 = "Release notes 3"; + const verifyConditions1 = stub().resolves(); + const verifyConditions2 = stub().resolves(); + const analyzeCommits = stub().resolves(nextRelease.type); + const verifyRelease = stub().resolves(); + const generateNotes1 = stub().resolves(notes1); + const generateNotes2 = stub().resolves(notes2); + const generateNotes3 = stub().resolves(notes3); + const release1 = { name: "Release 1", url: "https://release1.com" }; + const release2 = { name: "Release 2", url: "https://release2.com" }; + const addChannel = stub().resolves(release1); + const prepare = stub().resolves(); + const publish = stub().resolves(release2); + const success = stub().resolves(); + const env = {}; + const config = { + branches: [{ name: "master" }, { name: "next" }], + repositoryUrl, + originalRepositoryURL: repositoryUrl, + globalOpt: "global", + tagFormat: `v\${version}`, + }; + const branches = [ { - body: { tag_name: `v${version}`, name: `v${version}` }, - headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }], + channel: undefined, + name: "master", + range: ">=1.0.0", + accept: ["patch", "minor", "major"], + tags: [{ channels: ["next"], gitTag: "v1.0.0", version: "1.0.0" }], + type: "release", + main: true, }, - { body: { html_url: `release-url/${version}` } } - ); - - t.log("Commit a feature"); - await gitCommits(["feat: Initial commit"], { cwd }); - t.log("$ semantic-release"); - ({ stdout, exitCode } = await execa(cli, [], { env, cwd, extendEnv: false })); - t.regex(stdout, new RegExp(`Published GitHub release: release-url/${version}`)); - t.regex(stdout, new RegExp(`Publishing version ${version} to npm registry`)); - t.is(exitCode, 0); - - // Verify package.json and npm-shrinkwrap.json have been updated - t.is((await readJson(path.resolve(cwd, "package.json"))).version, version); - t.is((await readJson(path.resolve(cwd, "npm-shrinkwrap.json"))).version, version); - - // Retrieve the published package from the registry and check version and gitHead - let { - "dist-tags": { latest: releasedVersion }, - } = await npmView(packageName, npmTestEnv); - let head = await gitHead({ cwd }); - t.is(releasedVersion, version); - t.is(await gitTagHead(`v${version}`, { cwd }), head); - t.is(await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), head); - t.log(`+ released ${releasedVersion}`); - - await mockServer.verify(verifyMock); - await mockServer.verify(createReleaseMock); - - /* Patch release */ - version = "1.0.1"; - verifyMock = await mockServer.mock( - `/repos/${owner}/${packageName}`, - { headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] }, - { body: { permissions: { push: true } }, method: "GET" } - ); - createReleaseMock = await mockServer.mock( - `/repos/${owner}/${packageName}/releases`, { - body: { tag_name: `v${version}`, name: `v${version}` }, - headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }], + channel: "next", + name: "next", + range: ">=1.0.0", + accept: ["patch", "minor", "major"], + tags: [{ channels: ["next"], gitTag: "v1.0.0", version: "1.0.0" }], + type: "release", + main: false, }, - { body: { html_url: `release-url/${version}` } } - ); + ]; + const branch = branches[0]; + const options = { + ...config, + plugins: false, + verifyConditions: [verifyConditions1, verifyConditions2], + analyzeCommits, + verifyRelease, + addChannel, + generateNotes: [generateNotes1, generateNotes2, generateNotes3], + prepare, + publish: [publish, pluginNoop], + success, + }; + const envCiResults = { branch: "master", isCi: true, isPr: false }; - t.log("Commit a fix"); - await gitCommits(["fix: bar"], { cwd }); - t.log("$ semantic-release"); - ({ stdout, exitCode } = await execa(cli, [], { env, cwd, extendEnv: false })); - t.regex(stdout, new RegExp(`Published GitHub release: release-url/${version}`)); - t.regex(stdout, new RegExp(`Publishing version ${version} to npm registry`)); - t.is(exitCode, 0); - - // Verify package.json and npm-shrinkwrap.json have been updated - t.is((await readJson(path.resolve(cwd, "package.json"))).version, version); - t.is((await readJson(path.resolve(cwd, "npm-shrinkwrap.json"))).version, version); - - // Retrieve the published package from the registry and check version and gitHead - ({ - "dist-tags": { latest: releasedVersion }, - } = await npmView(packageName, npmTestEnv)); - head = await gitHead({ cwd }); - t.is(releasedVersion, version); - t.is(await gitTagHead(`v${version}`, { cwd }), head); - t.is(await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), head); - t.log(`+ released ${releasedVersion}`); - - await mockServer.verify(verifyMock); - await mockServer.verify(createReleaseMock); - - /* Minor release */ - version = "1.1.0"; - verifyMock = await mockServer.mock( - `/repos/${owner}/${packageName}`, - { headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] }, - { body: { permissions: { push: true } }, method: "GET" } - ); - createReleaseMock = await mockServer.mock( - `/repos/${owner}/${packageName}/releases`, + const releases = [ { - body: { tag_name: `v${version}`, name: `v${version}` }, - headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }], + ...omit(lastRelease, "channels"), + ...release1, + type: "major", + version: "1.0.0", + channel: null, + gitTag: "v1.0.0", + notes: `${notes1}\n\n${notes2}\n\n${notes3}`, + pluginName: "[Function: functionStub]", }, - { body: { html_url: `release-url/${version}` } } - ); - - t.log("Commit a feature"); - await gitCommits(["feat: baz"], { cwd }); - t.log("$ semantic-release"); - ({ stdout, exitCode } = await execa(cli, [], { env, cwd, extendEnv: false })); - t.regex(stdout, new RegExp(`Published GitHub release: release-url/${version}`)); - t.regex(stdout, new RegExp(`Publishing version ${version} to npm registry`)); - t.is(exitCode, 0); - - // Verify package.json and npm-shrinkwrap.json have been updated - t.is((await readJson(path.resolve(cwd, "package.json"))).version, version); - t.is((await readJson(path.resolve(cwd, "npm-shrinkwrap.json"))).version, version); - - // Retrieve the published package from the registry and check version and gitHead - ({ - "dist-tags": { latest: releasedVersion }, - } = await npmView(packageName, npmTestEnv)); - head = await gitHead({ cwd }); - t.is(releasedVersion, version); - t.is(await gitTagHead(`v${version}`, { cwd }), head); - t.is(await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), head); - t.log(`+ released ${releasedVersion}`); - - await mockServer.verify(verifyMock); - await mockServer.verify(createReleaseMock); - - /* Major release on next */ - version = "2.0.0"; - verifyMock = await mockServer.mock( - `/repos/${owner}/${packageName}`, - { headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] }, - { body: { permissions: { push: true } }, method: "GET" } - ); - createReleaseMock = await mockServer.mock( - `/repos/${owner}/${packageName}/releases`, { - body: { tag_name: `v${version}`, name: `v${version}` }, - headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }], + ...nextRelease, + ...release2, + notes: `${notes1}\n\n${notes2}\n\n${notes3}`, + pluginName: "[Function: functionStub]", }, - { body: { html_url: `release-url/${version}` } } - ); + { ...nextRelease, notes: `${notes1}\n\n${notes2}\n\n${notes3}`, pluginName: "[Function: noop]" }, + ]; - t.log("Commit a breaking change on next"); - await gitCheckout("next", true, { cwd }); - await gitPush("origin", "next", { cwd }); - await gitCommits(["feat: foo\n\n BREAKING CHANGE: bar"], { cwd }); - t.log("$ semantic-release"); - ({ stdout, exitCode } = await execa(cli, [], { env: { ...env, TRAVIS_BRANCH: "next" }, cwd, extendEnv: false })); - t.regex(stdout, new RegExp(`Published GitHub release: release-url/${version}`)); - t.regex(stdout, new RegExp(`Publishing version ${version} to npm registry`)); - t.is(exitCode, 0); - - // Verify package.json and npm-shrinkwrap.json have been updated - t.is((await readJson(path.resolve(cwd, "package.json"))).version, version); - t.is((await readJson(path.resolve(cwd, "npm-shrinkwrap.json"))).version, version); - - // Retrieve the published package from the registry and check version and gitHead - ({ - "dist-tags": { next: releasedVersion }, - } = await npmView(packageName, npmTestEnv)); - head = await gitHead({ cwd }); - t.is(releasedVersion, version); - t.is(await gitGetNote(`v${version}`, { cwd }), '{"channels":["next"]}'); - t.is(await gitTagHead(`v${version}`, { cwd }), head); - t.is(await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), head); - t.log(`+ released ${releasedVersion} on @next`); - - await mockServer.verify(verifyMock); - await mockServer.verify(createReleaseMock); - - /* Merge next into master */ - version = "2.0.0"; - const releaseId = 1; - verifyMock = await mockServer.mock( - `/repos/${owner}/${packageName}`, - { headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] }, - { body: { permissions: { push: true } }, method: "GET" } - ); - const getReleaseMock = await mockServer.mock( - `/repos/${owner}/${packageName}/releases/tags/v2.0.0`, - { headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] }, - { body: { id: releaseId }, method: "GET" } + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + const envCi = (await td.replaceEsm("env-ci")).default; + td.when(envCi({ env, cwd })).thenReturn(envCiResults); + const semanticRelease = (await import("../index.js")).default; + const result = await semanticRelease(options, { + cwd, + env, + stdout: new WritableStreamBuffer(), + stderr: new WritableStreamBuffer(), + }); + + t.is(verifyConditions1.callCount, 1); + t.deepEqual(verifyConditions1.args[0][0], config); + t.deepEqual(verifyConditions1.args[0][1].cwd, cwd); + t.deepEqual(verifyConditions1.args[0][1].options, options); + t.deepEqual(verifyConditions1.args[0][1].branch, branch); + t.deepEqual(verifyConditions1.args[0][1].branches, branches); + t.deepEqual(verifyConditions1.args[0][1].logger, t.context.logger); + t.deepEqual(verifyConditions1.args[0][1].envCi, envCiResults); + t.is(verifyConditions2.callCount, 1); + t.deepEqual(verifyConditions2.args[0][0], config); + t.deepEqual(verifyConditions2.args[0][1].cwd, cwd); + t.deepEqual(verifyConditions2.args[0][1].options, options); + t.deepEqual(verifyConditions2.args[0][1].branch, branch); + t.deepEqual(verifyConditions2.args[0][1].branches, branches); + t.deepEqual(verifyConditions2.args[0][1].logger, t.context.logger); + t.deepEqual(verifyConditions2.args[0][1].envCi, envCiResults); + + t.is(generateNotes1.callCount, 2); + t.is(generateNotes2.callCount, 2); + t.is(generateNotes3.callCount, 2); + + t.deepEqual(generateNotes1.args[0][0], config); + t.deepEqual(generateNotes1.args[0][1].options, options); + t.deepEqual(generateNotes1.args[0][1].branch, branch); + t.deepEqual(generateNotes1.args[0][1].branches, branches); + t.deepEqual(generateNotes1.args[0][1].logger, t.context.logger); + t.deepEqual(generateNotes1.args[0][1].lastRelease, {}); + t.deepEqual(generateNotes1.args[0][1].commits[0].hash, commits[1].hash); + t.deepEqual(generateNotes1.args[0][1].commits[0].message, commits[1].message); + t.deepEqual(generateNotes1.args[0][1].nextRelease, { + ...omit(lastRelease, "channels"), + type: "major", + version: "1.0.0", + channel: null, + gitTag: "v1.0.0", + name: "v1.0.0", + }); + t.deepEqual(generateNotes2.args[0][1].envCi, envCiResults); + + t.deepEqual(generateNotes2.args[0][0], config); + t.deepEqual(generateNotes2.args[0][1].options, options); + t.deepEqual(generateNotes2.args[0][1].branch, branch); + t.deepEqual(generateNotes2.args[0][1].branches, branches); + t.deepEqual(generateNotes2.args[0][1].logger, t.context.logger); + t.deepEqual(generateNotes2.args[0][1].lastRelease, {}); + t.deepEqual(generateNotes2.args[0][1].commits[0].hash, commits[1].hash); + t.deepEqual(generateNotes2.args[0][1].commits[0].message, commits[1].message); + t.deepEqual(generateNotes2.args[0][1].nextRelease, { + ...omit(lastRelease, "channels"), + type: "major", + version: "1.0.0", + channel: null, + gitTag: "v1.0.0", + name: "v1.0.0", + notes: notes1, + }); + t.deepEqual(generateNotes2.args[0][1].envCi, envCiResults); + + t.deepEqual(generateNotes3.args[0][0], config); + t.deepEqual(generateNotes3.args[0][1].options, options); + t.deepEqual(generateNotes3.args[0][1].branch, branch); + t.deepEqual(generateNotes3.args[0][1].branches, branches); + t.deepEqual(generateNotes3.args[0][1].logger, t.context.logger); + t.deepEqual(generateNotes3.args[0][1].lastRelease, {}); + t.deepEqual(generateNotes3.args[0][1].commits[0].hash, commits[1].hash); + t.deepEqual(generateNotes3.args[0][1].commits[0].message, commits[1].message); + t.deepEqual(generateNotes3.args[0][1].nextRelease, { + ...omit(lastRelease, "channels"), + type: "major", + version: "1.0.0", + channel: null, + gitTag: "v1.0.0", + name: "v1.0.0", + notes: `${notes1}\n\n${notes2}`, + }); + t.deepEqual(generateNotes3.args[0][1].envCi, envCiResults); + + branch.tags.push({ + version: "1.0.0", + channel: null, + gitTag: "v1.0.0", + gitHead: commits[commits.length - 1].hash, + }); + + t.is(addChannel.callCount, 1); + t.deepEqual(addChannel.args[0][0], config); + t.deepEqual(addChannel.args[0][1].options, options); + t.deepEqual(addChannel.args[0][1].branch, branch); + t.deepEqual(addChannel.args[0][1].branches, branches); + t.deepEqual(addChannel.args[0][1].logger, t.context.logger); + t.deepEqual(addChannel.args[0][1].lastRelease, {}); + t.deepEqual(addChannel.args[0][1].currentRelease, { ...lastRelease, type: "major" }); + t.deepEqual(addChannel.args[0][1].nextRelease, { + ...omit(lastRelease, "channels"), + type: "major", + version: "1.0.0", + channel: null, + gitTag: "v1.0.0", + name: "v1.0.0", + notes: `${notes1}\n\n${notes2}\n\n${notes3}`, + }); + t.deepEqual(addChannel.args[0][1].commits[0].hash, commits[1].hash); + t.deepEqual(addChannel.args[0][1].commits[0].message, commits[1].message); + t.deepEqual(addChannel.args[0][1].envCi, envCiResults); + + t.is(analyzeCommits.callCount, 1); + t.deepEqual(analyzeCommits.args[0][0], config); + t.deepEqual(analyzeCommits.args[0][1].options, options); + t.deepEqual(analyzeCommits.args[0][1].branch, branch); + t.deepEqual(analyzeCommits.args[0][1].branches, branches); + t.deepEqual(analyzeCommits.args[0][1].logger, t.context.logger); + t.deepEqual(analyzeCommits.args[0][1].lastRelease, lastRelease); + t.deepEqual(analyzeCommits.args[0][1].commits[0].hash, commits[0].hash); + t.deepEqual(analyzeCommits.args[0][1].commits[0].message, commits[0].message); + t.deepEqual(analyzeCommits.args[0][1].envCi, envCiResults); + + t.is(verifyRelease.callCount, 1); + t.deepEqual(verifyRelease.args[0][0], config); + t.deepEqual(verifyRelease.args[0][1].options, options); + t.deepEqual(verifyRelease.args[0][1].branch, branch); + t.deepEqual(verifyRelease.args[0][1].branches, branches); + t.deepEqual(verifyRelease.args[0][1].logger, t.context.logger); + t.deepEqual(verifyRelease.args[0][1].lastRelease, lastRelease); + t.deepEqual(verifyRelease.args[0][1].commits[0].hash, commits[0].hash); + t.deepEqual(verifyRelease.args[0][1].commits[0].message, commits[0].message); + t.deepEqual(verifyRelease.args[0][1].nextRelease, nextRelease); + t.deepEqual(verifyRelease.args[0][1].envCi, envCiResults); + + t.deepEqual(generateNotes1.args[1][0], config); + t.deepEqual(generateNotes1.args[1][1].options, options); + t.deepEqual(generateNotes1.args[1][1].branch, branch); + t.deepEqual(generateNotes1.args[1][1].branches, branches); + t.deepEqual(generateNotes1.args[1][1].logger, t.context.logger); + t.deepEqual(generateNotes1.args[1][1].lastRelease, lastRelease); + t.deepEqual(generateNotes1.args[1][1].commits[0].hash, commits[0].hash); + t.deepEqual(generateNotes1.args[1][1].commits[0].message, commits[0].message); + t.deepEqual(generateNotes1.args[1][1].nextRelease, nextRelease); + t.deepEqual(generateNotes1.args[1][1].envCi, envCiResults); + + t.deepEqual(generateNotes2.args[1][0], config); + t.deepEqual(generateNotes2.args[1][1].options, options); + t.deepEqual(generateNotes2.args[1][1].branch, branch); + t.deepEqual(generateNotes2.args[1][1].branches, branches); + t.deepEqual(generateNotes2.args[1][1].logger, t.context.logger); + t.deepEqual(generateNotes2.args[1][1].lastRelease, lastRelease); + t.deepEqual(generateNotes2.args[1][1].commits[0].hash, commits[0].hash); + t.deepEqual(generateNotes2.args[1][1].commits[0].message, commits[0].message); + t.deepEqual(generateNotes2.args[1][1].nextRelease, { ...nextRelease, notes: notes1 }); + t.deepEqual(generateNotes2.args[1][1].envCi, envCiResults); + + t.deepEqual(generateNotes3.args[1][0], config); + t.deepEqual(generateNotes3.args[1][1].options, options); + t.deepEqual(generateNotes3.args[1][1].branch, branch); + t.deepEqual(generateNotes3.args[1][1].branches, branches); + t.deepEqual(generateNotes3.args[1][1].logger, t.context.logger); + t.deepEqual(generateNotes3.args[1][1].lastRelease, lastRelease); + t.deepEqual(generateNotes3.args[1][1].commits[0].hash, commits[0].hash); + t.deepEqual(generateNotes3.args[1][1].commits[0].message, commits[0].message); + t.deepEqual(generateNotes3.args[1][1].nextRelease, { ...nextRelease, notes: `${notes1}\n\n${notes2}` }); + t.deepEqual(generateNotes3.args[1][1].envCi, envCiResults); + + t.is(prepare.callCount, 1); + t.deepEqual(prepare.args[0][0], config); + t.deepEqual(prepare.args[0][1].options, options); + t.deepEqual(prepare.args[0][1].branch, branch); + t.deepEqual(prepare.args[0][1].branches, branches); + t.deepEqual(prepare.args[0][1].logger, t.context.logger); + t.deepEqual(prepare.args[0][1].lastRelease, lastRelease); + t.deepEqual(prepare.args[0][1].commits[0].hash, commits[0].hash); + t.deepEqual(prepare.args[0][1].commits[0].message, commits[0].message); + t.deepEqual(prepare.args[0][1].nextRelease, { ...nextRelease, notes: `${notes1}\n\n${notes2}\n\n${notes3}` }); + t.deepEqual(prepare.args[0][1].envCi, envCiResults); + + t.is(publish.callCount, 1); + t.deepEqual(publish.args[0][0], config); + t.deepEqual(publish.args[0][1].options, options); + t.deepEqual(publish.args[0][1].branch, branch); + t.deepEqual(publish.args[0][1].branches, branches); + t.deepEqual(publish.args[0][1].logger, t.context.logger); + t.deepEqual(publish.args[0][1].lastRelease, lastRelease); + t.deepEqual(publish.args[0][1].commits[0].hash, commits[0].hash); + t.deepEqual(publish.args[0][1].commits[0].message, commits[0].message); + t.deepEqual(publish.args[0][1].nextRelease, { ...nextRelease, notes: `${notes1}\n\n${notes2}\n\n${notes3}` }); + t.deepEqual(publish.args[0][1].envCi, envCiResults); + + t.is(success.callCount, 2); + t.deepEqual(success.args[0][0], config); + t.deepEqual(success.args[0][1].options, options); + t.deepEqual(success.args[0][1].branch, branch); + t.deepEqual(success.args[0][1].branches, branches); + t.deepEqual(success.args[0][1].logger, t.context.logger); + t.deepEqual(success.args[0][1].lastRelease, {}); + t.deepEqual(success.args[0][1].commits[0].hash, commits[1].hash); + t.deepEqual(success.args[0][1].commits[0].message, commits[1].message); + t.deepEqual(success.args[0][1].nextRelease, { + ...omit(lastRelease, "channels"), + type: "major", + version: "1.0.0", + channel: null, + gitTag: "v1.0.0", + name: "v1.0.0", + notes: `${notes1}\n\n${notes2}\n\n${notes3}`, + }); + t.deepEqual(success.args[0][1].releases, [releases[0]]); + t.deepEqual(success.args[0][1].envCi, envCiResults); + + t.deepEqual(success.args[1][0], config); + t.deepEqual(success.args[1][1].options, options); + t.deepEqual(success.args[1][1].branch, branch); + t.deepEqual(success.args[1][1].branches, branches); + t.deepEqual(success.args[1][1].logger, t.context.logger); + t.deepEqual(success.args[1][1].lastRelease, lastRelease); + t.deepEqual(success.args[1][1].commits[0].hash, commits[0].hash); + t.deepEqual(success.args[1][1].commits[0].message, commits[0].message); + t.deepEqual(success.args[1][1].nextRelease, { ...nextRelease, notes: `${notes1}\n\n${notes2}\n\n${notes3}` }); + t.deepEqual(success.args[1][1].releases, [releases[1], releases[2]]); + t.deepEqual(success.args[1][1].envCi, envCiResults); + + t.deepEqual(result, { + lastRelease, + commits: [{ ...commits[0], gitTags: "(HEAD -> master, next)" }], + nextRelease: { ...nextRelease, notes: `${notes1}\n\n${notes2}\n\n${notes3}` }, + releases, + }); + + // Verify the tag has been created on the local and remote repo and reference the gitHead + t.is(await gitTagHead(nextRelease.gitTag, { cwd }), nextRelease.gitHead); + t.is(await gitRemoteTagHead(repositoryUrl, nextRelease.gitTag, { cwd }), nextRelease.gitHead); + + // Verify the author/commiter name and email have been set + t.is(env.GIT_AUTHOR_NAME, COMMIT_NAME); + t.is(env.GIT_AUTHOR_EMAIL, COMMIT_EMAIL); + t.is(env.GIT_COMMITTER_NAME, COMMIT_NAME); + t.is(env.GIT_COMMITTER_EMAIL, COMMIT_EMAIL); +}); + +test.serial("Use custom tag format", async (t) => { + const { cwd, repositoryUrl } = await gitRepo(true); + await gitCommits(["First"], { cwd }); + await gitTagVersion("test-1.0.0", undefined, { cwd }); + await gitCommits(["Second"], { cwd }); + await gitPush(repositoryUrl, "master", { cwd }); + + const nextRelease = { + name: "test-2.0.0", + type: "major", + version: "2.0.0", + gitHead: await getGitHead({ cwd }), + gitTag: "test-2.0.0", + }; + const notes = "Release notes"; + const config = { branches: "master", repositoryUrl, globalOpt: "global", tagFormat: `test-\${version}` }; + const options = { + ...config, + verifyConditions: stub().resolves(), + analyzeCommits: stub().resolves(nextRelease.type), + verifyRelease: stub().resolves(), + generateNotes: stub().resolves(notes), + addChannel: stub().resolves(), + prepare: stub().resolves(), + publish: stub().resolves(), + success: stub().resolves(), + fail: stub().resolves(), + }; + + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); + const semanticRelease = (await import("../index.js")).default; + t.truthy( + await semanticRelease(options, { + cwd, + env: {}, + stdout: new WritableStreamBuffer(), + stderr: new WritableStreamBuffer(), + }) ); - const updateReleaseMock = await mockServer.mock( - `/repos/${owner}/${packageName}/releases/${releaseId}`, - { - body: { name: `v${version}`, prerelease: false }, - headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }], - }, - { body: { html_url: `release-url/${version}` }, method: "PATCH" } + + // Verify the tag has been created on the local and remote repo and reference the gitHead + t.is(await gitTagHead(nextRelease.gitTag, { cwd }), nextRelease.gitHead); + t.is(await gitRemoteTagHead(repositoryUrl, nextRelease.gitTag, { cwd }), nextRelease.gitHead); +}); + +test.serial("Use new gitHead, and recreate release notes if a prepare plugin create a commit", async (t) => { + // Create a git repository, set the current working directory at the root of the repo + const { cwd, repositoryUrl } = await gitRepo(true); + // Add commits to the master branch + let commits = await gitCommits(["First"], { cwd }); + // Create the tag corresponding to version 1.0.0 + await gitTagVersion("v1.0.0", undefined, { cwd }); + // Add new commits to the master branch + commits = (await gitCommits(["Second"], { cwd })).concat(commits); + await gitPush(repositoryUrl, "master", { cwd }); + + const nextRelease = { + name: "v2.0.0", + type: "major", + version: "2.0.0", + gitHead: await getGitHead({ cwd }), + gitTag: "v2.0.0", + channel: null, + }; + const notes = "Release notes"; + + const generateNotes = stub().resolves(notes); + const prepare1 = stub().callsFake(async () => { + commits = (await gitCommits(["Third"], { cwd })).concat(commits); + }); + const prepare2 = stub().resolves(); + const publish = stub().resolves(); + const options = { + branches: ["master"], + repositoryUrl, + verifyConditions: stub().resolves(), + analyzeCommits: stub().resolves(nextRelease.type), + verifyRelease: stub().resolves(), + generateNotes, + addChannel: stub().resolves(), + prepare: [prepare1, prepare2], + publish, + success: stub().resolves(), + fail: stub().resolves(), + }; + + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); + const semanticRelease = (await import("../index.js")).default; + + t.truthy( + await semanticRelease(options, { + cwd, + env: {}, + stdout: new WritableStreamBuffer(), + stderr: new WritableStreamBuffer(), + }) ); - t.log("Merge next into master"); + t.is(generateNotes.callCount, 2); + t.deepEqual(generateNotes.args[0][1].nextRelease, nextRelease); + t.is(prepare1.callCount, 1); + t.deepEqual(prepare1.args[0][1].nextRelease, { ...nextRelease, notes }); + + nextRelease.gitHead = await getGitHead({ cwd }); + + t.deepEqual(generateNotes.args[1][1].nextRelease, { ...nextRelease, notes }); + t.is(prepare2.callCount, 1); + t.deepEqual(prepare2.args[0][1].nextRelease, { ...nextRelease, notes }); + + t.is(publish.callCount, 1); + t.deepEqual(publish.args[0][1].nextRelease, { ...nextRelease, notes }); + + // Verify the tag has been created on the local and remote repo and reference the last gitHead + t.is(await gitTagHead(nextRelease.gitTag, { cwd }), commits[0].hash); + t.is(await gitRemoteTagHead(repositoryUrl, nextRelease.gitTag, { cwd }), commits[0].hash); +}); + +test.serial("Make a new release when a commit is forward-ported to an upper branch", async (t) => { + const { cwd, repositoryUrl } = await gitRepo(true); + await gitCommits(["feat: initial release"], { cwd }); + await gitTagVersion("v1.0.0", undefined, { cwd }); + await gitAddNote(JSON.stringify({ channels: [null, "1.0.x"] }), "v1.0.0", { cwd }); + await gitCheckout("1.0.x", true, { cwd }); + await gitCommits(["fix: fix on maintenance version 1.0.x"], { cwd }); + await gitTagVersion("v1.0.1", undefined, { cwd }); + await gitAddNote(JSON.stringify({ channels: ["1.0.x"] }), "v1.0.1", { cwd }); + await gitPush("origin", "1.0.x", { cwd }); await gitCheckout("master", false, { cwd }); - await merge("next", { cwd }); + await gitCommits(["feat: new feature on master"], { cwd }); + await gitTagVersion("v1.1.0", undefined, { cwd }); + await merge("1.0.x", { cwd }); await gitPush("origin", "master", { cwd }); - t.log("$ semantic-release"); - ({ stdout, exitCode } = await execa(cli, [], { env, cwd, extendEnv: false })); - t.regex(stdout, new RegExp(`Updated GitHub release: release-url/${version}`)); - t.regex(stdout, new RegExp(`Adding version ${version} to npm registry on dist-tag latest`)); - t.is(exitCode, 0); - - // Wait for 3s as the change of dist-tag takes time to be reflected in the registry - await setTimeout(3000); - // Retrieve the published package from the registry and check version and gitHead - ({ - "dist-tags": { latest: releasedVersion }, - } = await npmView(packageName, npmTestEnv)); - t.is(releasedVersion, version); - t.is(await gitGetNote(`v${version}`, { cwd }), '{"channels":["next",null]}'); - t.is(await gitTagHead(`v${version}`, { cwd }), await gitTagHead(`v${version}`, { cwd })); - t.is( - await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), - await gitRemoteTagHead(authUrl, `v${version}`, { cwd }) - ); - t.log(`+ added ${releasedVersion}`); - await mockServer.verify(verifyMock); - await mockServer.verify(getReleaseMock); - await mockServer.verify(updateReleaseMock); + const verifyConditions = stub().resolves(); + const verifyRelease = stub().resolves(); + const addChannel = stub().resolves(); + const prepare = stub().resolves(); + const publish = stub().resolves(); + const success = stub().resolves(); + + const config = { branches: [{ name: "1.0.x" }, { name: "master" }], repositoryUrl, tagFormat: `v\${version}` }; + const options = { + ...config, + verifyConditions, + verifyRelease, + addChannel, + prepare, + publish, + success, + }; + + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); + const semanticRelease = (await import("../index.js")).default; + t.truthy(await semanticRelease(options, { cwd, env: {}, stdout: { write: () => {} }, stderr: { write: () => {} } })); + + t.is(addChannel.callCount, 0); + t.is(publish.callCount, 1); + // The release 1.1.1, triggered by the forward-port of "fix: fix on maintenance version 1.0.x" has been published from master + t.is(publish.args[0][1].nextRelease.version, "1.1.1"); + t.is(success.callCount, 1); }); -test("Exit with 1 if a plugin is not found", async (t) => { - const packageName = "test-plugin-not-found"; - const owner = "test-repo"; - // Create a git repository, set the current working directory at the root of the repo - t.log("Create git repository"); - const { cwd } = await gitRepo(); - await writeJson(path.resolve(cwd, "package.json"), { - name: packageName, - version: "0.0.0-dev", - repository: { url: `git+https://github.com/${owner}/${packageName}` }, - release: { analyzeCommits: "non-existing-path", success: false, fail: false }, +test.serial("Publish a pre-release version", async (t) => { + const { cwd, repositoryUrl } = await gitRepo(true); + await gitCommits(["feat: initial commit"], { cwd }); + await gitTagVersion("v1.0.0", undefined, { cwd }); + await gitPush(repositoryUrl, "master", { cwd }); + await gitCheckout("beta", true, { cwd }); + await gitCommits(["feat: a feature"], { cwd }); + await gitPush(repositoryUrl, "beta", { cwd }); + + const config = { branches: ["master", { name: "beta", prerelease: true }], repositoryUrl }; + const options = { + ...config, + verifyConditions: stub().resolves(), + verifyRelease: stub().resolves(), + generateNotes: stub().resolves(""), + addChannel: false, + prepare: stub().resolves(), + publish: stub().resolves(), + success: stub().resolves(), + fail: stub().resolves(), + }; + + const env = {}; + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + const envCi = (await td.replaceEsm("env-ci")).default; + td.when(envCi({ env, cwd })).thenReturn({ isCi: true, branch: "beta", isPr: false }); + const semanticRelease = (await import("../index.js")).default; + let { releases } = await semanticRelease(options, { + cwd, + env: {}, + stdout: { write: () => {} }, + stderr: { write: () => {} }, }); - const { exitCode, stderr } = await t.throwsAsync(execa(cli, [], { env, cwd, extendEnv: false })); - t.is(exitCode, 1); - t.regex(stderr, /Cannot find module/); + t.is(releases.length, 1); + t.is(releases[0].version, "1.1.0-beta.1"); + t.is(releases[0].gitTag, "v1.1.0-beta.1"); + t.is(await gitGetNote("v1.1.0-beta.1", { cwd }), '{"channels":["beta"]}'); + + await gitCommits(["fix: a fix"], { cwd }); + ({ releases } = await semanticRelease(options, { + cwd, + env, + stdout: { write: () => {} }, + stderr: { write: () => {} }, + })); + + t.is(releases.length, 1); + t.is(releases[0].version, "1.1.0-beta.2"); + t.is(releases[0].gitTag, "v1.1.0-beta.2"); + t.is(await gitGetNote("v1.1.0-beta.2", { cwd }), '{"channels":["beta"]}'); }); -test("Exit with 1 if a shareable config is not found", async (t) => { - const packageName = "test-config-not-found"; - const owner = "test-repo"; - // Create a git repository, set the current working directory at the root of the repo - t.log("Create git repository"); - const { cwd } = await gitRepo(); - await writeJson(path.resolve(cwd, "package.json"), { - name: packageName, - version: "0.0.0-dev", - repository: { url: `git+https://github.com/${owner}/${packageName}` }, - release: { extends: "non-existing-path", success: false, fail: false }, +test.serial("Publish releases from different branch on the same channel", async (t) => { + const { cwd, repositoryUrl } = await gitRepo(true); + await gitCommits(["feat: initial commit"], { cwd }); + await gitTagVersion("v1.0.0", undefined, { cwd }); + await gitPush(repositoryUrl, "master", { cwd }); + await gitCheckout("next-major", true, { cwd }); + await gitPush(repositoryUrl, "next-major", { cwd }); + await gitCheckout("next", true, { cwd }); + await gitCommits(["feat: a feature"], { cwd }); + await gitPush(repositoryUrl, "next", { cwd }); + + const config = { + branches: ["master", { name: "next", channel: false }, { name: "next-major", channel: false }], + repositoryUrl, + }; + const addChannel = stub().resolves({}); + const options = { + ...config, + verifyConditions: stub().resolves(), + verifyRelease: stub().resolves(), + generateNotes: stub().resolves(""), + addChannel, + prepare: stub().resolves(), + publish: stub().resolves(), + success: stub().resolves(), + fail: stub().resolves(), + }; + + const env = {}; + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + const envCi = (await td.replaceEsm("env-ci")).default; + td.when(envCi({ env, cwd })).thenReturn({ isCi: true, branch: "next", isPr: false }); + let semanticRelease = (await import("../index.js")).default; + let { releases } = await semanticRelease(options, { + cwd, + env, + stdout: { write: () => {} }, + stderr: { write: () => {} }, }); - const { exitCode, stderr } = await t.throwsAsync(execa(cli, [], { env, cwd, extendEnv: false })); - t.is(exitCode, 1); - t.regex(stderr, /Cannot find module/); + t.is(releases.length, 1); + t.is(releases[0].version, "1.1.0"); + t.is(releases[0].gitTag, "v1.1.0"); + + await gitCommits(["fix: a fix"], { cwd }); + ({ releases } = await semanticRelease(options, { + cwd, + env, + stdout: { write: () => {} }, + stderr: { write: () => {} }, + })); + + t.is(releases.length, 1); + t.is(releases[0].version, "1.1.1"); + t.is(releases[0].gitTag, "v1.1.1"); + + await gitCheckout("master", false, { cwd }); + await merge("next", { cwd }); + await gitPush("origin", "master", { cwd }); + + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); + semanticRelease = (await import("../index.js")).default; + + t.falsy(await semanticRelease(options, { cwd, env: {}, stdout: { write: () => {} }, stderr: { write: () => {} } })); + t.is(addChannel.callCount, 0); }); -test("Exit with 1 if a shareable config reference a not found plugin", async (t) => { - const packageName = "test-config-ref-not-found"; - const owner = "test-repo"; - const shareable = { analyzeCommits: "non-existing-path" }; +test.serial("Publish pre-releases the same channel as regular releases", async (t) => { + const { cwd, repositoryUrl } = await gitRepo(true); + await gitCommits(["feat: initial commit"], { cwd }); + await gitTagVersion("v1.0.0", undefined, { cwd }); + await gitPush(repositoryUrl, "master", { cwd }); + await gitCheckout("beta", true, { cwd }); + await gitCommits(["feat: a feature"], { cwd }); + await gitPush(repositoryUrl, "beta", { cwd }); + + const config = { + branches: ["master", { name: "beta", channel: false, prerelease: true }], + repositoryUrl, + }; + const options = { + ...config, + verifyConditions: stub().resolves(), + verifyRelease: stub().resolves(), + generateNotes: stub().resolves(""), + addChannel: false, + prepare: stub().resolves(), + publish: stub().resolves(), + success: stub().resolves(), + fail: stub().resolves(), + }; - // Create a git repository, set the current working directory at the root of the repo - t.log("Create git repository"); - const { cwd } = await gitRepo(); - await writeJson(path.resolve(cwd, "package.json"), { - name: packageName, - version: "0.0.0-dev", - repository: { url: `git+https://github.com/${owner}/${packageName}` }, - release: { extends: "./shareable.json", success: false, fail: false }, + const env = {}; + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + const envCi = (await td.replaceEsm("env-ci")).default; + td.when(envCi({ cwd, env })).thenReturn({ isCi: true, branch: "beta", isPr: false }); + const semanticRelease = (await import("../index.js")).default; + let { releases } = await semanticRelease(options, { + cwd, + env, + stdout: { write: () => {} }, + stderr: { write: () => {} }, }); - await writeJson(path.resolve(cwd, "shareable.json"), shareable); - const { exitCode, stderr } = await t.throwsAsync(execa(cli, [], { env, cwd, extendEnv: false })); - t.is(exitCode, 1); - t.regex(stderr, /Cannot find module/); + t.is(releases.length, 1); + t.is(releases[0].version, "1.1.0-beta.1"); + t.is(releases[0].gitTag, "v1.1.0-beta.1"); + + await gitCommits(["fix: a fix"], { cwd }); + ({ releases } = await semanticRelease(options, { + cwd, + env, + stdout: { write: () => {} }, + stderr: { write: () => {} }, + })); + + t.is(releases.length, 1); + t.is(releases[0].version, "1.1.0-beta.2"); + t.is(releases[0].gitTag, "v1.1.0-beta.2"); +}); + +test.serial("Do not add pre-releases to a different channel", async (t) => { + const { cwd, repositoryUrl } = await gitRepo(true); + await gitCommits(["feat: initial release"], { cwd }); + await gitTagVersion("v1.0.0", undefined, { cwd }); + await gitAddNote(JSON.stringify({ channels: [null, "beta"] }), "v1.0.0", { cwd }); + await gitCheckout("beta", true, { cwd }); + await gitCommits(["feat: breaking change/n/nBREAKING CHANGE: break something"], { cwd }); + await gitTagVersion("v2.0.0-beta.1", undefined, { cwd }); + await gitAddNote(JSON.stringify({ channels: ["beta"] }), "v2.0.0-beta.1", { cwd }); + await gitCommits(["fix: a fix"], { cwd }); + await gitTagVersion("v2.0.0-beta.2", undefined, { cwd }); + await gitAddNote(JSON.stringify({ channels: ["beta"] }), "v2.0.0-beta.2", { cwd }); + await gitPush("origin", "beta", { cwd }); + await gitCheckout("master", false, { cwd }); + await merge("beta", { cwd }); + await gitPush("origin", "master", { cwd }); + + const verifyConditions = stub().resolves(); + const verifyRelease = stub().resolves(); + const generateNotes = stub().resolves("Release notes"); + const release1 = { name: "Release 1", url: "https://release1.com" }; + const addChannel = stub().resolves(release1); + const prepare = stub().resolves(); + const publish = stub().resolves(); + const success = stub().resolves(); + + const config = { + branches: [{ name: "master" }, { name: "beta", prerelease: "beta" }], + repositoryUrl, + tagFormat: `v\${version}`, + }; + + const options = { + ...config, + verifyConditions, + verifyRelease, + addChannel, + generateNotes, + prepare, + publish, + success, + }; + + const env = {}; + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + const envCi = (await td.replaceEsm("env-ci")).default; + td.when(envCi({ cwd, env })).thenReturn({ isCi: true, branch: "master", isPr: false }); + const semanticRelease = (await import("../index.js")).default; + t.truthy(await semanticRelease(options, { cwd, env, stdout: { write: () => {} }, stderr: { write: () => {} } })); + + t.is(addChannel.callCount, 0); }); -test("Dry-run", async (t) => { - const packageName = "test-dry-run"; - const owner = "git"; +async function addChannelMacro(t, mergeFunction) { + const { cwd, repositoryUrl } = await gitRepo(true); + const commits = await gitCommits(["feat: initial release"], { cwd }); + await gitTagVersion("v1.0.0", undefined, { cwd }); + await gitAddNote(JSON.stringify({ channels: [null, "next"] }), "v1.0.0", { cwd }); + await gitCheckout("next", true, { cwd }); + commits.push(...(await gitCommits(["feat: breaking change/n/nBREAKING CHANGE: break something"], { cwd }))); + await gitTagVersion("v2.0.0", undefined, { cwd }); + await gitAddNote(JSON.stringify({ channels: ["next"] }), "v2.0.0", { cwd }); + + commits.push(...(await gitCommits(["fix: a fix"], { cwd }))); + await gitTagVersion("v2.0.1", undefined, { cwd }); + await gitAddNote(JSON.stringify({ channels: ["next"] }), "v2.0.1", { cwd }); + commits.push(...(await gitCommits(["feat: a feature"], { cwd }))); + await gitTagVersion("v2.1.0", undefined, { cwd }); + await gitAddNote(JSON.stringify({ channels: ["next"] }), "v2.1.0", { cwd }); + await gitPush("origin", "next", { cwd }); + await gitCheckout("master", false, { cwd }); + // Merge all commits but last one from next to master + await mergeFunction("next~1", { cwd }); + await gitPush("origin", "master", { cwd }); + + const notes = "Release notes"; + const verifyConditions = stub().resolves(); + const verifyRelease = stub().resolves(); + const generateNotes = stub().resolves(notes); + const release1 = { name: "Release 1", url: "https://release1.com" }; + const addChannel1 = stub().resolves(release1); + const addChannel2 = stub().resolves(); + const prepare = stub().resolves(); + const publish = stub().resolves(); + const success = stub().resolves(); + + const config = { + branches: [ + { name: "master", channel: "latest" }, + { name: "next", channel: "next" }, + ], + repositoryUrl, + tagFormat: `v\${version}`, + }; + const options = { + ...config, + verifyConditions, + verifyRelease, + addChannel: [addChannel1, addChannel2], + generateNotes, + prepare, + publish, + success, + }; + const nextRelease = { + name: "v2.0.1", + type: "patch", + version: "2.0.1", + channel: "latest", + gitTag: "v2.0.1", + gitHead: commits[2].hash, + }; + + const env = {}; + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + const envCi = (await td.replaceEsm("env-ci")).default; + td.when(envCi({ env, cwd })).thenReturn({ isCi: true, branch: "master", isPr: false }); + const semanticRelease = (await import("../index.js")).default; + const result = await semanticRelease(options, { cwd, env, stdout: { write: () => {} }, stderr: { write: () => {} } }); + + t.deepEqual(result.releases, [ + { ...nextRelease, ...release1, notes, pluginName: "[Function: functionStub]" }, + { ...nextRelease, notes, pluginName: "[Function: functionStub]" }, + ]); + + // Verify the tag has been created on the local and remote repo and reference + t.is(await gitTagHead(nextRelease.gitTag, { cwd }), nextRelease.gitHead); + t.is(await gitRemoteTagHead(repositoryUrl, nextRelease.gitTag, { cwd }), nextRelease.gitHead); +} + +addChannelMacro.title = (providedTitle) => `Add version to a channel after a merge (${providedTitle})`; + +test.serial("fast-forward", addChannelMacro, mergeFf); +test.serial("non fast-forward", addChannelMacro, merge); +test.serial("rebase", addChannelMacro, rebase); + +test.serial('Call all "success" plugins even if one errors out', async (t) => { // Create a git repository, set the current working directory at the root of the repo - t.log("Create git repository and package.json"); - const { cwd, repositoryUrl } = await gitbox.createRepo(packageName); - // Create package.json in repository root - await writeJson(path.resolve(cwd, "package.json"), { - name: packageName, - version: "0.0.0-dev", - repository: { url: repositoryUrl }, - publishConfig: { registry: npmRegistry.url }, - release: { success: false, fail: false }, - }); + const { cwd, repositoryUrl } = await gitRepo(true); + // Add commits to the master branch + await gitCommits(["First"], { cwd }); + // Create the tag corresponding to version 1.0.0 + await gitTagVersion("v1.0.0", undefined, { cwd }); + // Add new commits to the master branch + await gitCommits(["Second"], { cwd }); + await gitPush(repositoryUrl, "master", { cwd }); + + const nextRelease = { + name: "v2.0.0", + type: "major", + version: "2.0.0", + gitHead: await getGitHead({ cwd }), + gitTag: "v2.0.0", + channel: null, + }; + const notes = "Release notes"; + const verifyConditions1 = stub().resolves(); + const verifyConditions2 = stub().resolves(); + const analyzeCommits = stub().resolves(nextRelease.type); + const generateNotes = stub().resolves(notes); + const release = { name: "Release", url: "https://release.com" }; + const publish = stub().resolves(release); + const success1 = stub().rejects(); + const success2 = stub().resolves(); + const config = { + branches: [{ name: "master" }], + repositoryUrl, + globalOpt: "global", + tagFormat: `v\${version}`, + }; + const options = { + ...config, + verifyConditions: [verifyConditions1, verifyConditions2], + analyzeCommits, + generateNotes, + addChannel: stub().resolves(), + prepare: stub().resolves(), + publish, + success: [success1, success2], + }; + + const env = {}; + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + const envCi = (await td.replaceEsm("env-ci")).default; + td.when(envCi({ cwd, env })).thenReturn({ isCi: true, branch: "master", isPr: false }); + const semanticRelease = (await import("../index.js")).default; - /* Initial release */ - const verifyMock = await mockServer.mock( - `/repos/${owner}/${packageName}`, - { headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] }, - { body: { permissions: { push: true } }, method: "GET" } + await t.throwsAsync( + semanticRelease(options, { cwd, env, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer() }) ); - const version = "1.0.0"; - t.log("Commit a feature"); - await gitCommits(["feat: Initial commit"], { cwd }); - t.log("$ semantic-release -d"); - const { stdout, exitCode } = await execa(cli, ["-d"], { env, cwd, extendEnv: false }); - t.regex(stdout, new RegExp(`There is no previous release, the next release version is ${version}`)); - t.regex(stdout, new RegExp(`Release note for version ${version}`)); - t.regex(stdout, /Initial commit/); - t.is(exitCode, 0); - - // Verify package.json and has not been modified - t.is((await readJson(path.resolve(cwd, "package.json"))).version, "0.0.0-dev"); - await mockServer.verify(verifyMock); + + t.is(success1.callCount, 1); + t.deepEqual(success1.args[0][0], config); + t.deepEqual(success1.args[0][1].releases, [ + { ...nextRelease, ...release, notes, pluginName: "[Function: functionStub]" }, + ]); + + t.is(success2.callCount, 1); + t.deepEqual(success2.args[0][1].releases, [ + { ...nextRelease, ...release, notes, pluginName: "[Function: functionStub]" }, + ]); }); -test('Allow local releases with "noCi" option', async (t) => { - const envNoCi = { ...env }; - delete envNoCi.CI; - const packageName = "test-no-ci"; - const owner = "git"; +test.serial('Log all "verifyConditions" errors', async (t) => { // Create a git repository, set the current working directory at the root of the repo - t.log("Create git repository and package.json"); - const { cwd, repositoryUrl, authUrl } = await gitbox.createRepo(packageName); - // Create package.json in repository root - await writeJson(path.resolve(cwd, "package.json"), { - name: packageName, - version: "0.0.0-dev", - repository: { url: repositoryUrl }, - publishConfig: { registry: npmRegistry.url }, - release: { success: false, fail: false }, - }); + const { cwd, repositoryUrl } = await gitRepo(true); + // Add commits to the master branch + await gitCommits(["First"], { cwd }); + await gitPush(repositoryUrl, "master", { cwd }); + + const error1 = new Error("error 1"); + const error2 = new SemanticReleaseError("error 2", "ERR2"); + const error3 = new SemanticReleaseError("error 3", "ERR3"); + const fail = stub().resolves(); + const config = { + branches: [{ name: "master" }], + repositoryUrl, + originalRepositoryURL: repositoryUrl, + tagFormat: `v\${version}`, + }; + const options = { + ...config, + plugins: false, + verifyConditions: [stub().rejects(new AggregateError([error1, error2])), stub().rejects(error3)], + fail, + }; + + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); + const semanticRelease = (await import("../index.js")).default; + const errors = [ + ...( + await t.throwsAsync( + semanticRelease(options, { + cwd, + env: {}, + stdout: new WritableStreamBuffer(), + stderr: new WritableStreamBuffer(), + }) + ) + ).errors, + ]; + + t.deepEqual(sortBy(errors, ["message"]), sortBy([error1, error2, error3], ["message"])); + t.true(t.context.error.calledWith("An error occurred while running semantic-release: %O", error1)); + t.true(t.context.error.calledWith("ERR2 error 2")); + t.true(t.context.error.calledWith("ERR3 error 3")); + t.true(t.context.error.calledAfter(t.context.log)); + t.is(fail.callCount, 1); + t.deepEqual(fail.args[0][0], config); + t.deepEqual(fail.args[0][1].options, options); + t.deepEqual(fail.args[0][1].logger, t.context.logger); + t.deepEqual(fail.args[0][1].errors, [error2, error3]); +}); + +test.serial('Log all "verifyRelease" errors', async (t) => { + // Create a git repository, set the current working directory at the root of the repo + const { cwd, repositoryUrl } = await gitRepo(true); + // Add commits to the master branch + await gitCommits(["First"], { cwd }); + // Create the tag corresponding to version 1.0.0 + await gitTagVersion("v1.0.0", undefined, { cwd }); + // Add new commits to the master branch + await gitCommits(["Second"], { cwd }); + await gitPush(repositoryUrl, "master", { cwd }); + + const error1 = new SemanticReleaseError("error 1", "ERR1"); + const error2 = new SemanticReleaseError("error 2", "ERR2"); + const fail = stub().resolves(); + const config = { branches: [{ name: "master" }], repositoryUrl, tagFormat: `v\${version}` }; + const options = { + ...config, + verifyConditions: stub().resolves(), + analyzeCommits: stub().resolves("major"), + verifyRelease: [stub().rejects(error1), stub().rejects(error2)], + fail, + }; + + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); + const semanticRelease = (await import("../index.js")).default; + const errors = [ + ...( + await t.throwsAsync( + semanticRelease(options, { + cwd, + env: {}, + stdout: new WritableStreamBuffer(), + stderr: new WritableStreamBuffer(), + }) + ) + ).errors, + ]; + + t.deepEqual(sortBy(errors, ["message"]), sortBy([error1, error2], ["message"])); + t.true(t.context.error.calledWith("ERR1 error 1")); + t.true(t.context.error.calledWith("ERR2 error 2")); + t.is(fail.callCount, 1); + t.deepEqual(fail.args[0][0], config); + t.deepEqual(fail.args[0][1].errors, [error1, error2]); +}); + +test.serial("Dry-run skips addChannel, prepare, publish and success", async (t) => { + const { cwd, repositoryUrl } = await gitRepo(true); + await gitCommits(["First"], { cwd }); + await gitTagVersion("v1.0.0", undefined, { cwd }); + await gitAddNote(JSON.stringify({ channels: [null, "next"] }), "v1.0.0", { cwd }); + await gitCommits(["Second"], { cwd }); + await gitTagVersion("v1.1.0", undefined, { cwd }); + await gitAddNote(JSON.stringify({ channels: ["next"] }), "v1.1.0", { cwd }); + + await gitPush(repositoryUrl, "master", { cwd }); + await gitCheckout("next", true, { cwd }); + await gitPush("origin", "next", { cwd }); - /* Initial release */ - const version = "1.0.0"; - const verifyMock = await mockServer.mock( - `/repos/${owner}/${packageName}`, - { headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] }, - { body: { permissions: { push: true } }, method: "GET" } + const verifyConditions = stub().resolves(); + const analyzeCommits = stub().resolves("minor"); + const verifyRelease = stub().resolves(); + const generateNotes = stub().resolves(); + const addChannel = stub().resolves(); + const prepare = stub().resolves(); + const publish = stub().resolves(); + const success = stub().resolves(); + + const options = { + dryRun: true, + branches: ["master", "next"], + repositoryUrl, + verifyConditions, + analyzeCommits, + verifyRelease, + generateNotes, + addChannel, + prepare, + publish, + success, + }; + + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); + const semanticRelease = (await import("../index.js")).default; + t.truthy( + await semanticRelease(options, { + cwd, + env: {}, + stdout: new WritableStreamBuffer(), + stderr: new WritableStreamBuffer(), + }) ); - const createReleaseMock = await mockServer.mock( - `/repos/${owner}/${packageName}/releases`, - { - body: { tag_name: `v${version}`, name: `v${version}` }, - headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }], - }, - { body: { html_url: `release-url/${version}` } } + + t.not(t.context.warn.args[0][0], "This run was not triggered in a known CI environment, running in dry-run mode."); + t.is(verifyConditions.callCount, 1); + t.is(analyzeCommits.callCount, 1); + t.is(verifyRelease.callCount, 1); + t.is(generateNotes.callCount, 2); + t.is(addChannel.callCount, 0); + t.true( + t.context.warn.calledWith(`Skip step "addChannel" of plugin "[Function: ${addChannel.name}]" in dry-run mode`) ); + t.is(prepare.callCount, 0); + t.true(t.context.warn.calledWith(`Skip step "prepare" of plugin "[Function: ${prepare.name}]" in dry-run mode`)); + t.is(publish.callCount, 0); + t.true(t.context.warn.calledWith(`Skip step "publish" of plugin "[Function: ${publish.name}]" in dry-run mode`)); + t.is(success.callCount, 0); + t.true(t.context.warn.calledWith(`Skip step "success" of plugin "[Function: ${success.name}]" in dry-run mode`)); +}); + +test.serial("Dry-run skips fail", async (t) => { + // Create a git repository, set the current working directory at the root of the repo + const { cwd, repositoryUrl } = await gitRepo(true); + // Add commits to the master branch + await gitCommits(["First"], { cwd }); + // Create the tag corresponding to version 1.0.0 + await gitTagVersion("v1.0.0", undefined, { cwd }); + // Add new commits to the master branch + await gitCommits(["Second"], { cwd }); + await gitPush(repositoryUrl, "master", { cwd }); + + const error1 = new SemanticReleaseError("error 1", "ERR1"); + const error2 = new SemanticReleaseError("error 2", "ERR2"); + const fail = stub().resolves(); + + const options = { + dryRun: true, + branches: ["master"], + repositoryUrl, + verifyConditions: [stub().rejects(error1), stub().rejects(error2)], + fail, + }; - t.log("Commit a feature"); - await gitCommits(["feat: Initial commit"], { cwd }); - t.log("$ semantic-release --no-ci"); - const { stdout, exitCode } = await execa(cli, ["--no-ci"], { env: envNoCi, cwd, extendEnv: false }); - t.regex(stdout, new RegExp(`Published GitHub release: release-url/${version}`)); - t.regex(stdout, new RegExp(`Publishing version ${version} to npm registry`)); - t.is(exitCode, 0); - - // Verify package.json and has been updated - t.is((await readJson(path.resolve(cwd, "package.json"))).version, version); - - // Retrieve the published package from the registry and check version and gitHead - const { version: releasedVersion, gitHead: releasedGitHead } = await npmView(packageName, npmTestEnv); - - const head = await gitHead({ cwd }); - t.is(releasedVersion, version); - t.is(releasedGitHead, head); - t.is(await gitTagHead(`v${version}`, { cwd }), head); - t.is(await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), head); - t.log(`+ released ${releasedVersion} with head ${releasedGitHead}`); - - await mockServer.verify(verifyMock); - await mockServer.verify(createReleaseMock); + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); + const semanticRelease = (await import("../index.js")).default; + const errors = [ + ...( + await t.throwsAsync( + semanticRelease(options, { + cwd, + env: {}, + stdout: new WritableStreamBuffer(), + stderr: new WritableStreamBuffer(), + }) + ) + ).errors, + ]; + + t.deepEqual(sortBy(errors, ["message"]), sortBy([error1, error2], ["message"])); + t.true(t.context.error.calledWith("ERR1 error 1")); + t.true(t.context.error.calledWith("ERR2 error 2")); + t.is(fail.callCount, 0); + t.true(t.context.warn.calledWith(`Skip step "fail" of plugin "[Function: ${fail.name}]" in dry-run mode`)); }); -test("Pass options via CLI arguments", async (t) => { - const packageName = "test-cli"; +test.serial('Force a dry-run if not on a CI and "noCi" is not explicitly set', async (t) => { // Create a git repository, set the current working directory at the root of the repo - t.log("Create git repository and package.json"); - const { cwd, repositoryUrl, authUrl } = await gitbox.createRepo(packageName); - // Create package.json in repository root - await writeJson(path.resolve(cwd, "package.json"), { - name: packageName, - version: "0.0.0-dev", - repository: { url: repositoryUrl }, - publishConfig: { registry: npmRegistry.url }, - }); + const { cwd, repositoryUrl } = await gitRepo(true); + // Add commits to the master branch + await gitCommits(["First"], { cwd }); + // Create the tag corresponding to version 1.0.0 + await gitTagVersion("v1.0.0", undefined, { cwd }); + // Add new commits to the master branch + await gitCommits(["Second"], { cwd }); + await gitPush(repositoryUrl, "master", { cwd }); + + const nextRelease = { + name: "v2.0.0", + type: "major", + version: "2.0.0", + gitHead: await getGitHead({ cwd }), + gitTag: "v2.0.0", + channel: undefined, + }; + const notes = "Release notes"; + + const verifyConditions = stub().resolves(); + const analyzeCommits = stub().resolves(nextRelease.type); + const verifyRelease = stub().resolves(); + const generateNotes = stub().resolves(notes); + const publish = stub().resolves(); + const success = stub().resolves(); + + const options = { + dryRun: false, + branches: ["master"], + repositoryUrl, + verifyConditions, + analyzeCommits, + verifyRelease, + generateNotes, + addChannel: stub().resolves(), + prepare: stub().resolves(), + publish, + success, + fail: stub().resolves(), + }; - /* Initial release */ - const version = "1.0.0"; - t.log("Commit a feature"); - await gitCommits(["feat: Initial commit"], { cwd }); - t.log("$ semantic-release"); - const { stdout, exitCode } = await execa( - cli, - [ - "--verify-conditions", - "@semantic-release/npm", - "--publish", - "@semantic-release/npm", - `--success`, - false, - `--fail`, - false, - "--debug", - ], - { env, cwd, extendEnv: false } + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: false, branch: "master" })); + const semanticRelease = (await import("../index.js")).default; + t.truthy( + await semanticRelease(options, { + cwd, + env: {}, + stdout: new WritableStreamBuffer(), + stderr: new WritableStreamBuffer(), + }) ); - t.regex(stdout, new RegExp(`Publishing version ${version} to npm registry`)); - t.is(exitCode, 0); - - // Verify package.json and has been updated - t.is((await readJson(path.resolve(cwd, "package.json"))).version, version); - - // Retrieve the published package from the registry and check version and gitHead - const { version: releasedVersion, gitHead: releasedGitHead } = await npmView(packageName, npmTestEnv); - const head = await gitHead({ cwd }); - t.is(releasedVersion, version); - t.is(releasedGitHead, head); - t.is(await gitTagHead(`v${version}`, { cwd }), head); - t.is(await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), head); - t.log(`+ released ${releasedVersion} with head ${releasedGitHead}`); + + t.true(t.context.warn.calledWith("This run was not triggered in a known CI environment, running in dry-run mode.")); + t.is(verifyConditions.callCount, 1); + t.is(analyzeCommits.callCount, 1); + t.is(verifyRelease.callCount, 1); + t.is(generateNotes.callCount, 1); + t.is(publish.callCount, 0); + t.is(success.callCount, 0); }); -test("Run via JS API", async (t) => { - await td.replaceEsm("../lib/logger", null, { log: () => {}, error: () => {}, stdout: () => {} }); +test.serial('Dry-run does not print changelog if "generateNotes" return "undefined"', async (t) => { + // Create a git repository, set the current working directory at the root of the repo + const { cwd, repositoryUrl } = await gitRepo(true); + // Add commits to the master branch + await gitCommits(["First"], { cwd }); + // Create the tag corresponding to version 1.0.0 + await gitTagVersion("v1.0.0", undefined, { cwd }); + // Add new commits to the master branch + await gitCommits(["Second"], { cwd }); + await gitPush(repositoryUrl, "master", { cwd }); + + const nextRelease = { type: "major", version: "2.0.0", gitHead: await getGitHead({ cwd }), gitTag: "v2.0.0" }; + const analyzeCommits = stub().resolves(nextRelease.type); + const generateNotes = stub().resolves(); + + const options = { + dryRun: true, + branches: ["master"], + repositoryUrl, + verifyConditions: false, + analyzeCommits, + verifyRelease: false, + generateNotes, + prepare: false, + publish: false, + success: false, + }; + + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); const semanticRelease = (await import("../index.js")).default; - const packageName = "test-js-api"; - const owner = "git"; + t.truthy( + await semanticRelease(options, { + cwd, + env: {}, + stdout: new WritableStreamBuffer(), + stderr: new WritableStreamBuffer(), + }) + ); + + t.deepEqual(t.context.log.args[t.context.log.args.length - 1], ["Release note for version 2.0.0:"]); +}); + +test.serial('Allow local releases with "noCi" option', async (t) => { // Create a git repository, set the current working directory at the root of the repo - t.log("Create git repository and package.json"); - const { cwd, repositoryUrl, authUrl } = await gitbox.createRepo(packageName); - // Create package.json in repository root - await writeJson(path.resolve(cwd, "package.json"), { - name: packageName, - version: "0.0.0-dev", - repository: { url: repositoryUrl }, - publishConfig: { registry: npmRegistry.url }, - release: { - fail: false, - success: false, - }, - }); + const { cwd, repositoryUrl } = await gitRepo(true); + // Add commits to the master branch + await gitCommits(["First"], { cwd }); + // Create the tag corresponding to version 1.0.0 + await gitTagVersion("v1.0.0", undefined, { cwd }); + // Add new commits to the master branch + await gitCommits(["Second"], { cwd }); + await gitPush(repositoryUrl, "master", { cwd }); + + const nextRelease = { + name: "v2.0.0", + type: "major", + version: "2.0.0", + gitHead: await getGitHead({ cwd }), + gitTag: "v2.0.0", + channel: undefined, + }; + const notes = "Release notes"; + + const verifyConditions = stub().resolves(); + const analyzeCommits = stub().resolves(nextRelease.type); + const verifyRelease = stub().resolves(); + const generateNotes = stub().resolves(notes); + const publish = stub().resolves(); + const success = stub().resolves(); + + const options = { + noCi: true, + branches: ["master"], + repositoryUrl, + verifyConditions, + analyzeCommits, + verifyRelease, + generateNotes, + addChannel: stub().resolves(), + prepare: stub().resolves(), + publish, + success, + fail: stub().resolves(), + }; - /* Initial release */ - const version = "1.0.0"; - const verifyMock = await mockServer.mock( - `/repos/${owner}/${packageName}`, - { headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] }, - { body: { permissions: { push: true } }, method: "GET" } + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: false, branch: "master", isPr: false })); + const semanticRelease = (await import("../index.js")).default; + t.truthy( + await semanticRelease(options, { + cwd, + env: {}, + stdout: new WritableStreamBuffer(), + stderr: new WritableStreamBuffer(), + }) ); - const createReleaseMock = await mockServer.mock( - `/repos/${owner}/${packageName}/releases`, - { - body: { tag_name: `v${version}`, name: `v${version}` }, - headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }], - }, - { body: { html_url: `release-url/${version}` } } + + t.not(t.context.log.args[0][0], "This run was not triggered in a known CI environment, running in dry-run mode."); + t.not( + t.context.log.args[0][0], + "This run was triggered by a pull request and therefore a new version won't be published." ); + t.is(verifyConditions.callCount, 1); + t.is(analyzeCommits.callCount, 1); + t.is(verifyRelease.callCount, 1); + t.is(generateNotes.callCount, 1); + t.is(publish.callCount, 1); + t.is(success.callCount, 1); +}); - t.log("Commit a feature"); - await gitCommits(["feat: Initial commit"], { cwd }); - t.log("$ Call semantic-release via API"); - await semanticRelease(undefined, { - cwd, - env, - stdout: new WritableStreamBuffer(), - stderr: new WritableStreamBuffer(), - }); +test.serial( + 'Accept "undefined" value returned by "generateNotes" and "false" by "publish" and "addChannel"', + async (t) => { + const { cwd, repositoryUrl } = await gitRepo(true); + await gitCommits(["First"], { cwd }); + await gitTagVersion("v1.0.0", undefined, { cwd }); + await gitAddNote(JSON.stringify({ channels: [null, "next"] }), "v1.0.0", { cwd }); + await gitCommits(["Second"], { cwd }); + await gitTagVersion("v1.1.0", undefined, { cwd }); + await gitAddNote(JSON.stringify({ channels: ["next"] }), "v1.1.0", { cwd }); + await gitPush(repositoryUrl, "master", { cwd }); + await gitCheckout("next", true, { cwd }); + await gitPush("origin", "next", { cwd }); + await gitCheckout("master", false, { cwd }); + + const nextRelease = { + name: "v1.2.0", + type: "minor", + version: "1.2.0", + gitHead: await getGitHead({ cwd }), + gitTag: "v1.2.0", + channel: null, + }; + const analyzeCommits = stub().resolves(nextRelease.type); + const verifyRelease = stub().resolves(); + const generateNotes1 = stub().resolves(); + const notes2 = "Release notes 2"; + const generateNotes2 = stub().resolves(notes2); + const publish = stub().resolves(false); + const addChannel = stub().resolves(false); + const success = stub().resolves(); + + const options = { + branches: ["master", "next"], + repositoryUrl, + verifyConditions: stub().resolves(), + analyzeCommits, + verifyRelease, + generateNotes: [generateNotes1, generateNotes2], + addChannel, + prepare: stub().resolves(), + publish, + success, + fail: stub().resolves(), + }; + + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); + const semanticRelease = (await import("../index.js")).default; + t.truthy( + await semanticRelease(options, { + cwd, + env: {}, + stdout: new WritableStreamBuffer(), + stderr: new WritableStreamBuffer(), + }) + ); + + t.is(analyzeCommits.callCount, 1); + t.is(verifyRelease.callCount, 1); + t.is(generateNotes1.callCount, 2); + t.is(generateNotes2.callCount, 2); + t.is(addChannel.callCount, 1); + t.is(publish.callCount, 1); + t.is(success.callCount, 2); + t.deepEqual(publish.args[0][1].nextRelease, { ...nextRelease, notes: notes2 }); + t.deepEqual(success.args[0][1].releases, [{ pluginName: "[Function: functionStub]" }]); + t.deepEqual(success.args[1][1].releases, [{ pluginName: "[Function: functionStub]" }]); + } +); + +test.serial("Returns false if triggered by a PR", async (t) => { + // Create a git repository, set the current working directory at the root of the repo + const { cwd, repositoryUrl } = await gitRepo(true); + + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", prBranch: "patch-1", isPr: true })); + const semanticRelease = (await import("../index.js")).default; + + t.false( + await semanticRelease( + { cwd, repositoryUrl }, + { cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer() } + ) + ); + t.is( + t.context.log.args[t.context.log.args.length - 1][0], + "This run was triggered by a pull request and therefore a new version won't be published." + ); +}); + +test.serial( + 'Throws "EINVALIDNEXTVERSION" if next release is out of range of the current maintenance branch', + async (t) => { + const { cwd, repositoryUrl } = await gitRepo(true); + await gitCommits(["feat: initial commit"], { cwd }); + await gitTagVersion("v1.0.0", undefined, { cwd }); + await gitAddNote(JSON.stringify({ channels: [null, "1.x"] }), "v1.0.0", { cwd }); + await gitCheckout("1.x", true, { cwd }); + await gitPush("origin", "1.x", { cwd }); + await gitCheckout("master", false, { cwd }); + await gitCommits(["feat: new feature on master"], { cwd }); + await gitTagVersion("v1.1.0", undefined, { cwd }); + await gitCheckout("1.x", false, { cwd }); + await gitCommits(["feat: feature on maintenance version 1.x"], { cwd }); + await gitPush("origin", "master", { cwd }); + + const verifyConditions = stub().resolves(); + const verifyRelease = stub().resolves(); + const addChannel = stub().resolves(); + const prepare = stub().resolves(); + const publish = stub().resolves(); + const success = stub().resolves(); + + const config = { + branches: [{ name: "1.x" }, { name: "master" }], + repositoryUrl, + tagFormat: `v\${version}`, + }; + const options = { + ...config, + verifyConditions, + verifyRelease, + addChannel, + prepare, + publish, + success, + }; + + const env = {}; + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + const envCi = (await td.replaceEsm("env-ci")).default; + td.when(envCi({ cwd, env })).thenReturn({ isCi: true, branch: "1.x", isPr: false }); + const semanticRelease = (await import("../index.js")).default; + + const error = await t.throwsAsync( + semanticRelease(options, { cwd, env, stdout: { write: () => {} }, stderr: { write: () => {} } }) + ); + + t.is(error.code, "EINVALIDNEXTVERSION"); + t.is(error.name, "SemanticReleaseError"); + t.is(error.message, "The release `1.1.0` on branch `1.x` cannot be published as it is out of range."); + t.regex(error.details, /A valid branch could be `master`./); + } +); + +test.serial('Throws "EINVALIDNEXTVERSION" if next release is out of range of the current release branch', async (t) => { + const { cwd, repositoryUrl } = await gitRepo(true); + await gitCommits(["feat: initial commit"], { cwd }); + await gitTagVersion("v1.0.0", undefined, { cwd }); + await gitCheckout("next", true, { cwd }); + await gitCommits(["feat: new feature on next"], { cwd }); + await gitTagVersion("v1.1.0", undefined, { cwd }); + await gitAddNote(JSON.stringify({ channels: ["next"] }), "v1.1.0", { cwd }); + await gitPush("origin", "next", { cwd }); + await gitCheckout("next-major", true, { cwd }); + await gitPush("origin", "next-major", { cwd }); + await gitCheckout("master", false, { cwd }); + await gitCommits(["feat: new feature on master", "fix: new fix on master"], { cwd }); + await gitPush("origin", "master", { cwd }); + + const verifyConditions = stub().resolves(); + const verifyRelease = stub().resolves(); + const addChannel = stub().resolves(); + const prepare = stub().resolves(); + const publish = stub().resolves(); + const success = stub().resolves(); + + const config = { + branches: [{ name: "master" }, { name: "next" }, { name: "next-major" }], + repositoryUrl, + tagFormat: `v\${version}`, + }; + const options = { + ...config, + verifyConditions, + verifyRelease, + addChannel, + prepare, + publish, + success, + }; - // Verify package.json and has been updated - t.is((await readJson(path.resolve(cwd, "package.json"))).version, version); + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); + const semanticRelease = (await import("../index.js")).default; - // Retrieve the published package from the registry and check version and gitHead - const { version: releasedVersion, gitHead: releasedGitHead } = await npmView(packageName, npmTestEnv); - const head = await gitHead({ cwd }); - t.is(releasedVersion, version); - t.is(releasedGitHead, head); - t.is(await gitTagHead(`v${version}`, { cwd }), head); - t.is(await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), head); - t.log(`+ released ${releasedVersion} with head ${releasedGitHead}`); + const error = await t.throwsAsync( + semanticRelease(options, { cwd, env: {}, stdout: { write: () => {} }, stderr: { write: () => {} } }) + ); - await mockServer.verify(verifyMock); - await mockServer.verify(createReleaseMock); + t.is(error.code, "EINVALIDNEXTVERSION"); + t.is(error.name, "SemanticReleaseError"); + t.is(error.message, "The release `1.1.0` on branch `master` cannot be published as it is out of range."); + t.regex(error.details, /A valid branch could be `next` or `next-major`./); }); -test("Log unexpected errors from plugins and exit with 1", async (t) => { - const packageName = "test-unexpected-error"; +test.serial('Throws "EINVALIDMAINTENANCEMERGE" if merge an out of range release in a maintenance branch', async (t) => { + const { cwd, repositoryUrl } = await gitRepo(true); + await gitCommits(["First"], { cwd }); + await gitTagVersion("v1.0.0", undefined, { cwd }); + await gitAddNote(JSON.stringify({ channels: [null, "1.1.x"] }), "v1.0.0", { cwd }); + await gitCommits(["Second"], { cwd }); + await gitTagVersion("v1.1.0", undefined, { cwd }); + await gitAddNote(JSON.stringify({ channels: [null, "1.1.x"] }), "v1.1.0", { cwd }); + await gitCheckout("1.1.x", "master", { cwd }); + await gitPush("origin", "1.1.x", { cwd }); + await gitCheckout("master", false, { cwd }); + await gitCommits(["Third"], { cwd }); + await gitTagVersion("v1.1.1", undefined, { cwd }); + await gitCommits(["Fourth"], { cwd }); + await gitTagVersion("v1.2.0", undefined, { cwd }); + await gitPush("origin", "master", { cwd }); + await gitCheckout("1.1.x", false, { cwd }); + await merge("master", { cwd }); + await gitPush("origin", "1.1.x", { cwd }); + + const notes = "Release notes"; + const verifyConditions = stub().resolves(); + const analyzeCommits = stub().resolves(); + const verifyRelease = stub().resolves(); + const generateNotes = stub().resolves(notes); + const addChannel = stub().resolves(); + const prepare = stub().resolves(); + const publish = stub().resolves(); + const success = stub().resolves(); + const fail = stub().resolves(); + + const config = { branches: [{ name: "master" }, { name: "1.1.x" }], repositoryUrl, tagFormat: `v\${version}` }; + const options = { + ...config, + verifyConditions, + analyzeCommits, + verifyRelease, + addChannel, + generateNotes, + prepare, + publish, + success, + fail, + }; + + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "1.1.x", isPr: false })); + const semanticRelease = (await import("../index.js")).default; + const errors = [ + ...( + await t.throwsAsync( + semanticRelease(options, { cwd, env: {}, stdout: { write: () => {} }, stderr: { write: () => {} } }) + ) + ).errors, + ]; + + t.is(addChannel.callCount, 0); + + t.is(publish.callCount, 0); + + t.is(success.callCount, 0); + + t.is(fail.callCount, 1); + t.deepEqual(fail.args[0][1].errors, errors); + + t.is(errors[0].code, "EINVALIDMAINTENANCEMERGE"); + t.is(errors[0].name, "SemanticReleaseError"); + t.truthy(errors[0].message); + t.truthy(errors[0].details); +}); + +test.serial("Returns false value if triggered on an outdated clone", async (t) => { // Create a git repository, set the current working directory at the root of the repo - t.log("Create git repository and package.json"); - const { cwd, repositoryUrl } = await gitbox.createRepo(packageName); - // Create package.json in repository root - await writeJson(path.resolve(cwd, "package.json"), { - name: packageName, - version: "0.0.0-dev", - repository: { url: repositoryUrl }, - release: { verifyConditions: pluginError, fail: false, success: false }, - }); + let { cwd, repositoryUrl } = await gitRepo(true); + const repoDir = cwd; + // Add commits to the master branch + await gitCommits(["First"], { cwd }); + await gitCommits(["Second"], { cwd }); + await gitPush(repositoryUrl, "master", { cwd }); + cwd = await gitShallowClone(repositoryUrl); + await gitCommits(["Third"], { cwd }); + await gitPush(repositoryUrl, "master", { cwd }); + + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); + const semanticRelease = (await import("../index.js")).default; - /* Initial release */ - t.log("Commit a feature"); - await gitCommits(["feat: Initial commit"], { cwd }); - t.log("$ semantic-release"); - const { stderr, exitCode } = await execa(cli, [], { env, cwd, reject: false, extendEnv: false }); - // Verify the type and message are logged - t.regex(stderr, /Error: a/); - // Verify the stacktrace is logged - t.regex(stderr, new RegExp(process.platform === "win32" ? pluginError.replace(/\\/g, "\\\\") : pluginError)); - // Verify the Error properties are logged - t.regex(stderr, /errorProperty: 'errorProperty'/); - t.is(exitCode, 1); + t.false( + await semanticRelease( + { repositoryUrl }, + { cwd: repoDir, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer() } + ) + ); + t.deepEqual(t.context.log.args[t.context.log.args.length - 1], [ + "The local branch master is behind the remote one, therefore a new version won't be published.", + ]); }); -test("Log errors inheriting SemanticReleaseError and exit with 1", async (t) => { - const packageName = "test-inherited-error"; +test.serial("Returns false if not running from the configured branch", async (t) => { // Create a git repository, set the current working directory at the root of the repo - t.log("Create git repository and package.json"); - const { cwd, repositoryUrl } = await gitbox.createRepo(packageName); - // Create package.json in repository root - await writeJson(path.resolve(cwd, "package.json"), { - name: packageName, - version: "0.0.0-dev", - repository: { url: repositoryUrl }, - release: { verifyConditions: pluginInheritedError, fail: false, success: false }, - }); + const { cwd, repositoryUrl } = await gitRepo(true); + const options = { + branches: ["master"], + repositoryUrl, + verifyConditions: stub().resolves(), + analyzeCommits: stub().resolves(), + verifyRelease: stub().resolves(), + generateNotes: stub().resolves(), + addChannel: stub().resolves(), + prepare: stub().resolves(), + publish: stub().resolves(), + success: stub().resolves(), + fail: stub().resolves(), + }; - /* Initial release */ - t.log("Commit a feature"); - await gitCommits(["feat: Initial commit"], { cwd }); - t.log("$ semantic-release"); - const { stderr, exitCode } = await execa(cli, [], { env, cwd, reject: false, extendEnv: false }); - // Verify the type and message are logged - t.regex(stderr, /EINHERITED Inherited error/); - t.is(exitCode, 1); + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "other-branch", isPr: false })); + const semanticRelease = (await import("../index.js")).default; + + t.false( + await semanticRelease(options, { + cwd, + env: {}, + stdout: new WritableStreamBuffer(), + stderr: new WritableStreamBuffer(), + }) + ); + t.is( + t.context.log.args[1][0], + "This test run was triggered on the branch other-branch, while semantic-release is configured to only publish from master, therefore a new version won’t be published." + ); }); -test("Exit with 1 if missing permission to push to the remote repository", async (t) => { - const packageName = "unauthorized"; +test.serial("Returns false if there is no relevant changes", async (t) => { // Create a git repository, set the current working directory at the root of the repo - t.log("Create git repository"); - const { cwd } = await gitbox.createRepo(packageName); - await writeJson(path.resolve(cwd, "package.json"), { name: packageName, version: "0.0.0-dev" }); + const { cwd, repositoryUrl } = await gitRepo(true); + // Add commits to the master branch + await gitCommits(["First"], { cwd }); + await gitPush(repositoryUrl, "master", { cwd }); + + const analyzeCommits = stub().resolves(); + const verifyRelease = stub().resolves(); + const generateNotes = stub().resolves(); + const publish = stub().resolves(); + + const options = { + branches: ["master"], + repositoryUrl, + verifyConditions: [stub().resolves()], + analyzeCommits, + verifyRelease, + generateNotes, + addChannel: stub().resolves(), + prepare: stub().resolves(), + publish, + success: stub().resolves(), + fail: stub().resolves(), + }; - /* Initial release */ - t.log("Commit a feature"); - await gitCommits(["feat: Initial commit"], { cwd }); - await gitPush("origin", "master", { cwd }); - t.log("$ semantic-release"); - const { stderr, exitCode } = await execa( - cli, - ["--repository-url", "http://user:wrong_pass@localhost:2080/git/unauthorized.git"], - { env: { ...env, GH_TOKEN: "user:wrong_pass" }, cwd, reject: false, extendEnv: false } + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); + const semanticRelease = (await import("../index.js")).default; + + t.false( + await semanticRelease(options, { + cwd, + env: {}, + stdout: new WritableStreamBuffer(), + stderr: new WritableStreamBuffer(), + }) + ); + t.is(analyzeCommits.callCount, 1); + t.is(verifyRelease.callCount, 0); + t.is(generateNotes.callCount, 0); + t.is(publish.callCount, 0); + t.is( + t.context.log.args[t.context.log.args.length - 1][0], + "There are no relevant changes, so no new version is released." ); - // Verify the type and message are logged - t.regex(stderr, /EGITNOPERMISSION/); - t.is(exitCode, 1); }); -test("Hide sensitive environment variable values from the logs", async (t) => { - const packageName = "log-secret"; +test.serial("Exclude commits with [skip release] or [release skip] from analysis", async (t) => { // Create a git repository, set the current working directory at the root of the repo - t.log("Create git repository"); - const { cwd, repositoryUrl } = await gitbox.createRepo(packageName); - await writeJson(path.resolve(cwd, "package.json"), { - name: packageName, - version: "0.0.0-dev", - repository: { url: repositoryUrl }, - release: { verifyConditions: [pluginLogEnv], fail: false, success: false }, - }); + const { cwd, repositoryUrl } = await gitRepo(true); + // Add commits to the master branch + const commits = await gitCommits( + [ + "Test commit", + "Test commit [skip release]", + "Test commit [release skip]", + "Test commit [Release Skip]", + "Test commit [Skip Release]", + "Test commit [skip release]", + "Test commit\n\n commit body\n[skip release]", + "Test commit\n\n commit body\n[release skip]", + ], + { cwd } + ); + await gitPush(repositoryUrl, "master", { cwd }); + const analyzeCommits = stub().resolves(); + const config = { branches: ["master"], repositoryUrl, globalOpt: "global" }; + const options = { + ...config, + verifyConditions: [stub().resolves(), stub().resolves()], + analyzeCommits, + verifyRelease: stub().resolves(), + generateNotes: stub().resolves(), + addChannel: stub().resolves(), + prepare: stub().resolves(), + publish: stub().resolves(), + success: stub().resolves(), + fail: stub().resolves(), + }; - t.log("$ semantic-release"); - const { stdout, stderr } = await execa(cli, [], { - env: { ...env, MY_TOKEN: "secret token" }, + const env = {}; + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + const envCi = (await td.replaceEsm("env-ci")).default; + td.when(envCi({ env, cwd })).thenReturn({ isCi: true, branch: "master", isPr: false }); + const semanticRelease = (await import("../index.js")).default; + await semanticRelease(options, { cwd, - reject: false, - extendEnv: false, + env, + stdout: new WritableStreamBuffer(), + stderr: new WritableStreamBuffer(), }); - t.regex(stdout, new RegExp(`Console: Exposing token ${escapeRegExp(SECRET_REPLACEMENT)}`)); - t.regex(stdout, new RegExp(`Log: Exposing token ${escapeRegExp(SECRET_REPLACEMENT)}`)); - t.regex(stderr, new RegExp(`Error: Console token ${escapeRegExp(SECRET_REPLACEMENT)}`)); - t.regex(stderr, new RegExp(`Throw error: Exposing ${escapeRegExp(SECRET_REPLACEMENT)}`)); + t.is(analyzeCommits.callCount, 1); + t.is(analyzeCommits.args[0][1].commits.length, 2); + t.deepEqual(analyzeCommits.args[0][1].commits[0], commits[commits.length - 1]); }); -test("Use the valid git credentials when multiple are provided", async (t) => { - const { cwd, authUrl } = await gitbox.createRepo("test-auth"); +test.serial('Log both plugins errors and errors thrown by "fail" plugin', async (t) => { + const { cwd, repositoryUrl } = await gitRepo(true); + const pluginError = new SemanticReleaseError("Plugin error", "ERR"); + const failError1 = new Error("Fail error 1"); + const failError2 = new Error("Fail error 2"); + + const options = { + branches: ["master"], + repositoryUrl, + verifyConditions: stub().rejects(pluginError), + fail: [stub().rejects(failError1), stub().rejects(failError2)], + }; + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); + const semanticRelease = (await import("../index.js")).default; - t.is( - await getAuthUrl({ - cwd, - env: { - GITHUB_TOKEN: "dummy", - GITLAB_TOKEN: "trash", - BB_TOKEN_BASIC_AUTH: gitbox.gitCredential, - GIT_ASKPASS: "echo", - GIT_TERMINAL_PROMPT: 0, - GIT_CONFIG_PARAMETERS: "'credential.helper='", - }, - branch: { name: "master" }, - options: { repositoryUrl: "http://toto@localhost:2080/git/test-auth.git" }, - }), - authUrl + await t.throwsAsync( + semanticRelease(options, { cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer() }) ); + + t.is(t.context.error.args[t.context.error.args.length - 1][0], "ERR Plugin error"); + t.is(t.context.error.args[t.context.error.args.length - 3][1], failError1); + t.is(t.context.error.args[t.context.error.args.length - 2][1], failError2); }); -test("Use the repository URL as is if none of the given git credentials are valid", async (t) => { - const { cwd } = await gitbox.createRepo("test-invalid-auth"); - const dummyUrl = "http://toto@localhost:2080/git/test-invalid-auth.git"; +test.serial('Call "fail" only if a plugin returns a SemanticReleaseError', async (t) => { + const { cwd, repositoryUrl } = await gitRepo(true); + const pluginError = new Error("Plugin error"); + const fail = stub().resolves(); - t.is( - await getAuthUrl({ - cwd, - env: { - GITHUB_TOKEN: "dummy", - GITLAB_TOKEN: "trash", - GIT_ASKPASS: "echo", - GIT_TERMINAL_PROMPT: 0, - GIT_CONFIG_PARAMETERS: "'credential.helper='", - }, - branch: { name: "master" }, - options: { repositoryUrl: dummyUrl }, - }), - dummyUrl + const options = { + branches: ["master"], + repositoryUrl, + verifyConditions: stub().rejects(pluginError), + fail, + }; + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); + const semanticRelease = (await import("../index.js")).default; + + await t.throwsAsync( + semanticRelease(options, { cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer() }) ); + + t.true(fail.notCalled); + t.is(t.context.error.args[t.context.error.args.length - 1][1], pluginError); }); -test("ESM Plugin with named exports", async (t) => { - const packageName = "plugin-exports"; +test.serial( + "Throw SemanticReleaseError if repositoryUrl is not set and cannot be found from repo config", + async (t) => { + // Create a git repository, set the current working directory at the root of the repo + const { cwd } = await gitRepo(); + + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); + const semanticRelease = (await import("../index.js")).default; + const errors = [ + ...( + await t.throwsAsync( + semanticRelease({}, { cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer() }) + ) + ).errors, + ]; + + // Verify error code and type + t.is(errors[0].code, "ENOREPOURL"); + t.is(errors[0].name, "SemanticReleaseError"); + t.truthy(errors[0].message); + t.truthy(errors[0].details); + } +); + +test.serial("Throw an Error if plugin returns an unexpected value", async (t) => { // Create a git repository, set the current working directory at the root of the repo - t.log("Create git repository"); - const { cwd, repositoryUrl } = await gitbox.createRepo(packageName); - await writeJson(path.resolve(cwd, "package.json"), { - name: packageName, - version: "0.0.0-dev", - repository: { url: repositoryUrl }, - release: { plugins: [pluginEsmNamedExports] }, + const { cwd, repositoryUrl } = await gitRepo(true); + // Add commits to the master branch + await gitCommits(["First"], { cwd }); + // Create the tag corresponding to version 1.0.0 + await gitTagVersion("v1.0.0", undefined, { cwd }); + // Add new commits to the master branch + await gitCommits(["Second"], { cwd }); + await gitPush(repositoryUrl, "master", { cwd }); + + const verifyConditions = stub().resolves(); + const analyzeCommits = stub().resolves("string"); + + const options = { + branches: ["master"], + repositoryUrl, + verifyConditions: [verifyConditions], + analyzeCommits, + success: stub().resolves(), + fail: stub().resolves(), + }; + + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); + const semanticRelease = (await import("../index.js")).default; + + let error; + try { + await semanticRelease(options, { + cwd, + env: {}, + stdout: new WritableStreamBuffer(), + stderr: new WritableStreamBuffer(), + }); + } catch (e) { + error = e; + } + t.is(error.code, "EANALYZECOMMITSOUTPUT"); + t.regex(error.details, /string/); +}); + +test.serial('Hide sensitive information passed to "fail" plugin', async (t) => { + const { cwd, repositoryUrl } = await gitRepo(true); + + const fail = stub().resolves(); + const env = { MY_TOKEN: "secret token" }; + const options = { + branch: "master", + repositoryUrl, + verifyConditions: stub().throws( + new SemanticReleaseError( + `Message: Exposing token ${env.MY_TOKEN}`, + "ERR", + `Details: Exposing token ${env.MY_TOKEN}` + ) + ), + success: stub().resolves(), + fail, + }; + + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); + const semanticRelease = (await import("../index.js")).default; + await t.throwsAsync( + semanticRelease(options, { cwd, env, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer() }) + ); + + const error = fail.args[0][1].errors[0]; + + t.is(error.message, `Message: Exposing token ${SECRET_REPLACEMENT}`); + t.is(error.details, `Details: Exposing token ${SECRET_REPLACEMENT}`); + + Object.getOwnPropertyNames(error).forEach((prop) => { + if (isString(error[prop])) { + t.notRegex(error[prop], new RegExp(escapeRegExp(env.MY_TOKEN))); + } }); +}); - t.log("$ semantic-release"); - const { stdout, stderr } = await execa(cli, [], { - env: { ...env, MY_TOKEN: "secret token" }, - cwd, - reject: false, - extendEnv: false, +test.serial('Hide sensitive information passed to "success" plugin', async (t) => { + const { cwd, repositoryUrl } = await gitRepo(true); + await gitCommits(["feat: initial release"], { cwd }); + await gitTagVersion("v1.0.0", undefined, { cwd }); + await gitCommits(["feat: new feature"], { cwd }); + await gitPush(repositoryUrl, "master", { cwd }); + + const success = stub().resolves(); + const env = { MY_TOKEN: "secret token" }; + const options = { + branch: "master", + repositoryUrl, + verifyConditions: false, + verifyRelease: false, + prepare: false, + generateNotes: stub().resolves(`Exposing token ${env.MY_TOKEN}`), + publish: stub().resolves({ + name: `Name: Exposing token ${env.MY_TOKEN}`, + url: `URL: Exposing token ${env.MY_TOKEN}`, + }), + addChannel: false, + success, + fail: stub().resolves(), + }; + + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); + const semanticRelease = (await import("../index.js")).default; + await semanticRelease(options, { cwd, env, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer() }); + + const release = success.args[0][1].releases[0]; + + t.is(release.name, `Name: Exposing token ${SECRET_REPLACEMENT}`); + t.is(release.url, `URL: Exposing token ${SECRET_REPLACEMENT}`); + + Object.getOwnPropertyNames(release).forEach((prop) => { + if (isString(release[prop])) { + t.notRegex(release[prop], new RegExp(escapeRegExp(env.MY_TOKEN))); + } }); +}); + +test.serial("Get all commits including the ones not in the shallow clone", async (t) => { + let { cwd, repositoryUrl } = await gitRepo(true); + await gitTagVersion("v1.0.0", undefined, { cwd }); + await gitCommits(["First", "Second", "Third"], { cwd }); + await gitPush(repositoryUrl, "master", { cwd }); + + cwd = await gitShallowClone(repositoryUrl); + + const nextRelease = { + name: "v2.0.0", + type: "major", + version: "2.0.0", + gitHead: await getGitHead({ cwd }), + gitTag: "v2.0.0", + channel: undefined, + }; + const notes = "Release notes"; + const analyzeCommits = stub().resolves(nextRelease.type); + + const config = { branches: ["master"], repositoryUrl, globalOpt: "global" }; + const options = { + ...config, + verifyConditions: stub().resolves(), + analyzeCommits, + verifyRelease: stub().resolves(), + generateNotes: stub().resolves(notes), + prepare: stub().resolves(), + publish: stub().resolves(), + success: stub().resolves(), + fail: stub().resolves(), + }; + + await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger); + await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false })); + const semanticRelease = (await import("../index.js")).default; + t.truthy( + await semanticRelease(options, { + cwd, + env: {}, + stdout: new WritableStreamBuffer(), + stderr: new WritableStreamBuffer(), + }) + ); - t.regex(stdout, new RegExp(`verifyConditions called`)); + t.is(analyzeCommits.args[0][1].commits.length, 3); });