Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd4c4d1c81 | ||
|
|
7ba1cb956f | ||
|
|
1f70215ffe | ||
|
|
245f918201 | ||
|
|
f0f53f207b | ||
|
|
41c90124f6 | ||
|
|
44db677c4a | ||
|
|
127cb673bd | ||
|
|
a5dabed534 | ||
|
|
be9bb40dd2 | ||
|
|
4821aff69e | ||
|
|
773ecf693f | ||
|
|
f2dd66f614 | ||
|
|
3b921a63c5 | ||
|
|
785e7f7b3b | ||
|
|
b38f1e0687 | ||
|
|
323b5d5bf8 | ||
|
|
3369f31a8d | ||
|
|
63096c50c4 | ||
|
|
248c41a504 | ||
|
|
e0eee05a7e | ||
|
|
08ae05fb82 | ||
|
|
e445effdcf | ||
|
|
29469e0b8a | ||
|
|
615d796f24 | ||
|
|
49de103753 |
@@ -1,5 +1,6 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- iojs-v2
|
||||
- iojs-v1
|
||||
- '0.10'
|
||||
- '0.12'
|
||||
|
||||
@@ -5,65 +5,29 @@
|
||||
|
||||
[](https://nodei.co/npm/semantic-release/)
|
||||
|
||||
## What is this thing even?
|
||||
## What is `semantic-release` about?
|
||||
|
||||
`semantic-release` is a toolset to fully automate your package's releases. This will determine not only which version to release, but also when – all without you having to care about it ever again.
|
||||
It fully automates your package's releases. It will determine not only which version to release, but also when – all without you wasting [cognitive resources](https://www.youtube.com/watch?v=FKTxC9pl-WM) on it.
|
||||
|
||||
This is fully integrated with the `npm` lifecycle, so all you have to do is to setup your CI to `npm publish`.
|
||||
It is fully integrated into the `npm` lifecycle, so all you need to do is to configure your CI to regularly `npm publish` (i.e. for every commit).
|
||||
|
||||
The goal of this package is to remove humans from version numbers and releases. The [SemVer](http://semver.org/) spec clearly and unambiguously defines when to increase the major, minor or patch part. Still we tend to ignore the rules, because we are emotionally attached to version numbers.
|
||||
It removes human decisions and emotions from version numbers and releases – suddenly, strictly following the [SemVer](http://semver.org/) spec isn't a problem anymore.
|
||||
|
||||

|
||||
|
||||
## How does this work?
|
||||
## How does it work?
|
||||
|
||||
Conventions, conventions, conventions. Instead of dumping [lols](http://whatthecommit.com/) into our commit messages, we can take some time to think about what we changed in the codebase and write it down. Following formalized conventions it this then possible to not only generate a meaningful changelog, but to determine the next semantic version to release.
|
||||
Meaningful conventions. Instead of dumping [lols](http://whatthecommit.com/) into our commit messages, we can take some time to think about what we changed in the codebase and write it down. Following formalized conventions it this then possible to not only generate a helpful changelog, but to determine whether a new version should be released.
|
||||
|
||||
Note: Currently the only supported style is the [AngularJS Commit Message Convention](https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit) style, but feel free to formalize your own style, write a parser for it, and send a PR to this package.
|
||||
|
||||
```
|
||||
<type>(<scope>): <subject>
|
||||
<BLANK LINE>
|
||||
<body>
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
```
|
||||
feat(ruler): add inches as well as centimeters
|
||||
```
|
||||
|
||||
```
|
||||
fix(protractor): fix 90 degrees counting as 91 degrees
|
||||
```
|
||||
|
||||
```
|
||||
fix(pen): use blue ink instead of red ink
|
||||
|
||||
BREAKING CHANGE: Pen now uses blue ink instead of red.
|
||||
|
||||
To migrate, change your code from the following:
|
||||
|
||||
`pen.draw('blue')`
|
||||
|
||||
To:
|
||||
|
||||
`pen.draw('red')`
|
||||
```
|
||||
|
||||
[Synopsis](https://github.com/ajoslin/conventional-changelog/blob/master/CONVENTIONS.md)
|
||||
|
||||
The preferred configuration is the "try to release on every push" mode. What it does is that everytime a build passes `npm publish` is executed.
|
||||
This module ships with the [AngularJS Commit Message Conventions](https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit), but you can [define your own](https://github.com/boennemann/semantic-release/wiki/commit-analysis).
|
||||
|
||||
### The `prepublish` step
|
||||
|
||||
Before `npm` actually gets to publish a new version `semantic-release`'s `prepublish` step does the following:
|
||||
|
||||
- Analyze the commits since the last version was published
|
||||
- Decide on the release type (`major`|`minor`|`patch`) or abort if nothing changed
|
||||
- Get the last published version from the registry
|
||||
- Increase the last version with the determined type
|
||||
- Write the new version to the package
|
||||
- Extract all commits since the last version was published
|
||||
- Determine the release type (`major`|`minor`|`patch`) or abort if nothing relevant changed
|
||||
- Increase the version number accordingly
|
||||
|
||||
### The `publish` step
|
||||
|
||||
@@ -73,16 +37,16 @@ Before `npm` actually gets to publish a new version `semantic-release`'s `prepub
|
||||
|
||||
After `npm` published the new version the `postpublish` step does this:
|
||||
|
||||
- Generate a changelog
|
||||
- Create a new [GitHub Release](https://help.github.com/articles/about-releases/) with the changelog as body
|
||||
- Generate release notes
|
||||
- Create a new [GitHub Release](https://help.github.com/articles/about-releases/) (including a git tag) with the release notes
|
||||
|
||||
Note: The GitHub Release automatically creates a tag, too.
|
||||
Note: The default release notes are a [changelog](https://github.com/ajoslin/conventional-changelog) that is generated from git metadata, using the AngularJS commit conventions. You can [specify your own release note generator](https://github.com/boennemann/semantic-release/wiki/release-note-generation).
|
||||
|
||||
Note: This is tied to GitHub, feel free to send PRs for other services.
|
||||
|
||||
Note: `semantic-release` works around a limitation in `npm`'s `prepublish` step. Once a version is published it prints an error that you can *safely ignore* [npm/npm#7118](https://github.com/npm/npm/issues/7118).
|
||||
Note: `semantic-release` works around a limitation in `npm`'s `prepublish` step. Once a version is published it prints a "Could not pack" error that you can *safely ignore* [npm/npm#7118](https://github.com/npm/npm/issues/7118).
|
||||
|
||||
## How do I set this up?
|
||||
## How you can set it up
|
||||
|
||||
### Installation
|
||||
|
||||
@@ -113,7 +77,7 @@ The setup command configures `scripts` inside the `package.json`:
|
||||
}
|
||||
```
|
||||
|
||||
Note: If you have already configured `scripts` for `prepublish` or `postpublish` they're just executed one after another. For example: `"npm run 6to5 && semantic-release pre"`.
|
||||
Note: If you have already configured `scripts` for `prepublish` or `postpublish` they're just executed one after another. For example: `"npm run babelify && semantic-release pre"`.
|
||||
|
||||
#### Version
|
||||
|
||||
@@ -137,12 +101,15 @@ cache:
|
||||
- node_modules
|
||||
notifications:
|
||||
email: false
|
||||
# See https://github.com/boennemann/semantic-release/issues/18
|
||||
before_deploy:
|
||||
- npm config set spin false --global
|
||||
env:
|
||||
# Get your token here: https://github.com/settings/tokens/new
|
||||
# Grant the token repo/public_repo scope (all others can be deselected)
|
||||
# You should encrypt this:
|
||||
# `travis encrypt GH_TOKEN=<token> --add`
|
||||
global: GH_TOKEN=<github-access-token-with-acceess-to-your-repo>
|
||||
global: GH_TOKEN=<github-access-token-with-access-to-your-repo>
|
||||
deploy:
|
||||
provider: npm
|
||||
email: <your-npm-mail@example.com>
|
||||
@@ -158,7 +125,7 @@ deploy:
|
||||
repo: <user>/<repo>
|
||||
```
|
||||
|
||||
Note: For once this isn't tied to a specific service, but example configuration is shown for [Travis CI](https://travis-ci.org/). Feel free to contribute configuration of other servers or services.
|
||||
Note: This isn't tied to a specific service, but example configuration is provided for [Travis CI](https://travis-ci.org/). Feel free to contribute configuration for other servers or services.
|
||||
|
||||
Note: You should [encrypt](http://docs.travis-ci.com/user/environment-variables/#sts=Secure Variables) your api keys and tokens.
|
||||
|
||||
@@ -178,7 +145,7 @@ The `npm` docs even state:
|
||||
> The most important things in your package.json are the name and version fields. Those are actually required, and your package won't install without them.
|
||||
> -- [npm docs](https://docs.npmjs.com/files/package.json#version)
|
||||
|
||||
While this entirely true the version number doesn't have to be checked into source control. `semantic-release` takes care of the version field right before `npm publish` uses it – and this is the only point when it _really_ is required.
|
||||
While this entirely true the version number doesn't have to be checked into source control. `semantic-release` takes care of the version field right before `npm publish` uses it – and this is the only point where it _really_ is required.
|
||||
|
||||
### Is there a way to preview which version would currently get published?
|
||||
|
||||
@@ -186,13 +153,13 @@ If you're running `npm publish` locally `semantic-release` automatically perform
|
||||
|
||||
### Can I run this on my own machine rather than on a CI server?
|
||||
|
||||
Of course you can, but this doesn't mean you should. Running your tests on an independent machine before releasing software is a crucial part of this workflow. Also it is a pain to set this up locally, with GitHub tokens lying around and everything. That said, you can either set the environment variable `CI=true`, or run the scripts with `--debug=false` explicitly. Don't forget to export `GH_TOKEN=your_token` as well.
|
||||
Of course you can, but this doesn't necessarly mean you should. Running your tests on an independent machine before releasing software is a crucial part of this workflow. Also it is a pain to set this up locally, with GitHub tokens lying around and everything. That said, you can either set the environment variable `CI=true`, or run the scripts with `--debug=false` explicitly. Don't forget to export `GH_TOKEN=your_token` as well.
|
||||
|
||||
### Can I manually trigger the release of a specific version?
|
||||
|
||||
You can trigger a release by pushing to your repository. You deliberately can not trigger a _specific_ version release, because this is the whole point of `semantic-release`. Start your packages with `1.0.0` and semver on.
|
||||
|
||||
Note: pre-release flags are kind of an exeption here and a solution for them is being thought of. If you have one please open an issue. For the time being: Have a look at the next question.
|
||||
Note: The default commit message conventions do not support pre-release flags, but you can build this in yourself using [custom analyzers](https://github.com/boennemann/semantic-release/wiki/commit-analysis).
|
||||
|
||||
### How do I get back to good ol' `npm publish`?
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict'
|
||||
|
||||
var readFile = require('fs').readFileSync
|
||||
|
||||
var abbrev = require('abbrev')
|
||||
var minimist = require('minimist')
|
||||
|
||||
@@ -21,6 +23,8 @@ var argv = minimist(process.argv.slice(2), {
|
||||
}
|
||||
})
|
||||
|
||||
var plugins = JSON.parse(readFile('./package.json')).release || {}
|
||||
|
||||
var npmArgv = process.env.npm_config_argv ?
|
||||
minimist(JSON.parse(process.env.npm_config_argv).cooked) :
|
||||
{_: []}
|
||||
@@ -46,7 +50,7 @@ if (~argv._.indexOf('pre')) {
|
||||
// require a correct setup during publish
|
||||
if (publish && !argv.debug && !require('../src/verify')(argv)) process.exit(1)
|
||||
|
||||
require('../src/pre')(argv, efh(function (result) {
|
||||
require('../src/pre')(argv, plugins, efh(function (result) {
|
||||
if (!result) {
|
||||
console.log('Nothing changed. Not publishing.')
|
||||
process.exit(1)
|
||||
@@ -64,7 +68,7 @@ if (~argv._.indexOf('pre')) {
|
||||
}
|
||||
|
||||
if (~argv._.indexOf('post')) {
|
||||
require('../src/post')(argv, efh(function () {
|
||||
require('../src/post')(argv, plugins, efh(function () {
|
||||
// see src/restart.js
|
||||
if (npmArgv['semantic-release-rerun']) {
|
||||
console.log('Everything is alright :) npm will now print an error message that you can safely ignore.')
|
||||
|
||||
@@ -18,8 +18,6 @@ function cleanup {
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
[ -d ".tmp" ] && ./bin/post-test
|
||||
|
||||
mkdir -p .tmp/modules
|
||||
|
||||
export DEBUG=ghrs:cli
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
'use strict'
|
||||
|
||||
var parseRawCommit = require('conventional-changelog/lib/git').parseRawCommit
|
||||
|
||||
module.exports = function (commits) {
|
||||
var type = null
|
||||
|
||||
commits
|
||||
|
||||
.map(function (commit) {
|
||||
return parseRawCommit(commit.hash + '\n' + commit.message)
|
||||
})
|
||||
|
||||
.filter(function (commit) {
|
||||
return !!commit
|
||||
})
|
||||
|
||||
.every(function (commit) {
|
||||
if (commit.breaks.length) {
|
||||
type = 'major'
|
||||
return false
|
||||
}
|
||||
|
||||
if (commit.type === 'feat') type = 'minor'
|
||||
|
||||
if (!type && commit.type === 'fix') type = 'patch'
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
return type
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
'use strict'
|
||||
|
||||
var exec = require('child_process').exec
|
||||
|
||||
var efh = require('./error').efh
|
||||
|
||||
module.exports = function (from, cb) {
|
||||
var range = (from ? from + '..' : '') + 'HEAD'
|
||||
exec(
|
||||
'git log -E --format=%H==SPLIT==%B==END== ' + range,
|
||||
efh(cb)(function (stdout) {
|
||||
cb(null, String(stdout).split('==END==\n')
|
||||
|
||||
.filter(function (raw) {
|
||||
return !!raw.trim()
|
||||
})
|
||||
|
||||
.map(function (raw) {
|
||||
var data = raw.split('==SPLIT==')
|
||||
return {
|
||||
hash: data[0],
|
||||
message: data[1]
|
||||
}
|
||||
}))
|
||||
})
|
||||
)
|
||||
}
|
||||
+1
-1
@@ -7,7 +7,7 @@ module.exports = {
|
||||
standard: efh(function (err) {
|
||||
console.log('Something went wrong:')
|
||||
if (typeof err === 'string') return console.log(err)
|
||||
if (err instanceof Error) return console.log(err.message)
|
||||
if (err instanceof Error) return console.log(err.message, err.stack)
|
||||
if (err.message) return console.log(err.message)
|
||||
console.log(err)
|
||||
})
|
||||
|
||||
+3
-2
@@ -5,7 +5,8 @@ var request = require('request')
|
||||
var efh = require('./error').efh
|
||||
|
||||
module.exports = function (pkgName, cb) {
|
||||
request(process.env.npm_config_registry + pkgName, efh(cb)(function (response, body) {
|
||||
var encodedPkgName = pkgName.replace(/\//g, '%2F')
|
||||
request(process.env.npm_config_registry + encodedPkgName, efh(cb)(function (response, body) {
|
||||
var res = {
|
||||
version: null,
|
||||
gitHead: null,
|
||||
@@ -16,7 +17,7 @@ module.exports = function (pkgName, cb) {
|
||||
|
||||
var pkg = JSON.parse(body)
|
||||
|
||||
if (pkg.error && response.statusCode !== 404) return cb(pkg.error)
|
||||
if (pkg.error) return cb(pkg.error)
|
||||
|
||||
res.version = pkg['dist-tags'].latest
|
||||
res.gitHead = pkg.versions[res.version].gitHead
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
'use strict'
|
||||
|
||||
var readFile = require('fs').readFileSync
|
||||
|
||||
var changelog = require('conventional-changelog')
|
||||
var parseUrl = require('github-url-from-git')
|
||||
|
||||
module.exports = function (cb) {
|
||||
var pkg = JSON.parse(readFile('./package.json'))
|
||||
var repository = pkg.repository ? parseUrl(pkg.repository.url) : null
|
||||
|
||||
changelog({
|
||||
version: pkg.version,
|
||||
repository: repository,
|
||||
file: false
|
||||
}, cb)
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
var git = require('conventional-changelog/lib/git')
|
||||
|
||||
var efh = require('../error').efh
|
||||
|
||||
module.exports = function (from, cb) {
|
||||
git.getCommits({
|
||||
log: console.log.bind(console),
|
||||
warn: console.warn.bind(console),
|
||||
from: from
|
||||
}, efh(cb)(function (commits) {
|
||||
cb(null, commits)
|
||||
}))
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
var analyze = require('./analyze')
|
||||
var commits = require('./commits')
|
||||
var efh = require('../error').efh
|
||||
|
||||
module.exports = function (gitHead, cb) {
|
||||
commits(gitHead, efh(cb)(function (commits) {
|
||||
cb(null, analyze(commits))
|
||||
}))
|
||||
}
|
||||
+5
-1
@@ -12,7 +12,7 @@
|
||||
"conventional-changelog": "0.0.17",
|
||||
"error-first-handler": "^1.0.1",
|
||||
"git-head": "^1.2.1",
|
||||
"github": "^0.2.3",
|
||||
"github": "0.2.4",
|
||||
"github-url-from-git": "^1.4.0",
|
||||
"ini": "^1.3.2",
|
||||
"minimist": "^1.1.0",
|
||||
@@ -21,6 +21,7 @@
|
||||
"semver": "^4.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cracks": "^2.0.1",
|
||||
"github-release-fake-server": "^1.3.0",
|
||||
"lodash.defaults": "^3.0.0",
|
||||
"nano-uid": "^0.2.0",
|
||||
@@ -59,5 +60,8 @@
|
||||
"test:style": "standard",
|
||||
"test:integration": "node tests | tap-spec",
|
||||
"test": "./bin/test"
|
||||
},
|
||||
"release": {
|
||||
"verification": "cracks"
|
||||
}
|
||||
}
|
||||
|
||||
+4
-8
@@ -3,20 +3,20 @@
|
||||
var readFile = require('fs').readFileSync
|
||||
var url = require('url')
|
||||
|
||||
var changelog = require('conventional-changelog')
|
||||
var gitHead = require('git-head')
|
||||
var GitHubApi = require('github')
|
||||
var parseSlug = require('parse-github-repo-url')
|
||||
var parseUrl = require('github-url-from-git')
|
||||
|
||||
var efh = require('../lib/error').efh
|
||||
|
||||
module.exports = function (options, cb) {
|
||||
module.exports = function (options, plugins, cb) {
|
||||
var pkg = JSON.parse(readFile('./package.json'))
|
||||
var repository = pkg.repository ? pkg.repository.url : null
|
||||
|
||||
if (!repository) return cb(new Error('Package must have a repository'))
|
||||
|
||||
var notesGenerator = require(plugins.notes || '../lib/release-notes')
|
||||
|
||||
var config = options['github-url'] ? url.parse(options['github-url']) : {}
|
||||
|
||||
var github = new GitHubApi({
|
||||
@@ -26,11 +26,7 @@ module.exports = function (options, cb) {
|
||||
host: config.hostname
|
||||
})
|
||||
|
||||
changelog({
|
||||
version: pkg.version,
|
||||
repository: parseUrl(repository),
|
||||
file: false
|
||||
}, efh(cb)(function (log) {
|
||||
notesGenerator(efh(cb)(function (log) {
|
||||
gitHead(efh(cb)(function (hash) {
|
||||
var ghRepo = parseSlug(repository)
|
||||
var release = {
|
||||
|
||||
+49
-9
@@ -4,21 +4,61 @@ var fs = require('fs')
|
||||
|
||||
var semver = require('semver')
|
||||
|
||||
var type = require('../lib/type')
|
||||
var getCommits = require('../lib/commits')
|
||||
var npmInfo = require('../lib/npm-info')
|
||||
var efh = require('../lib/error').efh
|
||||
|
||||
module.exports = function (options, cb) {
|
||||
module.exports = function (options, plugins, cb) {
|
||||
var path = './package.json'
|
||||
var pkg = JSON.parse(fs.readFileSync(path))
|
||||
if (!pkg.name) return cb(new Error('Package must have a name'))
|
||||
npmInfo(pkg.name, efh(cb)(function (res) {
|
||||
type(res.gitHead, efh(cb)(function (type) {
|
||||
if (!type) return cb(null, null)
|
||||
pkg.version = !res.version ? '1.0.0' : semver.inc(res.version, type)
|
||||
if (!options.debug) fs.writeFileSync(path, JSON.stringify(pkg, null, 2))
|
||||
|
||||
cb(null, pkg.version)
|
||||
if (!pkg.name) return cb(new Error('Package must have a name'))
|
||||
|
||||
npmInfo(pkg.name, efh(cb)(function (res) {
|
||||
getCommits(res.gitHead, efh(cb)(function (commits) {
|
||||
var analyzer = require(plugins.analyzer || '../lib/analyzer')
|
||||
var type = analyzer(commits)
|
||||
|
||||
if (!type) return cb(null, null)
|
||||
|
||||
if (res.version) {
|
||||
pkg.version = semver.inc(res.version, type)
|
||||
} else {
|
||||
type = 'major'
|
||||
pkg.version = '1.0.0'
|
||||
}
|
||||
|
||||
var writePkg = function () {
|
||||
if (!options.debug) fs.writeFileSync(path, JSON.stringify(pkg, null, 2) + '\n')
|
||||
cb(null, pkg.version)
|
||||
}
|
||||
|
||||
if (!plugins.verification) return writePkg()
|
||||
|
||||
var opts = {}
|
||||
|
||||
if (typeof plugins.verification === 'string') {
|
||||
opts.path = plugins.verification
|
||||
}
|
||||
if (typeof plugins.verification === 'object') {
|
||||
opts = plugins.verification
|
||||
opts.path = opts.path || opts.name
|
||||
}
|
||||
|
||||
opts.type = type
|
||||
opts.commits = commits
|
||||
opts.version = res.version
|
||||
opts.nextVersion = pkg.version
|
||||
|
||||
var verification = require(opts.path)
|
||||
|
||||
console.log('Running verification hook...')
|
||||
|
||||
verification(opts, function (error, ok) {
|
||||
if (!error && ok) return writePkg()
|
||||
console.log('Verification failed' + (error ? ': ' + error : ''))
|
||||
process.exit(1)
|
||||
})
|
||||
}))
|
||||
}))
|
||||
}
|
||||
|
||||
+1
-1
@@ -38,5 +38,5 @@ module.exports = function () {
|
||||
pkg.devDependencies['semantic-release'] = '^' + require('../package.json').version
|
||||
}
|
||||
|
||||
fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 2))
|
||||
fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 2) + '\n')
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ var test = require('tape')
|
||||
|
||||
var createModule = require('./lib/create-module')
|
||||
|
||||
require('./scenarios/custom-analyzer')(test, createModule)
|
||||
require('./scenarios/custom-verification')(test, createModule)
|
||||
require('./scenarios/ignore')(test, createModule)
|
||||
require('./scenarios/prepublish')(test, createModule)
|
||||
require('./scenarios/postpublish')(test, createModule)
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
'use strict'
|
||||
|
||||
var fs = require('fs')
|
||||
var exec = require('child_process').exec
|
||||
|
||||
var nixt = require('nixt')
|
||||
|
||||
module.exports = function (t, message, version, code, name, cwd) {
|
||||
t.test(name, function (t) {
|
||||
t.plan(3)
|
||||
|
||||
nixt()
|
||||
.cwd(cwd)
|
||||
.env('CI', true)
|
||||
.env('npm_config_registry', 'http://127.0.0.1:4873/')
|
||||
.exec('git commit --allow-empty -m "' + message + '"')
|
||||
.run('npm run prepublish')
|
||||
.code(code)
|
||||
.stdout(/> semantic-release pre\n\nDetermining new version\n/m)
|
||||
.end(function (err) {
|
||||
t.error(err, 'nixt')
|
||||
|
||||
var pkg = JSON.parse(fs.readFileSync(cwd + '/package.json'))
|
||||
t.is(pkg.version, version, 'version')
|
||||
|
||||
if (code === 1) {
|
||||
return t.error(null, 'no publish')
|
||||
}
|
||||
|
||||
exec('npm publish --ignore-scripts', {cwd: cwd}, function (err) {
|
||||
setTimeout(function () {
|
||||
t.error(err, 'publish')
|
||||
}, 300)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -4,14 +4,14 @@ module.exports = function (commits) {
|
||||
var type = null
|
||||
|
||||
commits.every(function (commit) {
|
||||
if (commit.breaks.length) {
|
||||
if (/FOO/.test(commit.message)) {
|
||||
type = 'major'
|
||||
return false
|
||||
}
|
||||
|
||||
if (commit.type === 'feat') type = 'minor'
|
||||
if (/BAR/.test(commit.message)) type = 'minor'
|
||||
|
||||
if (!type && commit.type === 'fix') type = 'patch'
|
||||
if (!type && /BAZ/.test(commit.message)) type = 'patch'
|
||||
|
||||
return true
|
||||
})
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = function (cb) {
|
||||
cb(null, 'custom log')
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = function (opts, cb) {
|
||||
cb(null, !(opts.commits.length % 2))
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
'use strict'
|
||||
|
||||
var path = require('path')
|
||||
|
||||
var efh = require('error-first-handler')
|
||||
|
||||
var commitToVersionTest = require('../lib/commit-to-version-test')
|
||||
|
||||
module.exports = function (test, createModule) {
|
||||
createModule({
|
||||
release: {
|
||||
analyzer: path.join(__dirname, '../lib/custom-analyzer')
|
||||
}
|
||||
}, efh()(function (name, cwd) {
|
||||
test('custom-analyzer', function (t) {
|
||||
commitToVersionTest(t, 'HO', '0.0.0', 1, 'abort publish w/o changes', cwd)
|
||||
commitToVersionTest(t, 'BAZ', '1.0.0', 0, 'release 1.0.0 if unpublished', cwd)
|
||||
commitToVersionTest(t, 'BAZ', '1.0.1', 0, 'bump patch for fix', cwd)
|
||||
commitToVersionTest(t, 'BAR', '1.1.0', 0, 'bump minor for feature', cwd)
|
||||
commitToVersionTest(t, 'FOO', '2.0.0', 0, 'bump major for breaking change', cwd)
|
||||
})
|
||||
}))
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
'use strict'
|
||||
|
||||
var path = require('path')
|
||||
|
||||
var efh = require('error-first-handler')
|
||||
var nixt = require('nixt')
|
||||
|
||||
module.exports = function (test, createModule) {
|
||||
createModule({
|
||||
release: {
|
||||
verification: path.join(__dirname, '../lib/custom-verification')
|
||||
}
|
||||
}, efh()(function (name, cwd) {
|
||||
test('custom-verification', function (t) {
|
||||
t.test('even commit count', function (t) {
|
||||
t.plan(1)
|
||||
nixt()
|
||||
.cwd(cwd)
|
||||
.env('CI', true)
|
||||
.env('npm_config_registry', 'http://127.0.0.1:4873/')
|
||||
.exec('git commit --allow-empty -m "feat: commit"')
|
||||
.run('npm run prepublish')
|
||||
.code(0)
|
||||
.end(function (err) {
|
||||
t.error(err, 'nixt')
|
||||
})
|
||||
})
|
||||
|
||||
t.test('odd commit count', function (t) {
|
||||
t.plan(1)
|
||||
nixt()
|
||||
.cwd(cwd)
|
||||
.env('CI', true)
|
||||
.env('npm_config_registry', 'http://127.0.0.1:4873/')
|
||||
.exec('git commit --allow-empty -m "feat: commit"')
|
||||
.run('npm run prepublish')
|
||||
.code(1)
|
||||
.stdout(/Verification failed/)
|
||||
.end(function (err) {
|
||||
t.error(err, 'nixt')
|
||||
})
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
'use strict'
|
||||
|
||||
var path = require('path')
|
||||
|
||||
var efh = require('error-first-handler')
|
||||
var GitHubApi = require('github')
|
||||
var nixt = require('nixt')
|
||||
@@ -25,19 +27,13 @@ module.exports = function (test, createModule) {
|
||||
}
|
||||
}, efh()(function (name, cwd) {
|
||||
test('postpublish', function (t) {
|
||||
var base = nixt()
|
||||
.cwd(cwd)
|
||||
.env('CI', true)
|
||||
.env('GH_URL', 'http://127.0.0.1:4343/')
|
||||
.env('GH_TOKEN', '***')
|
||||
.exec('git commit --allow-empty -m "feat(cool): the next big thing"')
|
||||
.code(0)
|
||||
.stdout(/> semantic-release post\n\nGenerating changelog from.*\nParsed/m)
|
||||
var base = getBase(cwd)
|
||||
|
||||
t.test('publish new version to github releases', function (t) {
|
||||
t.plan(1)
|
||||
|
||||
base.clone()
|
||||
.stdout(/> semantic-release post\n\nGenerating changelog from.*\nParsed/m)
|
||||
.run('npm run postpublish')
|
||||
.end(function (err) {
|
||||
t.error(err, 'nixt')
|
||||
@@ -48,6 +44,7 @@ module.exports = function (test, createModule) {
|
||||
t.plan(1)
|
||||
|
||||
base.clone()
|
||||
.stdout(/> semantic-release post\n\nGenerating changelog from.*\nParsed/m)
|
||||
.exec('git checkout `git rev-parse HEAD`')
|
||||
.run('npm run postpublish')
|
||||
.end(function (err) {
|
||||
@@ -58,7 +55,8 @@ module.exports = function (test, createModule) {
|
||||
t.test('correct data published', function (t) {
|
||||
t.plan(4)
|
||||
|
||||
github.releases.getRelease({ owner: 'user', repo: 'repo', id: 1}, function (err, res) {
|
||||
github.releases.getRelease({ owner: 'user', repo: 'repo', id: 1}, function (err, raw) {
|
||||
var res = JSON.parse(raw)
|
||||
t.error(err, 'github')
|
||||
t.is(res.tag_name, 'v2.0.0', 'version')
|
||||
t.is(res.author.login, 'user', 'user')
|
||||
@@ -67,4 +65,51 @@ module.exports = function (test, createModule) {
|
||||
})
|
||||
})
|
||||
}))
|
||||
|
||||
createModule({
|
||||
version: '2.0.0',
|
||||
repository: {
|
||||
type: 'git',
|
||||
url: 'http://github.com/user/repo'
|
||||
},
|
||||
release: {
|
||||
notes: path.join(__dirname, '../lib/custom-release-notes')
|
||||
}
|
||||
}, efh()(function (name, cwd) {
|
||||
test('custom-release-notes', function (t) {
|
||||
var base = getBase(cwd)
|
||||
|
||||
t.test('publish new version (with custom notes) to github releases', function (t) {
|
||||
t.plan(1)
|
||||
|
||||
base.clone()
|
||||
.run('npm run postpublish')
|
||||
.end(function (err) {
|
||||
t.error(err, 'nixt')
|
||||
})
|
||||
})
|
||||
|
||||
t.test('custom notes published', function (t) {
|
||||
t.plan(4)
|
||||
|
||||
github.releases.getRelease({ owner: 'user', repo: 'repo', id: 3}, function (err, raw) {
|
||||
var res = JSON.parse(raw)
|
||||
t.error(err, 'github')
|
||||
t.is(res.tag_name, 'v2.0.0', 'version')
|
||||
t.is(res.author.login, 'user', 'user')
|
||||
t.ok(/custom log/.test(res.body), 'body')
|
||||
})
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
function getBase (cwd) {
|
||||
return nixt()
|
||||
.cwd(cwd)
|
||||
.env('CI', true)
|
||||
.env('GH_URL', 'http://127.0.0.1:4343/')
|
||||
.env('GH_TOKEN', '***')
|
||||
.exec('git commit --allow-empty -m "feat(cool): the next big thing"')
|
||||
.code(0)
|
||||
}
|
||||
|
||||
@@ -1,50 +1,17 @@
|
||||
'use strict'
|
||||
|
||||
var fs = require('fs')
|
||||
var exec = require('child_process').exec
|
||||
|
||||
var efh = require('error-first-handler')
|
||||
var nixt = require('nixt')
|
||||
|
||||
var commitToVersionTest = require('../lib/commit-to-version-test')
|
||||
|
||||
module.exports = function (test, createModule) {
|
||||
createModule(efh()(function (name, cwd) {
|
||||
test('prepublish', function (t) {
|
||||
prepublishTest(t, 'refactor: change', '0.0.0', 1, 'abort publish w/o changes')
|
||||
prepublishTest(t, 'fix: change', '1.0.0', 0, 'release 1.0.0 if unpublished')
|
||||
prepublishTest(t, 'fix: change', '1.0.1', 0, 'bump patch for fix')
|
||||
prepublishTest(t, 'feat: change', '1.1.0', 0, 'bump minor for feature')
|
||||
prepublishTest(t, 'fix: BREAKING CHANGE: change', '2.0.0', 0, 'bump major for breaking change')
|
||||
commitToVersionTest(t, 'refactor: change', '0.0.0', 1, 'abort publish w/o changes', cwd)
|
||||
commitToVersionTest(t, 'fix: change', '1.0.0', 0, 'release 1.0.0 if unpublished', cwd)
|
||||
commitToVersionTest(t, 'fix: change', '1.0.1', 0, 'bump patch for fix', cwd)
|
||||
commitToVersionTest(t, 'feat: change', '1.1.0', 0, 'bump minor for feature', cwd)
|
||||
commitToVersionTest(t, 'fix: BREAKING CHANGE: change', '2.0.0', 0, 'bump major for breaking change', cwd)
|
||||
})
|
||||
|
||||
function prepublishTest (t, message, version, code, name) {
|
||||
t.test(name, function (t) {
|
||||
t.plan(3)
|
||||
|
||||
nixt()
|
||||
.cwd(cwd)
|
||||
.env('CI', true)
|
||||
.env('npm_config_registry', 'http://127.0.0.1:4873/')
|
||||
.exec('git commit --allow-empty -m "' + message + '"')
|
||||
.run('npm run prepublish')
|
||||
.code(code)
|
||||
.stdout(/> semantic-release pre\n\nDetermining new version\n/m)
|
||||
.end(function (err) {
|
||||
t.error(err, 'nixt')
|
||||
|
||||
var pkg = JSON.parse(fs.readFileSync(cwd + '/package.json'))
|
||||
t.is(pkg.version, version, 'version')
|
||||
|
||||
if (code === 1) {
|
||||
return t.error(null, 'no publish')
|
||||
}
|
||||
|
||||
exec('npm publish --ignore-scripts', {cwd: cwd}, function (err) {
|
||||
setTimeout(function () {
|
||||
t.error(err, 'publish')
|
||||
}, 300)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user