Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allows configuration of standard-version and submodules using package.json or a provided --config file #278

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 25 additions & 0 deletions command.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
var fs = require('fs')
var defaults = require('./defaults')

module.exports = require('yargs')
Expand Down Expand Up @@ -86,6 +87,30 @@ module.exports = require('yargs')
default: defaults.preset,
describe: 'Commit message guideline preset (default: angular)'
})
.config(
'config',
'Specify a path to a file that provides configuration options to standard-version and it\'s modules',
function (configPath) {
const parsed = {}
if (!fs.existsSync(configPath)) {
throw Error('unable to locate provided configuration file')
}
const config = require(configPath)
if (typeof config === 'function') {
// if the export of the configuraiton is a function, we expect the
// result to be our configuration object.
parsed.configuration = config()
}
if (typeof config === 'object') {
parsed.configuration = config.hasOwnProperty('standard-version') ? config['standard-version'] : (
// if the configuration is coming from a `package.json`, the `standard-version` key is required.
configPath.endsWith('package.json') ? {} : config
)
}
return parsed
}
)
.default('config', 'package.json')
.check((argv) => {
if (typeof argv.scripts !== 'object' || Array.isArray(argv.scripts)) {
throw Error('scripts must be an object')
Expand Down
20 changes: 16 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ module.exports = function standardVersion (argv) {
})
let newVersion
let defaults = require('./defaults')
let args = Object.assign({}, defaults, argv)

const packageConfiguration = Object.assign({}, argv.configuration)
// the `modules` key is reserved for submodule configurations.
const moduleConfigurations = packageConfiguration.modules || {}
// module specific configurations are *not* passed as part of `standard-version`s arguments.
delete packageConfiguration.modules
const args = Object.assign({}, defaults, argv, packageConfiguration)
return Promise.resolve()
.then(() => {
if (!pkg && args.gitTagFallback) {
Expand All @@ -35,13 +39,21 @@ module.exports = function standardVersion (argv) {
newVersion = version
})
.then(() => {
return bump(args, newVersion)
return bump(
args,
newVersion,
moduleConfigurations
)
})
.then((_newVersion) => {
// if bump runs, it calculaes the new version that we
// should release at.
if (_newVersion) newVersion = _newVersion
return changelog(args, newVersion)
return changelog(
args,
newVersion,
moduleConfigurations
)
})
.then(() => {
return commit(args, newVersion)
Expand Down
16 changes: 9 additions & 7 deletions lib/lifecycles/bump.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@ const semver = require('semver')
const stringifyPackage = require('stringify-package')
const writeFile = require('../write-file')

var configsToUpdate = {}
let configsToUpdate = {}
let moduleConfiguration = {}

function Bump (args, version) {
function Bump (args, version, configuration) {
// reset the cache of updated config files each
// time we perform the version bump step.
configsToUpdate = {}

moduleConfiguration = configuration['conventional-recommended-bump'] || {}
if (args.skip.bump) return Promise.resolve()
var newVersion = version
let newVersion = version
return runLifecycleScript(args, 'prerelease')
.then(runLifecycleScript.bind(this, args, 'prebump'))
.then((stdout) => {
Expand All @@ -31,7 +32,7 @@ function Bump (args, version) {
})
.then((release) => {
if (!args.firstRelease) {
var releaseType = getReleaseType(args.prerelease, release.releaseType, version)
let releaseType = getReleaseType(args.prerelease, release.releaseType, version)
newVersion = semver.valid(releaseType) || semver.inc(version, releaseType, args.prerelease)
updateConfigs(args, newVersion)
} else {
Expand Down Expand Up @@ -135,11 +136,12 @@ function bumpVersion (releaseAs, args) {
releaseType: releaseAs
})
} else {
conventionalRecommendedBump({
conventionalRecommendedBump(Object.assign({
debug: args.verbose && console.info.bind(console, 'conventional-recommended-bump'),
preset: args.preset || 'angular',
path: args.path
}, function (err, release) {
}, moduleConfiguration),
function (err, release) {
if (err) return reject(err)
else return resolve(release)
})
Expand Down
28 changes: 18 additions & 10 deletions lib/lifecycles/changelog.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@ const fs = require('fs')
const runLifecycleScript = require('../run-lifecycle-script')
const writeFile = require('../write-file')

module.exports = function (args, newVersion) {
module.exports = function (args, newVersion, moduleConfigurations) {
if (args.skip.changelog) return Promise.resolve()
return runLifecycleScript(args, 'prechangelog')
.then(() => {
return outputChangelog(args, newVersion)
return outputChangelog(args, newVersion, moduleConfigurations)
})
.then(() => {
return runLifecycleScript(args, 'postchangelog')
})
}

function outputChangelog (args, newVersion) {
function outputChangelog (args, newVersion, moduleConfigurations) {
return new Promise((resolve, reject) => {
createIfMissing(args)
var header = '# Change Log\n\nAll notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.\n'
Expand All @@ -28,16 +28,24 @@ function outputChangelog (args, newVersion) {
oldContent = oldContent.substring(oldContent.search(changelogSectionRegExp))
}
var content = ''
var context
if (args.dryRun) context = { version: newVersion }
var changelogStream = conventionalChangelog({
var context = {}
if (args.dryRun) context.version = newVersion
Object.assign(context, moduleConfigurations['conventional-changelog-core'])

var config = Object.assign({}, {
debug: args.verbose && console.info.bind(console, 'conventional-changelog'),
preset: args.preset || 'angular',
tagPrefix: args.tagPrefix
}, context, { merges: null, path: args.path })
.on('error', function (err) {
return reject(err)
})
})
Object.assign(config, moduleConfigurations['conventional-changelog'])

var changelogStream = conventionalChangelog(
config,
context,
{ merges: null, path: args.path }
).on('error', function (err) {
return reject(err)
})

changelogStream.on('data', function (buffer) {
content += buffer.toString()
Expand Down
132 changes: 132 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,138 @@ describe('cli', function () {
beforeEach(initInTempFolder)
afterEach(finishTemp)

describe('configuration', function () {
describe('preset', function () {
const presetOverride = 'eslint'
function makePresetCommits () {
commit('Upgrade: This is an <type> defined by the eslint preset.')
commit('fix: This is not <type> defined eslint preset (angular).')
}
function assertPresetOverrideCHANGELOG () {
var content = fs.readFileSync('CHANGELOG.md', 'utf-8')
content.should.contain('### Upgrade')
content.should.not.contain('### Bug Fixes')
}
it('uses --preset angular as the default', function () {
makePresetCommits()
execCli().code.should.equal(0)
var content = fs.readFileSync('CHANGELOG.md', 'utf-8')
content.should.not.contain('### Upgrade')
content.should.contain('### Bug Fixes')
})
it('via --preset flag', function () {
makePresetCommits()
execCli('--preset ' + presetOverride).code.should.equal(0)
assertPresetOverrideCHANGELOG()
})
it('via package.json (["standard-version"].modules["conventional-changelog"].preset)', function () {
writePackageJson('1.0.0', {
'standard-version': {
modules: {
'conventional-changelog': {
preset: presetOverride
}
}
}
})
makePresetCommits()
execCli().code.should.equal(0)
assertPresetOverrideCHANGELOG()
})
it('via custom.json (modules["conventional-changelog"].preset)', function () {
fs.writeFileSync('custom.json', JSON.stringify({
modules: {
'conventional-changelog': {
preset: presetOverride
}
}
}), 'utf-8')
makePresetCommits()
execCli('--config custom.json').code.should.equal(0)
assertPresetOverrideCHANGELOG()
})
it('via functional-config.js (modules["conventional-changelog"].preset)', function () {
fs.writeFileSync(
'functional-config.js',
`module.exports = () => ({
modules: {
'conventional-changelog': {
preset: '${presetOverride}'
}
}
});`,
'utf-8'
)
makePresetCommits()
execCli('--config functional-config.js').code.should.equal(0)
assertPresetOverrideCHANGELOG()
})
it('providing and invalid configuration file will result in an error', function () {
execCli('--config fake-file.js').code.should.above(0)
})
it('allows modules["conventional-changelog"].preset and modules["conventional-changelog-core"] options', function () {
writePackageJson('2.0.0', {
'standard-version': {
modules: {
'conventional-changelog': {
preset: presetOverride
},
'conventional-changelog-core': {
host: 'gitlab',
repoUrl: 'https://other-git-service.com/repoUrl',
repository: 'git+https://other-git-service.com/repository.git'
}
}
}
})
makePresetCommits()
execCli().code.should.equal(0)
assertPresetOverrideCHANGELOG()
var content = fs.readFileSync('CHANGELOG.md', 'utf-8')
content.should.contain('other-git-service.com')
})
})
it('allows configuration of repository options (modules.["conventional-changelog-core"])', function () {
writePackageJson('2.0.0', {
'standard-version': {
modules: {
'conventional-changelog-core': {
host: 'gitlab',
repoUrl: 'https://other-git-service.com/repoUrl',
repository: 'git+https://other-git-service.com/repository.git'
}
}
}
})
commit('feat: angular style commit with issue reference\n\n#278')
execCli().code.should.equal(0)
var content = fs.readFileSync('CHANGELOG.md', 'utf-8')
content.should.contain('other-git-service.com')
})

describe('tagPrefix', function () {
it('via --tagPrefix flag', function () {
var prefix = 'version-foo/'
commit('feat: angular style commit')
execCli('--tagPrefix=' + prefix).code.should.equal(0)
commit('feat: another angular style commit')
execCli('--tagPrefix=' + prefix).code.should.equal(0)
var content = fs.readFileSync('CHANGELOG.md', 'utf-8')
content.should.contain('/compare/' + prefix)
})

it('via --tagPrefix flag with --preset flag', function () {
var prefix = 'version-foo/'
commit('Feat: eslint style commit')
execCli('--preset=eslint --tagPrefix=' + prefix).code.should.equal(0)
commit('Feat: another eslint style commit')
execCli('--preset=eslint --tagPrefix=' + prefix).code.should.equal(0)
var content = fs.readFileSync('CHANGELOG.md', 'utf-8')
content.should.contain('/compare/' + prefix)
})
})
})

describe('CHANGELOG.md does not exist', function () {
it('populates changelog with commits since last tag by default', function () {
commit('feat: first commit')
Expand Down