commit-and-tag-version
Advanced tools
Comparing version 11.2.3 to 11.2.4
@@ -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
168822
2608
14