commit-and-tag-version
Advanced tools
Comparing version
@@ -5,2 +5,10 @@ # Changelog | ||
## [11.2.4](https://github.com/absolute-version/commit-and-tag-version/compare/v11.2.3...v11.2.4) (2023-10-02) | ||
### Bug Fixes | ||
* allow bump task to handle versions with build metadata ([33913ee](https://github.com/absolute-version/commit-and-tag-version/commit/33913ee03bff2dfc26c9ffc942e1191c1f767949)) | ||
* handle invalid versions passed to releaseAs ([33913ee](https://github.com/absolute-version/commit-and-tag-version/commit/33913ee03bff2dfc26c9ffc942e1191c1f767949)) | ||
## [11.2.3](https://github.com/absolute-version/commit-and-tag-version/compare/v11.2.2...v11.2.3) (2023-08-22) | ||
@@ -7,0 +15,0 @@ |
@@ -23,12 +23,42 @@ 'use strict' | ||
if (args.skip.bump) return version | ||
if (args.releaseAs && !(['major', 'minor', 'patch'].includes(args.releaseAs.toLowerCase()) || semver.valid(args.releaseAs))) { | ||
throw new Error("releaseAs must be one of 'major', 'minor' or 'patch', or a valid semvar version.") | ||
} | ||
let newVersion = version | ||
await runLifecycleScript(args, 'prerelease') | ||
const stdout = await runLifecycleScript(args, 'prebump') | ||
if (stdout && stdout.trim().length) args.releaseAs = stdout.trim() | ||
const release = await bumpVersion(args.releaseAs, version, args) | ||
if (stdout?.trim().length) { | ||
const prebumpString = stdout.trim() | ||
if (semver.valid(prebumpString)) args.releaseAs = prebumpString | ||
} | ||
if (!args.firstRelease) { | ||
const releaseType = getReleaseType(args.prerelease, release.releaseType, version) | ||
const releaseTypeAsVersion = releaseType === 'pre' + release.releaseType ? semver.valid(release.releaseType + '-' + args.prerelease + '.0') : semver.valid(releaseType) | ||
if (semver.valid(args.releaseAs)) { | ||
const releaseAs = new semver.SemVer(args.releaseAs) | ||
if (isString(args.prerelease) && releaseAs.prerelease.length && releaseAs.prerelease.slice(0, -1).join('.') !== args.prerelease) { | ||
// If both releaseAs and the prerelease identifier are supplied, they must match. The behavior | ||
// for a mismatch is undefined, so error out instead. | ||
throw new Error('releaseAs and prerelease have conflicting prerelease identifiers') | ||
} else if (isString(args.prerelease) && releaseAs.prerelease.length) { | ||
newVersion = releaseAs.version | ||
} else if (isString(args.prerelease)) { | ||
newVersion = `${releaseAs.major}.${releaseAs.minor}.${releaseAs.patch}-${args.prerelease}.0` | ||
} else { | ||
newVersion = releaseAs.version | ||
} | ||
newVersion = releaseTypeAsVersion || semver.inc(version, releaseType, args.prerelease) | ||
// Check if the previous version is the same version and prerelease, and increment if so | ||
if (isString(args.prerelease) && ['prerelease', null].includes(semver.diff(version, newVersion)) && semver.lte(newVersion, version)) { | ||
newVersion = semver.inc(version, 'prerelease', args.prerelease) | ||
} | ||
// Append any build info from releaseAs | ||
newVersion = semvarToVersionStr(newVersion, releaseAs.build) | ||
} else { | ||
const release = await bumpVersion(args.releaseAs, version, args) | ||
const releaseType = getReleaseType(args.prerelease, release.releaseType, version) | ||
newVersion = semver.inc(version, releaseType, args.prerelease) | ||
} | ||
updateConfigs(args, newVersion) | ||
@@ -46,2 +76,12 @@ } else { | ||
/** | ||
* Convert a semver object to a full version string including build metadata | ||
* @param {string} semverVersion The semvar version string | ||
* @param {string[]} semverBuild An array of the build metadata elements, to be joined with '.' | ||
* @returns {string} | ||
*/ | ||
function semvarToVersionStr (semverVersion, semverBuild) { | ||
return [semverVersion, semverBuild.join('.')].filter(Boolean).join('+') | ||
} | ||
function getReleaseType (prerelease, expectedReleaseType, currentVersion) { | ||
@@ -48,0 +88,0 @@ if (isString(prerelease)) { |
{ | ||
"name": "commit-and-tag-version", | ||
"version": "11.2.3", | ||
"version": "11.2.4", | ||
"description": "replacement for `npm version` with automatic CHANGELOG generation", | ||
@@ -59,2 +59,3 @@ "bin": "bin/cli.js", | ||
"chai": "^4.2.0", | ||
"chai-as-promised": "^7.1.1", | ||
"eslint": "^8.16.0", | ||
@@ -61,0 +62,0 @@ "eslint-config-standard": "^17.0.0", |
@@ -11,3 +11,5 @@ /* global describe it beforeEach afterEach */ | ||
require('chai').should() | ||
const chai = require('chai') | ||
const expect = chai.expect | ||
chai.use(require('chai-as-promised')) | ||
@@ -172,10 +174,5 @@ function exec () { | ||
fs.writeFileSync('.versionrc.js', 'module.exports = 3', 'utf-8') | ||
try { | ||
await exec() | ||
/* istanbul ignore next */ | ||
throw new Error('Unexpected success') | ||
} catch (error) { | ||
error.message.should.match(/Invalid configuration/) | ||
} | ||
expect(exec).to.throw(/Invalid configuration/) | ||
}) | ||
}) |
@@ -17,3 +17,6 @@ /* global describe it afterEach */ | ||
const should = require('chai').should() | ||
const chai = require('chai') | ||
const should = chai.should() | ||
const expect = chai.expect | ||
chai.use(require('chai-as-promised')) | ||
@@ -161,8 +164,3 @@ // set by mock() | ||
getPackageVersion().should.equal('1.1.0') | ||
try { | ||
fs.readFileSync('CHANGELOG.md', 'utf-8') | ||
throw new Error('File should not exist') | ||
} catch (err) { | ||
err.code.should.equal('ENOENT') | ||
} | ||
expect(() => fs.readFileSync('CHANGELOG.md', 'utf-8')).to.throw(/ENOENT/) | ||
}) | ||
@@ -222,8 +220,3 @@ }) | ||
mock({ bump: 'minor', fs: { 'CHANGELOG.md': '' } }) | ||
try { | ||
await exec('--changelogHeader="## 3.0.2"') | ||
throw new Error('That should not have worked') | ||
} catch (error) { | ||
error.message.should.match(/custom changelog header must not match/) | ||
} | ||
expect(exec('--changelogHeader="## 3.0.2"')).to.be.rejectedWith(/custom changelog header must not match/) | ||
}) | ||
@@ -255,13 +248,7 @@ }) | ||
try { | ||
await exec({ | ||
scripts: { | ||
prerelease: "node -e \"throw new Error('prerelease' + ' fail')\"" | ||
} | ||
}) | ||
/* istanbul ignore next */ | ||
throw new Error('Unexpected success') | ||
} catch (error) { | ||
error.message.should.match(/prerelease fail/) | ||
} | ||
expect(exec({ | ||
scripts: { | ||
prerelease: "node -e \"throw new Error('prerelease' + ' fail')\"" | ||
} | ||
})).to.be.rejectedWith(/prerelease fail/) | ||
}) | ||
@@ -284,3 +271,46 @@ }) | ||
stdout.join('').should.match(/9\.9\.9/) | ||
getPackageVersion().should.equal('9.9.9') | ||
}) | ||
it('should not allow prebump hook to return a releaseAs command', async function () { | ||
mock({ | ||
bump: 'minor', | ||
fs: { 'CHANGELOG.md': 'legacy header format<a name="1.0.0">\n' } | ||
}) | ||
await exec({ | ||
scripts: { | ||
prebump: "node -e \"console.log('major')\"" | ||
} | ||
}) | ||
getPackageVersion().should.equal('1.1.0') | ||
}) | ||
it('should allow prebump hook to return an arbitrary string', async function () { | ||
mock({ | ||
bump: 'minor', | ||
fs: { 'CHANGELOG.md': 'legacy header format<a name="1.0.0">\n' } | ||
}) | ||
await exec({ | ||
scripts: { | ||
prebump: "node -e \"console.log('Hello World')\"" | ||
} | ||
}) | ||
getPackageVersion().should.equal('1.1.0') | ||
}) | ||
it('should allow prebump hook to return a version with build info', async function () { | ||
mock({ | ||
bump: 'minor', | ||
fs: { 'CHANGELOG.md': 'legacy header format<a name="1.0.0">\n' } | ||
}) | ||
await exec({ | ||
scripts: { | ||
prebump: "node -e \"console.log('9.9.9-test+build')\"" | ||
} | ||
}) | ||
getPackageVersion().should.equal('9.9.9-test+build') | ||
}) | ||
}) | ||
@@ -310,14 +340,8 @@ | ||
try { | ||
await exec({ | ||
scripts: { | ||
postbump: "node -e \"throw new Error('postbump' + ' fail')\"" | ||
} | ||
}) | ||
await exec('--patch') | ||
/* istanbul ignore next */ | ||
throw new Error('Unexpected success') | ||
} catch (error) { | ||
error.message.should.match(/postbump fail/) | ||
} | ||
expect(exec({ | ||
scripts: { | ||
postbump: "node -e \"throw new Error('postbump' + ' fail')\"" | ||
} | ||
})).to.be.rejectedWith(/postbump fail/) | ||
expect(exec('--patch')).to.be.rejectedWith(/postbump fail/) | ||
}) | ||
@@ -354,2 +378,8 @@ }) | ||
}) | ||
it('exits with error if an invalid release type is provided', async function () { | ||
mock({ bump: 'minor', fs: { 'CHANGELOG.md': '' } }) | ||
expect(exec('--release-as invalid')).to.be.rejectedWith(/releaseAs must be one of/) | ||
}) | ||
}) | ||
@@ -405,8 +435,56 @@ | ||
pkg: { | ||
version: '100.0.0-amazing.0' | ||
version: '100.0.0-amazing.1' | ||
} | ||
}) | ||
await exec('--release-as 100.0.0-amazing.0 --prerelease amazing') | ||
should.equal(getPackageVersion(), '100.0.0-amazing.1') | ||
should.equal(getPackageVersion(), '100.0.0-amazing.2') | ||
}) | ||
it('release 100.0.0 with prerelease amazing correctly sets version', async function () { | ||
mock({ | ||
bump: 'patch', | ||
fs: { 'CHANGELOG.md': 'legacy header format<a name="100.0.0-amazing.0">\n' }, | ||
pkg: { | ||
version: '99.0.0-amazing.0' | ||
} | ||
}) | ||
await exec('--release-as 100.0.0 --prerelease amazing') | ||
should.equal(getPackageVersion(), '100.0.0-amazing.0') | ||
}) | ||
it('release 100.0.0-amazing.0 with prerelease amazing correctly sets version', async function () { | ||
mock({ | ||
bump: 'patch', | ||
fs: { 'CHANGELOG.md': 'legacy header format<a name="100.0.0-amazing.0">\n' }, | ||
pkg: { | ||
version: '99.0.0-amazing.0' | ||
} | ||
}) | ||
await exec('--release-as 100.0.0-amazing.0 --prerelease amazing') | ||
should.equal(getPackageVersion(), '100.0.0-amazing.0') | ||
}) | ||
it('release 100.0.0-amazing.0 with prerelease amazing retains build metadata', async function () { | ||
mock({ | ||
bump: 'patch', | ||
fs: { 'CHANGELOG.md': 'legacy header format<a name="100.0.0-amazing.0">\n' }, | ||
pkg: { | ||
version: '100.0.0-amazing.0' | ||
} | ||
}) | ||
await exec('--release-as 100.0.0-amazing.0+build.1234 --prerelease amazing') | ||
should.equal(getPackageVersion(), '100.0.0-amazing.1+build.1234') | ||
}) | ||
it('release 100.0.0-amazing.3 with prerelease amazing correctly sets prerelease version', async function () { | ||
mock({ | ||
bump: 'patch', | ||
fs: { 'CHANGELOG.md': 'legacy header format<a name="100.0.0-amazing.0">\n' }, | ||
pkg: { | ||
version: '100.0.0-amazing.0' | ||
} | ||
}) | ||
await exec('--release-as 100.0.0-amazing.3 --prerelease amazing') | ||
should.equal(getPackageVersion(), '100.0.0-amazing.3') | ||
}) | ||
}) | ||
@@ -438,2 +516,15 @@ | ||
}) | ||
it('exits with error if an invalid release version is provided', async function () { | ||
mock({ bump: 'minor', fs: { 'CHANGELOG.md': '' } }) | ||
expect(exec('--release-as 10.2')).to.be.rejectedWith(/releaseAs must be one of/) | ||
}) | ||
it('exits with error if release version conflicts with prerelease', async function () { | ||
mock({ bump: 'minor', fs: { 'CHANGELOG.md': '' } }) | ||
expect(exec('--release-as 1.2.3-amazing.2 --prerelease awesome')).to.be | ||
.rejectedWith(/releaseAs and prerelease have conflicting prerelease identifiers/) | ||
}) | ||
}) | ||
@@ -490,9 +581,4 @@ | ||
mock({ bump: new Error('bump err') }) | ||
try { | ||
await exec() | ||
/* istanbul ignore next */ | ||
throw new Error('Unexpected success') | ||
} catch (err) { | ||
err.message.should.match(/bump err/) | ||
} | ||
expect(exec()).to.be.rejectedWith(/bump err/) | ||
}) | ||
@@ -502,9 +588,4 @@ | ||
mock({ bump: 'minor', changelog: new Error('changelog err') }) | ||
try { | ||
await exec() | ||
/* istanbul ignore next */ | ||
throw new Error('Unexpected success') | ||
} catch (err) { | ||
err.message.should.match(/changelog err/) | ||
} | ||
expect(exec()).to.be.rejectedWith(/changelog err/) | ||
}) | ||
@@ -514,9 +595,4 @@ | ||
mock({ bump: 'patch', pkg: false }) | ||
try { | ||
await exec({ gitTagFallback: false }) | ||
/* istanbul ignore next */ | ||
throw new Error('Unexpected success') | ||
} catch (err) { | ||
err.message.should.equal('no package file found') | ||
} | ||
expect(exec({ gitTagFallback: false })).to.be.rejectedWith('no package file found') | ||
}) | ||
@@ -895,2 +971,3 @@ | ||
const gitArgs = [['add', 'CHANGELOG.md', 'package.json']] | ||
const gitError = new Error('Command failed: git\nfailed add') | ||
const execFile = (_args, cmd, cmdArgs) => { | ||
@@ -900,4 +977,5 @@ cmd.should.equal('git') | ||
cmdArgs.should.deep.equal(expected) | ||
if (expected[0] === 'add') { | ||
return Promise.reject(new Error('Command failed: git\nfailed add')) | ||
return Promise.reject(gitError) | ||
} | ||
@@ -908,9 +986,3 @@ return Promise.resolve('') | ||
try { | ||
await exec({}, true) | ||
/* istanbul ignore next */ | ||
throw new Error('Unexpected success') | ||
} catch (error) { | ||
error.message.should.match(/failed add/) | ||
} | ||
expect(exec({}, true)).to.be.rejectedWith(gitError) | ||
}) | ||
@@ -923,2 +995,3 @@ | ||
] | ||
const gitError = new Error('Command failed: git\nfailed commit') | ||
const execFile = (_args, cmd, cmdArgs) => { | ||
@@ -929,3 +1002,3 @@ cmd.should.equal('git') | ||
if (expected[0] === 'commit') { | ||
return Promise.reject(new Error('Command failed: git\nfailed commit')) | ||
return Promise.reject(gitError) | ||
} | ||
@@ -936,9 +1009,3 @@ return Promise.resolve('') | ||
try { | ||
await exec({}, true) | ||
/* istanbul ignore next */ | ||
throw new Error('Unexpected success') | ||
} catch (error) { | ||
error.message.should.match(/failed commit/) | ||
} | ||
expect(exec({}, true)).to.be.rejectedWith(gitError) | ||
}) | ||
@@ -952,2 +1019,3 @@ | ||
] | ||
const gitError = new Error('Command failed: git\nfailed tag') | ||
const execFile = (_args, cmd, cmdArgs) => { | ||
@@ -958,3 +1026,3 @@ cmd.should.equal('git') | ||
if (expected[0] === 'tag') { | ||
return Promise.reject(new Error('Command failed: git\nfailed tag')) | ||
return Promise.reject(gitError) | ||
} | ||
@@ -965,10 +1033,4 @@ return Promise.resolve('') | ||
try { | ||
await exec({}, true) | ||
/* istanbul ignore next */ | ||
throw new Error('Unexpected success') | ||
} catch (error) { | ||
error.message.should.match(/failed tag/) | ||
} | ||
expect(exec({}, true)).to.be.rejectedWith(gitError) | ||
}) | ||
}) |
@@ -11,3 +11,5 @@ /* global describe it beforeEach afterEach */ | ||
require('chai').should() | ||
const chai = require('chai') | ||
const expect = chai.expect | ||
chai.use(require('chai-as-promised')) | ||
@@ -360,9 +362,3 @@ function exec (opt = '') { | ||
mock({ bump: 'minor' }) | ||
try { | ||
await exec('--patch') | ||
/* istanbul ignore next */ | ||
throw new Error('Unexpected success') | ||
} catch (error) { | ||
error.message.should.match(/precommit-failure/) | ||
} | ||
expect(exec('--patch')).to.be.rejectedWith(/precommit-failure/) | ||
}) | ||
@@ -369,0 +365,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
168822
3.11%2608
2.72%14
7.69%