diff --git a/.commitlintrc.js b/.commitlintrc.js index e9c80b92..b706e527 100644 --- a/.commitlintrc.js +++ b/.commitlintrc.js @@ -7,5 +7,6 @@ module.exports = { 'header-max-length': [2, 'always', 80], 'subject-case': [0], 'body-max-line-length': [0], + 'footer-max-line-length': [0], }, } diff --git a/.github/actions/create-check/action.yml b/.github/actions/create-check/action.yml index aa24a5b0..d1220c90 100644 --- a/.github/actions/create-check/action.yml +++ b/.github/actions/create-check/action.yml @@ -25,7 +25,7 @@ runs: with: result-encoding: string script: | - const { repo: { owner, repo}, runId, serverUrl } = context + const { repo: { owner, repo}, runId, serverUrl } = context const { JOB_NAME, SHA } = process.env const job = await github.rest.actions.listJobsForWorkflowRun({ diff --git a/.github/actions/install-latest-npm/action.yml b/.github/actions/install-latest-npm/action.yml index 8339dbf0..580603dd 100644 --- a/.github/actions/install-latest-npm/action.yml +++ b/.github/actions/install-latest-npm/action.yml @@ -44,7 +44,7 @@ runs: MATCH=$SPEC echo "Found compatible version: npm@$MATCH" break - fi + fi done if [ -z $MATCH ]; then diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index 24539905..f6ab948b 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -61,7 +61,7 @@ jobs: run: npm run postlint --ignore-scripts - name: Conclude Check uses: LouisBrunner/checks-action@v1.6.0 - if: always() + if: steps.create-check.outputs.check-id && always() with: token: ${{ secrets.GITHUB_TOKEN }} conclusion: ${{ job.status }} @@ -151,7 +151,7 @@ jobs: run: npm test --ignore-scripts - name: Conclude Check uses: LouisBrunner/checks-action@v1.6.0 - if: always() + if: steps.create-check.outputs.check-id && always() with: token: ${{ secrets.GITHUB_TOKEN }} conclusion: ${{ job.status }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 3741af66..f8b17025 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -31,8 +31,8 @@ jobs: git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: javascript - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/post-dependabot.yml b/.github/workflows/post-dependabot.yml index a7ebe12d..1ea8693c 100644 --- a/.github/workflows/post-dependabot.yml +++ b/.github/workflows/post-dependabot.yml @@ -49,7 +49,7 @@ jobs: id: flags run: | dependabot_dir="${{ steps.metadata.outputs.directory }}" - if [[ "$dependabot_dir" == "/" ]]; then + if [[ "$dependabot_dir" == "/" || "$dependabot_dir" == "/main" ]]; then echo "workspace=-iwr" >> $GITHUB_OUTPUT else # strip leading slash from directory so it works as a diff --git a/.gitignore b/.gitignore index ff56062c..ac3c1dad 100644 --- a/.gitignore +++ b/.gitignore @@ -2,17 +2,17 @@ # ignore everything in the root /* -# transient test directories -tap-testdir*/ -# keep these !**/.gitignore !/.commitlintrc.js !/.eslintrc.js !/.eslintrc.local.* +!/.git-blame-ignore-revs !/.github/ !/.gitignore !/.npmrc +!/.prettierignore +!/.prettierrc.js !/.release-please-manifest.json !/benchmarks !/bin/ @@ -38,3 +38,4 @@ tap-testdir*/ !/tap-snapshots/ !/test/ !/tsconfig.json +tap-testdir*/ diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b637db6f..6a15549e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "7.6.3" + ".": "7.7.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 4910123d..b4ddfe57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [7.7.0](https://github.com/npm/node-semver/compare/v7.6.3...v7.7.0) (2025-01-29) +### Features +* [`0864b3c`](https://github.com/npm/node-semver/commit/0864b3ce7932667013e0c7c5ec764777d4682883) [#753](https://github.com/npm/node-semver/pull/753) add "release" inc type (#753) (@mbtools) +### Bug Fixes +* [`d588e37`](https://github.com/npm/node-semver/commit/d588e3782864b1cab2fe9f2452b848e8c7f609d1) [#755](https://github.com/npm/node-semver/pull/755) diff: fix prerelease to stable version diff logic (#755) (@eminberkayd, berkay.daglar) +* [`8a34bde`](https://github.com/npm/node-semver/commit/8a34bdecc783407f4e1a8a1ee1f67906b84a4b78) [#754](https://github.com/npm/node-semver/pull/754) add identifier validation to `inc()` (#754) (@mbtools) +### Documentation +* [`67e5478`](https://github.com/npm/node-semver/commit/67e54785a0f871361230f84323cbb631b9b6d834) [#756](https://github.com/npm/node-semver/pull/756) readme: added missing period for consistency (#756) (@shaymolcho) +* [`868d4bb`](https://github.com/npm/node-semver/commit/868d4bbe3d318c52544f38d5f9977a1103e924c2) [#749](https://github.com/npm/node-semver/pull/749) clarify comment about obsolete prefixes (#749) (@mbtools, @ljharb) +### Chores +* [`145c554`](https://github.com/npm/node-semver/commit/145c554b8c7b7ecfcb451153ad18bdb2f24ad10d) [#741](https://github.com/npm/node-semver/pull/741) bump @npmcli/eslint-config from 4.0.5 to 5.0.0 (@dependabot[bot]) +* [`753e02b`](https://github.com/npm/node-semver/commit/753e02b9d0cb3ac23e085dc33efcab3e08d61f2b) [#747](https://github.com/npm/node-semver/pull/747) bump @npmcli/template-oss from 4.23.3 to 4.23.4 (#747) (@dependabot[bot], @npm-cli-bot) +* [`0b812d5`](https://github.com/npm/node-semver/commit/0b812d5fb5fbb208e89dc1250e2efafeaa549437) [#744](https://github.com/npm/node-semver/pull/744) postinstall for dependabot template-oss PR (@hashtagchris) + ## [7.6.3](https://github.com/npm/node-semver/compare/v7.6.2...v7.6.3) (2024-07-16) ### Bug Fixes diff --git a/README.md b/README.md index ede7b7d0..e9522153 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ Options: -i --increment [] Increment a version by the specified level. Level can be one of: major, minor, patch, premajor, preminor, - prepatch, or prerelease. Default level is 'patch'. + prepatch, prerelease, or release. Default level is 'patch'. Only one version may be specified. --preid @@ -141,6 +141,8 @@ A "version" is described by the `v2.0.0` specification found at . A leading `"="` or `"v"` character is stripped off and ignored. +Support for stripping a leading "v" is kept for compatibility with `v1.0.0` of the SemVer +specification but should not be used anymore. ## Ranges @@ -237,6 +239,13 @@ $ semver 1.2.4-beta.0 -i prerelease 1.2.4-beta.1 ``` +To get out of the prerelease phase, use the `release` option: + +```bash +$ semver 1.2.4-beta.1 -i release +1.2.4 +``` + #### Prerelease Identifier Base The method `.inc` takes an optional parameter 'identifierBase' string @@ -415,10 +424,10 @@ Strict-mode Comparators and Ranges will be strict about the SemVer strings that they parse. * `valid(v)`: Return the parsed version, or null if it's not valid. -* `inc(v, release, options, identifier, identifierBase)`: +* `inc(v, releaseType, options, identifier, identifierBase)`: Return the version incremented by the release type (`major`, `premajor`, `minor`, `preminor`, `patch`, - `prepatch`, or `prerelease`), or null if it's not valid + `prepatch`, `prerelease`, or `release`), or null if it's not valid * `premajor` in one call will bump the version up to the next major version and down to a prerelease of that major version. `preminor`, and `prepatch` work the same way. @@ -426,6 +435,7 @@ strings that they parse. same as `prepatch`. It increments the patch version and then makes a prerelease. If the input version is already a prerelease it simply increments it. + * `release` will remove any prerelease part of the version. * `identifier` can be used to prefix `premajor`, `preminor`, `prepatch`, or `prerelease` version increments. `identifierBase` is the base to be used for the `prerelease` identifier. @@ -477,7 +487,7 @@ strings that they parse. ### Ranges -* `validRange(range)`: Return the valid range or null if it's not valid +* `validRange(range)`: Return the valid range or null if it's not valid. * `satisfies(version, range)`: Return true if the version satisfies the range. * `maxSatisfying(versions, range)`: Return the highest version in the list diff --git a/SECURITY.md b/SECURITY.md index 9cd2deaf..4fe06a2a 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,7 @@ GitHub takes the security of our software products and services seriously, including the open source code repositories managed through our GitHub organizations, such as [GitHub](https://github.com/GitHub). -If you believe you have found a security vulnerability in this GitHub-owned open source repository, you can report it to us in one of two ways. +If you believe you have found a security vulnerability in this GitHub-owned open source repository, you can report it to us in one of two ways. If the vulnerability you have found is *not* [in scope for the GitHub Bug Bounty Program](https://bounty.github.com/#scope) or if you do not wish to be considered for a bounty reward, please report the issue to us directly through [opensource-security@github.com](mailto:opensource-security@github.com). diff --git a/bin/semver.js b/bin/semver.js index f62b566f..22fc76ea 100755 --- a/bin/semver.js +++ b/bin/semver.js @@ -61,6 +61,7 @@ const main = () => { switch (argv[0]) { case 'major': case 'minor': case 'patch': case 'prerelease': case 'premajor': case 'preminor': case 'prepatch': + case 'release': inc = argv.shift() break default: @@ -149,7 +150,7 @@ Options: -i --increment [] Increment a version by the specified level. Level can be one of: major, minor, patch, premajor, preminor, - prepatch, or prerelease. Default level is 'patch'. + prepatch, prerelease, or release. Default level is 'patch'. Only one version may be specified. --preid diff --git a/classes/semver.js b/classes/semver.js index 13e66ce4..97049a40 100644 --- a/classes/semver.js +++ b/classes/semver.js @@ -10,7 +10,7 @@ class SemVer { if (version instanceof SemVer) { if (version.loose === !!options.loose && - version.includePrerelease === !!options.includePrerelease) { + version.includePrerelease === !!options.includePrerelease) { return version } else { version = version.version @@ -176,6 +176,19 @@ class SemVer { // preminor will bump the version up to the next minor release, and immediately // down to pre-release. premajor and prepatch work the same way. inc (release, identifier, identifierBase) { + if (release.startsWith('pre')) { + if (!identifier && identifierBase === false) { + throw new Error('invalid increment argument: identifier is empty') + } + // Avoid an invalid semver results + if (identifier) { + const match = `-${identifier}`.match(this.options.loose ? re[t.PRERELEASELOOSE] : re[t.PRERELEASE]) + if (!match || match[1] !== identifier) { + throw new Error(`invalid identifier: ${identifier}`) + } + } + } + switch (release) { case 'premajor': this.prerelease.length = 0 @@ -206,6 +219,12 @@ class SemVer { } this.inc('pre', identifier, identifierBase) break + case 'release': + if (this.prerelease.length === 0) { + throw new Error(`version ${this.raw} is not a prerelease`) + } + this.prerelease.length = 0 + break case 'major': // If this is a pre-major version, bump up to the same major version. @@ -249,10 +268,6 @@ class SemVer { case 'pre': { const base = Number(identifierBase) ? 1 : 0 - if (!identifier && identifierBase === false) { - throw new Error('invalid increment argument: identifier is empty') - } - if (this.prerelease.length === 0) { this.prerelease = [base] } else { diff --git a/functions/diff.js b/functions/diff.js index fc224e30..33171dc1 100644 --- a/functions/diff.js +++ b/functions/diff.js @@ -27,20 +27,13 @@ const diff = (version1, version2) => { return 'major' } - // Otherwise it can be determined by checking the high version - - if (highVersion.patch) { - // anything higher than a patch bump would result in the wrong version + // If the main part has no difference + if (lowVersion.compareMain(highVersion) === 0) { + if (lowVersion.minor && !lowVersion.patch) { + return 'minor' + } return 'patch' } - - if (highVersion.minor) { - // anything higher than a minor bump would result in the wrong version - return 'minor' - } - - // bumping major/minor/patch all have same result - return 'major' } // add the `pre` prefix if we are going to a prerelease version diff --git a/package.json b/package.json index 663d3701..405fb66e 100644 --- a/package.json +++ b/package.json @@ -1,20 +1,21 @@ { "name": "semver", - "version": "7.6.3", + "version": "7.7.0", "description": "The semantic version parser used by npm.", "main": "index.js", "scripts": { "test": "tap", "snap": "tap", - "lint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"", + "lint": "npm run eslint", "postlint": "template-oss-check", - "lintfix": "npm run lint -- --fix", + "lintfix": "npm run eslint -- --fix", "posttest": "npm run lint", - "template-oss-apply": "template-oss-apply --force" + "template-oss-apply": "template-oss-apply --force", + "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"" }, "devDependencies": { - "@npmcli/eslint-config": "^4.0.0", - "@npmcli/template-oss": "4.22.0", + "@npmcli/eslint-config": "^5.0.0", + "@npmcli/template-oss": "4.23.4", "benchmark": "^2.1.4", "tap": "^16.0.0" }, @@ -51,7 +52,7 @@ "author": "GitHub Inc.", "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.22.0", + "version": "4.23.4", "engines": ">=10", "distPaths": [ "classes/", diff --git a/tap-snapshots/test/bin/semver.js.test.cjs b/tap-snapshots/test/bin/semver.js.test.cjs index e820ca47..4938f10d 100644 --- a/tap-snapshots/test/bin/semver.js.test.cjs +++ b/tap-snapshots/test/bin/semver.js.test.cjs @@ -70,7 +70,7 @@ Object { -i --increment [] Increment a version by the specified level. Level can be one of: major, minor, patch, premajor, preminor, - prepatch, or prerelease. Default level is 'patch'. + prepatch, prerelease, or release. Default level is 'patch'. Only one version may be specified. --preid @@ -131,7 +131,7 @@ Object { -i --increment [] Increment a version by the specified level. Level can be one of: major, minor, patch, premajor, preminor, - prepatch, or prerelease. Default level is 'patch'. + prepatch, prerelease, or release. Default level is 'patch'. Only one version may be specified. --preid @@ -192,7 +192,7 @@ Object { -i --increment [] Increment a version by the specified level. Level can be one of: major, minor, patch, premajor, preminor, - prepatch, or prerelease. Default level is 'patch'. + prepatch, prerelease, or release. Default level is 'patch'. Only one version may be specified. --preid @@ -253,7 +253,7 @@ Object { -i --increment [] Increment a version by the specified level. Level can be one of: major, minor, patch, premajor, preminor, - prepatch, or prerelease. Default level is 'patch'. + prepatch, prerelease, or release. Default level is 'patch'. Only one version may be specified. --preid @@ -348,6 +348,15 @@ Object { } ` +exports[`test/bin/semver.js TAP inc tests > -i release 1.0.0-pre`] = ` +Object { + "code": 0, + "err": "", + "out": "1.0.0\\n", + "signal": null, +} +` + exports[`test/bin/semver.js TAP sorting and filtering > 1.2.3 -v 3.2.1 --version 2.3.4 -rv 1`] = ` Object { "code": 0, diff --git a/test/classes/semver.js b/test/classes/semver.js index 85a0ec31..946fa417 100644 --- a/test/classes/semver.js +++ b/test/classes/semver.js @@ -106,6 +106,34 @@ test('incrementing', t => { })) }) +test('invalid increments', (t) => { + t.throws( + () => new SemVer('1.2.3').inc('prerelease', '', false), + Error('invalid increment argument: identifier is empty') + ) + t.throws( + () => new SemVer('1.2.3-dev').inc('prerelease', 'dev', false), + Error('invalid increment argument: identifier already exists') + ) + t.throws( + () => new SemVer('1.2.3').inc('prerelease', 'invalid/preid'), + Error('invalid identifier: invalid/preid') + ) + + t.end() +}) + +test('increment side-effects', (t) => { + const v = new SemVer('1.0.0') + try { + v.inc('prerelease', 'hot/mess') + } catch (er) { + // ignore but check that the version has not changed + } + t.equal(v.toString(), '1.0.0') + t.end() +}) + test('compare main vs pre', (t) => { const s = new SemVer('1.2.3') t.equal(s.compareMain('2.3.4'), -1) diff --git a/test/fixtures/increments.js b/test/fixtures/increments.js index 65e9530b..a9b06358 100644 --- a/test/fixtures/increments.js +++ b/test/fixtures/increments.js @@ -40,7 +40,12 @@ module.exports = [ ['1.2.3-1', 'premajor', '2.0.0-0'], ['1.2.0-1', 'minor', '1.2.0'], ['1.0.0-1', 'major', '1.0.0'], + ['1.0.0-1', 'release', '1.0.0'], + ['1.2.0-1', 'release', '1.2.0'], + ['1.2.3-1', 'release', '1.2.3'], + ['1.2.3', 'release', null], + // [version, inc, result, identifierIndex, loose, identifier] ['1.2.3', 'major', '2.0.0', false, 'dev'], ['1.2.3', 'minor', '1.3.0', false, 'dev'], ['1.2.3', 'patch', '1.2.4', false, 'dev'], @@ -88,7 +93,7 @@ module.exports = [ ['1.2.3-1.1', 'prerelease', '1.2.3-1.2', false, '1'], ['1.2.3-1.1', 'prerelease', '1.2.3-2.0', false, '2'], - // [version, inc, result, identifierIndex, loose, identifier] + // [version, inc, result, identifierIndex, loose, identifier, identifierBase] ['1.2.0-1', 'prerelease', '1.2.0-alpha.0', false, 'alpha', '0'], ['1.2.1', 'prerelease', '1.2.2-alpha.0', false, 'alpha', '0'], ['0.2.0', 'prerelease', '0.2.1-alpha.0', false, 'alpha', '0'], @@ -124,4 +129,7 @@ module.exports = [ ['1.2.0-dev', 'prepatch', '1.2.1-dev', false, 'dev', false], ['1.2.0', 'prerelease', null, false, '', false], ['1.0.0-rc.1+build.4', 'prerelease', '1.0.0-rc.2', 'rc', false], + ['1.2.0', 'prerelease', null, false, 'invalid/preid'], + ['1.2.0', 'prerelease', null, false, 'invalid+build'], + ['1.2.0beta', 'prerelease', null, { loose: true }, 'invalid/preid'], ] diff --git a/test/functions/diff.js b/test/functions/diff.js index 720e159b..80f5e3c3 100644 --- a/test/functions/diff.js +++ b/test/functions/diff.js @@ -34,6 +34,13 @@ test('diff versions test', (t) => { ['1.0.0-1', '2.0.0-1', 'premajor'], ['1.0.0-1', '1.1.0-1', 'preminor'], ['1.0.0-1', '1.0.1-1', 'prepatch'], + ['1.7.2-1', '1.8.1', 'minor'], + ['1.1.1-pre', '2.1.1-pre', 'premajor'], + ['1.1.1-pre', '2.1.1', 'major'], + ['1.2.3-1', '1.2.3', 'patch'], + ['1.4.0-1', '2.3.5', 'major'], + ['1.6.1-5', '1.7.2', 'minor'], + ['2.0.0-1', '2.1.1', 'major'], ].forEach((v) => { const version1 = v[0] const version2 = v[1]