Skip to content

Commit

Permalink
feat: fallback to tags if no meta-information file found (#275)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: if no package.json, bower.json, etc., is found, we now fallback to git tags
  • Loading branch information
bcoe authored Nov 4, 2018
1 parent e86fe6b commit 844cde6
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 32 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,23 @@

_Having problems? want to contribute? join our [community slack](http://devtoolscommunity.herokuapp.com)_.

> stop using `npm version`, use `standard-version` it rocks!

Automatic versioning and CHANGELOG generation, using GitHub's squash button and
Automate versioning and CHANGELOG generation, with [semver](https://semver.org/) and
[conventional commit messages](https://conventionalcommits.org).

_how it works:_

1. when you land commits on your `master` branch, select the _Squash and Merge_ option.
2. add a title and body that follows the [Conventional Commits Specification](https://conventionalcommits.org).
3. when you're ready to release to npm:
3. when you're ready to release:
1. `git checkout master; git pull origin master`
2. run `standard-version`
3. `git push --follow-tags origin master && npm publish`
3. `git push --follow-tags origin master && npm publish
_(or, `docker push`, `gem push`, etc.)_

`standard-version` does the following:

1. bumps the version in _package.json/bower.json_ (based on your commit history)
1. bumps the version in metadata files (package.json, composer.json, etc).
2. uses [conventional-changelog](https://github.com/conventional-changelog/conventional-changelog) to update _CHANGELOG.md_
3. commits _package.json (et al.)_ and _CHANGELOG.md_
4. tags a new release
Expand Down Expand Up @@ -181,7 +181,7 @@ Simply add the following to your package.json to configure lifecycle scripts:
}
```

As an example to change from using GitHub to track your items to using your projects Jira use a
As an example to change from using GitHub to track your items to using your projects Jira use a
`postchangelog` script to replace the url fragment containing 'https://github.com/`myproject`/issues/'
with a link to your Jira - assuming you have already installed [replace](https://www.npmjs.com/package/replace)
```json
Expand Down
5 changes: 5 additions & 0 deletions command.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ module.exports = require('yargs')
default: defaults.dryRun,
describe: 'See the commands that running standard-version would run'
})
.option('git-tag-fallback', {
type: 'boolean',
default: defaults.gitTagFallback,
describe: `fallback to git tags for version, if no meta-information file is found (e.g., package.json)`
})
.check((argv) => {
if (typeof argv.scripts !== 'object' || Array.isArray(argv.scripts)) {
throw Error('scripts must be an object')
Expand Down
3 changes: 2 additions & 1 deletion defaults.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
"tagPrefix": "v",
"scripts": {},
"skip": {},
"dryRun": false
"dryRun": false,
"gitTagFallback": true
}
28 changes: 19 additions & 9 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const latestSemverTag = require('./lib/latest-semver-tag')
const path = require('path')
const printError = require('./lib/print-error')

Expand All @@ -7,24 +8,33 @@ const commit = require('./lib/lifecycles/commit')
const tag = require('./lib/lifecycles/tag')

module.exports = function standardVersion (argv) {
var pkg
let pkg
bump.pkgFiles.forEach((filename) => {
if (pkg) return
var pkgPath = path.resolve(process.cwd(), filename)
try {
pkg = require(pkgPath)
} catch (err) {}
})
if (!pkg) {
return Promise.reject(new Error('no package file found'))
}
var newVersion = pkg.version
var defaults = require('./defaults')
var args = Object.assign({}, defaults, argv)
let newVersion
let defaults = require('./defaults')
let args = Object.assign({}, defaults, argv)

return Promise.resolve()
.then(() => {
return bump(args, pkg)
if (!pkg && args.gitTagFallback) {
return latestSemverTag()
} else if (!pkg) {
throw new Error('no package file found')
} else {
return pkg.version
}
})
.then(version => {
newVersion = version
})
.then(() => {
return bump(args, newVersion)
})
.then((_newVersion) => {
// if bump runs, it calculaes the new version that we
Expand All @@ -36,7 +46,7 @@ module.exports = function standardVersion (argv) {
return commit(args, newVersion)
})
.then(() => {
return tag(newVersion, pkg.private, args)
return tag(newVersion, pkg ? pkg.private : false, args)
})
.catch((err) => {
printError(args, err.message)
Expand Down
15 changes: 15 additions & 0 deletions lib/latest-semver-tag.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const gitSemverTags = require('git-semver-tags')
const semver = require('semver')

module.exports = function () {
return new Promise((resolve, reject) => {
gitSemverTags(function (err, tags) {
if (err) return reject(err)
else if (!tags.length) return resolve('1.0.0')
// ensure that the largest semver tag is at the head.
tags = tags.map(tag => { return semver.clean(tag) })
tags.sort(semver.rcompare)
return resolve(tags[0])
})
})
}
8 changes: 4 additions & 4 deletions lib/lifecycles/bump.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ const writeFile = require('../write-file')

var configsToUpdate = {}

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

if (args.skip.bump) return Promise.resolve()
var newVersion = pkg.version
var newVersion = version
return runLifecycleScript(args, 'prerelease')
.then(runLifecycleScript.bind(this, args, 'prebump'))
.then((stdout) => {
Expand All @@ -28,8 +28,8 @@ function Bump (args, pkg) {
})
.then((release) => {
if (!args.firstRelease) {
var releaseType = getReleaseType(args.prerelease, release.releaseType, pkg.version)
newVersion = semver.valid(releaseType) || semver.inc(pkg.version, releaseType, args.prerelease)
var releaseType = getReleaseType(args.prerelease, release.releaseType, version)
newVersion = semver.valid(releaseType) || semver.inc(version, releaseType, args.prerelease)
updateConfigs(args, newVersion)
} else {
checkpoint(args, 'skip version bump on first release', [], chalk.red(figures.cross))
Expand Down
79 changes: 67 additions & 12 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

'use strict'

var shell = require('shelljs')
var fs = require('fs')
var path = require('path')
var stream = require('stream')
var mockGit = require('mock-git')
var mockery = require('mockery')
var semver = require('semver')
var formatCommitMessage = require('./lib/format-commit-message')
var cli = require('./command')
var standardVersion = require('./index')
const shell = require('shelljs')
const fs = require('fs')
const path = require('path')
const stream = require('stream')
const mockGit = require('mock-git')
const mockery = require('mockery')
const semver = require('semver')
const formatCommitMessage = require('./lib/format-commit-message')
const cli = require('./command')
const standardVersion = require('./index')

require('chai').should()

Expand Down Expand Up @@ -45,7 +45,6 @@ function writePackageJson (version, option) {
option = option || {}
var pkg = Object.assign(option, { version: version })
fs.writeFileSync('package.json', JSON.stringify(pkg), 'utf-8')
delete require.cache[require.resolve(path.join(process.cwd(), 'package.json'))]
}

function writeBowerJson (version, option) {
Expand Down Expand Up @@ -96,6 +95,16 @@ function initInTempFolder () {
shell.cd('tmp')
shell.exec('git init')
commit('root-commit')
;['package.json',
'manifest.json',
'bower.json'
].forEach(metadata => {
try {
delete require.cache[require.resolve(path.join(process.cwd(), metadata))]
} catch (err) {
// we haven't loaded the metadata file yet.
}
})
writePackageJson('1.0.0')
}

Expand Down Expand Up @@ -746,7 +755,10 @@ describe('standard-version', function () {
describe('without a package file to bump', function () {
it('should exit with error', function () {
shell.rm('package.json')
return require('./index')({ silent: true })
return require('./index')({
silent: true,
gitTagFallback: false
})
.catch((err) => {
err.message.should.equal('no package file found')
})
Expand Down Expand Up @@ -886,4 +898,47 @@ describe('standard-version', function () {
})
})
})

describe('.gitignore', () => {
beforeEach(function () {
writeBowerJson('1.0.0')
})

it('does not update files present in .gitignore', () => {
fs.writeFileSync('.gitignore', 'bower.json', 'utf-8')

commit('feat: first commit')
shell.exec('git tag -a v1.0.0 -m "my awesome first release"')
commit('feat: new feature!')
return require('./index')({ silent: true })
.then(() => {
JSON.parse(fs.readFileSync('bower.json', 'utf-8')).version.should.equal('1.0.0')
getPackageVersion().should.equal('1.1.0')
})
})
})

describe('gitTagFallback', () => {
it('defaults to 1.0.0 if no tags in git history', () => {
shell.rm('package.json')
commit('feat: first commit')
return require('./index')({ silent: true })
.then(() => {
const output = shell.exec('git tag')
output.stdout.should.include('v1.1.0')
})
})

it('bases version on last tag, if tags are found', () => {
shell.rm('package.json')
shell.exec('git tag -a v5.0.0 -m "a release"')
shell.exec('git tag -a v3.0.0 -m "another release"')
commit('feat: another commit')
return require('./index')({ silent: true })
.then(() => {
const output = shell.exec('git tag')
output.stdout.should.include('v5.1.0')
})
})
})
})

0 comments on commit 844cde6

Please sign in to comment.