Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5dabed534 | ||
|
|
be9bb40dd2 | ||
|
|
4821aff69e | ||
|
|
773ecf693f | ||
|
|
f2dd66f614 | ||
|
|
3b921a63c5 | ||
|
|
785e7f7b3b | ||
|
|
b38f1e0687 | ||
|
|
323b5d5bf8 | ||
|
|
3369f31a8d | ||
|
|
63096c50c4 | ||
|
|
248c41a504 | ||
|
|
e0eee05a7e | ||
|
|
08ae05fb82 | ||
|
|
e445effdcf | ||
|
|
29469e0b8a | ||
|
|
615d796f24 | ||
|
|
49de103753 | ||
|
|
749eb11e58 | ||
|
|
36f5555d8e | ||
|
|
d4f6ee0d6a | ||
|
|
6763a006d2 | ||
|
|
0307894914 | ||
|
|
06c464f9d8 | ||
|
|
f74f764a80 | ||
|
|
d5a8cb1935 | ||
|
|
f32a8e7d03 | ||
|
|
30fd1c19eb | ||
|
|
f192acc1ff | ||
|
|
4ccda66a39 | ||
|
|
c2d963be70 | ||
|
|
f8c4e495fd | ||
|
|
c3b59d6a06 | ||
|
|
53c0adb365 | ||
|
|
045c913342 | ||
|
|
5c12e718cb | ||
|
|
4e32c7dde0 | ||
|
|
6f891ed781 | ||
|
|
e43ff5573b | ||
|
|
19af8b7ef2 | ||
|
|
bf69c1ae93 | ||
|
|
486ebed9f3 | ||
|
|
918e2c08a0 | ||
|
|
a5e50e0d3d | ||
|
|
36f8643f3e | ||
|
|
c7862b8d0d | ||
|
|
fee6d6baba | ||
|
|
44eb633458 | ||
|
|
e92bd610bb | ||
|
|
5f96cd4589 | ||
|
|
6f7b382130 | ||
|
|
ed39847510 | ||
|
|
7b170b1167 | ||
|
|
c957308716 | ||
|
|
54fe414bab | ||
|
|
e0fc4840de | ||
|
|
d94c6b76d3 | ||
|
|
be249fa0e0 | ||
|
|
f5c6c9622a | ||
|
|
b309732953 | ||
|
|
6ef503001f | ||
|
|
5610fafb25 | ||
|
|
a4dc9c3ef9 | ||
|
|
466be0eb7e | ||
|
|
7bf436fe8a | ||
|
|
4ed5f73a04 | ||
|
|
782c992755 | ||
|
|
5d8f6561a8 | ||
|
|
96fe49662a | ||
|
|
875bb038a1 | ||
|
|
89f1928769 | ||
|
|
3799ad0cb6 | ||
|
|
7380d586ee | ||
|
|
eb470712d7 | ||
|
|
f2484b8e42 | ||
|
|
73b888fdc3 | ||
|
|
f44cedbaa7 | ||
|
|
a540c402a9 | ||
|
|
ffbd39e78a | ||
|
|
81df21b924 | ||
|
|
d22b98a4ee | ||
|
|
c936e8be4b | ||
|
|
019aeeabe1 | ||
|
|
19fd15c1dc | ||
|
|
16cf9aee9b | ||
|
|
f2c701ca1b | ||
|
|
b39fecbdc2 | ||
|
|
f7faebb175 |
@@ -1,2 +1,3 @@
|
||||
node_modules
|
||||
*.log
|
||||
.tmp
|
||||
|
||||
+19
@@ -1,12 +1,30 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- iojs-v2
|
||||
- iojs-v1
|
||||
- '0.10'
|
||||
- '0.12'
|
||||
sudo: false
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
notifications:
|
||||
email: false
|
||||
before_install:
|
||||
- npm i -g npm@^2.0.0
|
||||
before_script:
|
||||
- npm prune
|
||||
- curl -Lo travis_after_all.py https://raw.github.com/dmakhno/travis_after_all/master/travis_after_all.py
|
||||
after_success:
|
||||
- python travis_after_all.py
|
||||
- export $(cat .to_export_back)
|
||||
after_failure:
|
||||
- python travis_after_all.py
|
||||
- export $(cat .to_export_back)
|
||||
before_deploy:
|
||||
- rm -f travis_after_all.py .to_export_back
|
||||
after_script:
|
||||
- echo leader=$BUILD_LEADER status=$BUILD_AGGREGATE_STATUS
|
||||
deploy:
|
||||
provider: npm
|
||||
email: stephan@boennemann.me
|
||||
@@ -16,3 +34,4 @@ deploy:
|
||||
on:
|
||||
branch: master
|
||||
repo: boennemann/semantic-release
|
||||
condition: "$BUILD_LEADER$BUILD_AGGREGATE_STATUS = YESothers_succeeded"
|
||||
|
||||
@@ -1,29 +1,179 @@
|
||||
# semantic-release
|
||||
[](https://travis-ci.org/boennemann/semantic-release)
|
||||
[](https://travis-ci.org/boennemann/semantic-release)
|
||||
[](https://david-dm.org/boennemann/semantic-release)
|
||||
[](https://david-dm.org/boennemann/semantic-release#info=devDependencies)
|
||||
|
||||
[](https://nodei.co/npm/semantic-release/)
|
||||
|
||||
## What is `semantic-release` about?
|
||||
|
||||
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.
|
||||
|
||||
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).
|
||||
|
||||
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 it work?
|
||||
|
||||
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.
|
||||
|
||||
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:
|
||||
|
||||
- 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
|
||||
|
||||
`npm` does its thing.
|
||||
|
||||
### The `postpublish` step
|
||||
|
||||
After `npm` published the new version the `postpublish` step does this:
|
||||
|
||||
- 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 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 a "Could not pack" error that you can *safely ignore* [npm/npm#7118](https://github.com/npm/npm/issues/7118).
|
||||
|
||||
## How you can set it up
|
||||
|
||||
### Installation
|
||||
|
||||
First of all you need to install `semantic-release` and save it as a `devDependency`.
|
||||
|
||||
```bash
|
||||
npm i semantic-release
|
||||
npm install --save-dev semantic-release
|
||||
# Btw, if you're feeling lazy you can just type this – it's the same thing.
|
||||
npm i -D semantic-release
|
||||
```
|
||||
|
||||
`semantic-release` provides "prepublish" and "postpublish" hooks so you automatically release the correct version.
|
||||
### Package
|
||||
|
||||
Run `semantic-release pre` right before `npm publish` and `semantic-release post` right after.
|
||||
```bash
|
||||
./node_modules/.bin/semantic-release setup
|
||||
```
|
||||
|
||||
For maximum comfort you can automate this inside your `package.json`:
|
||||
What this does:
|
||||
|
||||
#### Scripts
|
||||
|
||||
The setup command configures `scripts` inside the `package.json`:
|
||||
|
||||
```json
|
||||
"scripts": {
|
||||
"prepublish": "semantic-release pre"
|
||||
"prepublish": "semantic-release pre",
|
||||
"postpublish": "semantic-release post"
|
||||
}
|
||||
```
|
||||
|
||||
Note: Even though `semantic-release` works around a limitation in npm's "prepublish" hook using it prints an error that you can *safely ignore*.
|
||||
See [npm/npm#7118](https://github.com/npm/npm/issues/7118).
|
||||
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"`.
|
||||
|
||||
MIT License
|
||||
2015 Stephan Bönnemann
|
||||
#### Version
|
||||
|
||||
It would be preferable not to have a version field in the `package.json` at all, but due to an `npm` limitation it is required to have a _not yet published_ version in there [npm/npm#7118](https://github.com/npm/npm/issues/7118). Because of this the version gets changed to `"0.0.0-semantically-released"` until `npm` _hopefully_ removes its limitations.
|
||||
|
||||
#### Repository
|
||||
|
||||
If you haven't defined your GitHub repository in the `package.json`s [repository field](https://docs.npmjs.com/files/package.json#repository) the remote `origin`'s repository is used.
|
||||
|
||||
### CI Server
|
||||
|
||||
Inside your `.travis.yml`:
|
||||
|
||||
```yml
|
||||
language: node_js
|
||||
node_js:
|
||||
- iojs-v1
|
||||
sudo: false
|
||||
cache:
|
||||
directories:
|
||||
- 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-access-to-your-repo>
|
||||
deploy:
|
||||
provider: npm
|
||||
email: <your-npm-mail@example.com>
|
||||
# Very important. Don't forget this one.
|
||||
skip_cleanup: true
|
||||
# Travis currently only supports the old auth key format.
|
||||
# Do `echo -n "<username>:<password>" | base64` to get it.
|
||||
# You should encrypt this:
|
||||
# `travis encrypt $(echo -n "<username>:<password>" | base64) --add deploy.api_key`
|
||||
api_key: <npm-api-key>
|
||||
on:
|
||||
branch: master
|
||||
repo: <user>/<repo>
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
Note: Your CI environment has to export `CI=true` in order for `semantic-release` not to automatically perform a dry run. Travis CI does this by default.
|
||||
|
||||
Note: It is crucial that your CI server also fetches all tags when checking out your repository. Travis CI does this by default.
|
||||
|
||||
Note: If you have a more sophisticated build with multiple jobs you should have a look at [travis-after-all](https://github.com/dmakhno/travis_after_all), which is also configured for this [package](.travis.yml).
|
||||
|
||||
## ITYM*FAQ*LT
|
||||
> I think you might frequently ask questions like these
|
||||
|
||||
### Why is the `package.json`'s version not updated in my repository?
|
||||
|
||||
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 where it _really_ is required.
|
||||
|
||||
### Is there a way to preview which version would currently get published?
|
||||
|
||||
If you're running `npm publish` locally `semantic-release` automatically performs a dry run. This does log the version that would currently get published, but only if you `git fetch --tags` before.
|
||||
|
||||
### Can I run this on my own machine rather than on a CI server?
|
||||
|
||||
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: 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`?
|
||||
|
||||
`npm` offers the `--ignore-scripts` flag. Doing `npm publish --ignore-scripts` doesn't execute the `prepublish` and `postpublish` scripts.
|
||||
|
||||
### Is it _really_ a good idea to release on every push?
|
||||
|
||||
It is indeed a great idea because it _forces_ you to follow best practices. If you don't feel comfortable making every passing feature or fix on your master branch addressable via `npm` you might not treat your master right. Have a look at [branch workflows](https://guides.github.com/introduction/flow/index.html). If you still think you should have control over the exact point in time of your release, e.g. because you are following a release schedule, configure your CI server to release only on the `production`/`deploy`/`release` branch and push your code there in certain intervals.
|
||||
|
||||
### Why should I trust `semantic-release` with my releases? What if it breaks?
|
||||
|
||||
`semantic-release` has a full integration-test suite that tests _actual_ `npm` publishes and _actual_ GitHub Releases (with private registry/API) on node.js `^0.10`, `^0.12` and io.js `^1`. A new version won't get published if it doesn't pass on all these engines.
|
||||
|
||||
## License
|
||||
|
||||
MIT License
|
||||
2015 © Stephan Bönnemann and [contributors](https://github.com/boennemann/semantic-release/graphs/contributors)
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict'
|
||||
|
||||
var confirm = require('confirm-simple')
|
||||
|
||||
var argv = require('minimist')(process.argv.slice(2), {
|
||||
alias: {
|
||||
d: 'debug',
|
||||
dry: 'debug',
|
||||
t: 'token'
|
||||
},
|
||||
default: {
|
||||
token: process.env.GH_TOKEN || process.env.TOKEN || process.env.GITHUB_TOKEN
|
||||
}
|
||||
})
|
||||
|
||||
var npmArgv = process.env.npm_config_argv
|
||||
npmArgv = npmArgv ? JSON.parse(npmArgv).cooked : []
|
||||
|
||||
if (~argv._.indexOf('pre')) {
|
||||
var publish = false
|
||||
|
||||
// see src/restart.js
|
||||
if (~npmArgv.indexOf('--semantic-release-rerun')) process.exit(0)
|
||||
// the `prepublish` hook is also executed when the package is installed
|
||||
// in this case we abort the command and do nothing.
|
||||
if (~npmArgv.indexOf('install')) process.exit(0)
|
||||
|
||||
return confirmCI(function () {
|
||||
if (~npmArgv.indexOf('publish')) publish = true
|
||||
|
||||
console.log('Determining new version')
|
||||
|
||||
require('../src/pre')(argv, function (err, result) {
|
||||
if (err) {
|
||||
console.log('Something went wrong.')
|
||||
throw err
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
console.log('Nothing changed. Not publishing.')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
console.log('Publishing v' + result)
|
||||
if (publish) require('../src/restart')()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if (~argv._.indexOf('post')) {
|
||||
return confirmCI(function () {
|
||||
require('../src/post')(argv, function (err) {
|
||||
if (err) {
|
||||
console.log('Something went wrong.')
|
||||
throw err
|
||||
}
|
||||
|
||||
// see src/restart.js
|
||||
if (~npmArgv.indexOf('--semantic-release-rerun')) {
|
||||
console.log('Everything is alright :) npm will now print an error message that you can safely ignore.')
|
||||
process.exit(1)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function confirmCI (cb) {
|
||||
if (process.env.CI) return cb(null, true)
|
||||
|
||||
confirm('Not running in a CI enviroment. Are you sure you want to run this hook?', function (ok) {
|
||||
if (!ok) process.exit(1)
|
||||
cb(null, ok)
|
||||
})
|
||||
}
|
||||
Executable
+87
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict'
|
||||
|
||||
var readFile = require('fs').readFileSync
|
||||
|
||||
var abbrev = require('abbrev')
|
||||
var minimist = require('minimist')
|
||||
|
||||
var efh = require('../lib/error').standard
|
||||
|
||||
var argv = minimist(process.argv.slice(2), {
|
||||
alias: {
|
||||
d: 'debug',
|
||||
dry: 'debug',
|
||||
t: 'token',
|
||||
g: 'github-url'
|
||||
},
|
||||
booleans: ['debug'],
|
||||
default: {
|
||||
debug: !process.env.CI,
|
||||
token: process.env.GH_TOKEN || process.env.TOKEN || process.env.GITHUB_TOKEN,
|
||||
'github-url': process.env.GH_URL
|
||||
}
|
||||
})
|
||||
|
||||
var plugins = JSON.parse(readFile('./package.json')).release || {}
|
||||
|
||||
var npmArgv = process.env.npm_config_argv ?
|
||||
minimist(JSON.parse(process.env.npm_config_argv).cooked) :
|
||||
{_: []}
|
||||
|
||||
if (~argv._.indexOf('pre')) {
|
||||
// see src/restart.js
|
||||
if (npmArgv['semantic-release-rerun']) process.exit(0)
|
||||
// the `prepublish` hook is also executed when the package is installed
|
||||
// in this case we abort the command and do nothing.
|
||||
if (
|
||||
isAbbrev(npmArgv, 'install') ||
|
||||
isAbbrev(npmArgv, 'link') ||
|
||||
isAbbrev(npmArgv, 'pack')
|
||||
) process.exit(0)
|
||||
|
||||
if (argv.debug) console.log('This is a dry run')
|
||||
|
||||
console.log('Determining new version')
|
||||
|
||||
var publish = false
|
||||
if (isAbbrev(npmArgv, 'publish')) publish = true
|
||||
|
||||
// require a correct setup during publish
|
||||
if (publish && !argv.debug && !require('../src/verify')(argv)) process.exit(1)
|
||||
|
||||
require('../src/pre')(argv, plugins, efh(function (result) {
|
||||
if (!result) {
|
||||
console.log('Nothing changed. Not publishing.')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
console.log('Publishing v' + result)
|
||||
if (!publish) process.exit(0)
|
||||
|
||||
if (argv.debug) process.exit(1)
|
||||
|
||||
require('../src/restart')(efh(function () {
|
||||
process.exit(1)
|
||||
}))
|
||||
}))
|
||||
}
|
||||
|
||||
if (~argv._.indexOf('post')) {
|
||||
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.')
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
if (~argv._.indexOf('setup')) {
|
||||
require('../src/setup')()
|
||||
console.log('"package.json" is set up properly. Now configure your CI server.')
|
||||
console.log('https://github.com/boennemann/semantic-release#ci-server')
|
||||
}
|
||||
|
||||
function isAbbrev (argv, command) {
|
||||
return argv._.some(Object.prototype.hasOwnProperty.bind(abbrev(command)))
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
npm run test:style
|
||||
|
||||
function cleanup {
|
||||
set +e
|
||||
|
||||
cp .tmp/.npmrc ~/.npmrc
|
||||
|
||||
cat .tmp/sinopia.pid | xargs kill
|
||||
|
||||
cat .tmp/ghrs.pid | xargs kill
|
||||
|
||||
rm -rf .tmp
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
mkdir -p .tmp/modules
|
||||
|
||||
export DEBUG=ghrs:cli
|
||||
|
||||
./node_modules/.bin/sinopia ./tests/config.yml & echo $! >> .tmp/sinopia.pid
|
||||
./node_modules/.bin/github-release-fake-server -p 4343 & echo $! >> .tmp/ghrs.pid
|
||||
|
||||
sleep 0.5
|
||||
|
||||
cp ~/.npmrc .tmp/.npmrc
|
||||
|
||||
cp tests/.npmrc ~/.npmrc
|
||||
|
||||
npm run test:integration
|
||||
@@ -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]
|
||||
}
|
||||
}))
|
||||
})
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
'use strict'
|
||||
|
||||
var efh = require('error-first-handler')
|
||||
|
||||
module.exports = {
|
||||
efh: efh,
|
||||
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, err.stack)
|
||||
if (err.message) return console.log(err.message)
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
'use strict'
|
||||
|
||||
var request = require('request')
|
||||
|
||||
var efh = require('./error').efh
|
||||
|
||||
module.exports = function (pkgName, cb) {
|
||||
var encodedPkgName = pkgName.replace(/\//g, '%2F')
|
||||
request(process.env.npm_config_registry + encodedPkgName, efh(cb)(function (response, body) {
|
||||
var res = {
|
||||
version: null,
|
||||
gitHead: null,
|
||||
pkg: null
|
||||
}
|
||||
|
||||
if (response.statusCode === 404 || !body) return cb(null, res)
|
||||
|
||||
var pkg = JSON.parse(body)
|
||||
|
||||
if (pkg.error) return cb(pkg.error)
|
||||
|
||||
res.version = pkg['dist-tags'].latest
|
||||
res.gitHead = pkg.versions[res.version].gitHead
|
||||
res.pkg = pkg
|
||||
|
||||
cb(null, res)
|
||||
}))
|
||||
}
|
||||
@@ -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,14 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
var git = require('conventional-changelog/lib/git')
|
||||
|
||||
module.exports = function (cb) {
|
||||
git.latestTag(function (err, from) {
|
||||
if (err) return cb(err)
|
||||
|
||||
git.getCommits({from: from}, function (err, commits) {
|
||||
if (err) return cb(err)
|
||||
cb(null, commits)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
var commits = require('./commits')
|
||||
var analyze = require('./analyze')
|
||||
|
||||
module.exports = function (cb) {
|
||||
commits(function (err, commits) {
|
||||
if (err) return cb(err)
|
||||
|
||||
cb(null, analyze(commits))
|
||||
})
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
var exec = require('child_process').exec
|
||||
var unlink = require('fs').unlinkSync
|
||||
|
||||
module.exports = function (pkg, cb) {
|
||||
if (!pkg.name) return cb('Package must have a name')
|
||||
|
||||
exec('npm show ' + pkg.name + ' version', function(err, stdout, stderr) {
|
||||
if (err) unlink('./npm-debug.log')
|
||||
|
||||
if (err && /is not in the npm registry/m.test(stderr)) return cb(null, null, true)
|
||||
|
||||
if (err) return cb(err)
|
||||
|
||||
cb(null, stdout.trim())
|
||||
})
|
||||
}
|
||||
+31
-11
@@ -1,26 +1,44 @@
|
||||
{
|
||||
"name": "semantic-release",
|
||||
"description": "semantic semver compliant package publishing",
|
||||
"version": "0.0.3",
|
||||
"description": "automated semver compliant package publishing",
|
||||
"version": "0.0.0-semantically-released",
|
||||
"author": "Stephan Bönnemann <stephan@boennemann.me>",
|
||||
"bin": "./bin/semantic-release",
|
||||
"bin": "./bin/semantic-release.js",
|
||||
"bugs": {
|
||||
"url": "https://github.com/boennemann/semantic-release/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"confirm-simple": "^1.0.3",
|
||||
"conventional-changelog": "0.0.11",
|
||||
"github": "^0.2.3",
|
||||
"abbrev": "^1.0.5",
|
||||
"conventional-changelog": "0.0.17",
|
||||
"error-first-handler": "^1.0.1",
|
||||
"git-head": "^1.2.1",
|
||||
"github": "0.2.4",
|
||||
"github-url-from-git": "^1.4.0",
|
||||
"ini": "^1.3.2",
|
||||
"minimist": "^1.1.0",
|
||||
"parse-github-repo-url": "^1.0.0",
|
||||
"semver": "^4.2.0"
|
||||
"request": "^2.53.0",
|
||||
"semver": "^4.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"standard": "^2.3.1"
|
||||
"github-release-fake-server": "^1.3.0",
|
||||
"lodash.defaults": "^3.0.0",
|
||||
"nano-uid": "^0.2.0",
|
||||
"nixt": "^0.4.1",
|
||||
"sinopia": "^1.0.0",
|
||||
"standard": "^3.2.1",
|
||||
"tap-spec": "^3.0.0",
|
||||
"tape": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"iojs": "^1",
|
||||
"node": "^0.10",
|
||||
"npm": "^2"
|
||||
},
|
||||
"homepage": "https://github.com/boennemann/semantic-release",
|
||||
"keywords": [
|
||||
"author",
|
||||
"automation",
|
||||
"release",
|
||||
"publish",
|
||||
"module",
|
||||
@@ -36,8 +54,10 @@
|
||||
"url": "https://github.com/boennemann/semantic-release.git"
|
||||
},
|
||||
"scripts": {
|
||||
"prepublish": "./bin/semantic-release pre",
|
||||
"postpublish": "./bin/semantic-release post",
|
||||
"test": "standard"
|
||||
"postpublish": "./bin/semantic-release.js post",
|
||||
"prepublish": "./bin/semantic-release.js pre",
|
||||
"test:style": "standard",
|
||||
"test:integration": "node tests | tap-spec",
|
||||
"test": "./bin/test"
|
||||
}
|
||||
}
|
||||
|
||||
+20
-21
@@ -1,33 +1,33 @@
|
||||
'use strict'
|
||||
|
||||
var exec = require('child_process').exec
|
||||
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 github = new GitHubApi({
|
||||
version: '3.0.0'
|
||||
})
|
||||
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('Package must have a repository')
|
||||
if (!repository) return cb(new Error('Package must have a repository'))
|
||||
|
||||
changelog({
|
||||
version: pkg.version,
|
||||
repository: parseUrl(repository),
|
||||
file: false
|
||||
}, function(err, log) {
|
||||
if (err) return cb(err)
|
||||
var notesGenerator = require(plugins.notes || '../lib/release-notes')
|
||||
|
||||
exec('git rev-parse HEAD', function(err, hash) {
|
||||
if (err) return cb(err)
|
||||
var config = options['github-url'] ? url.parse(options['github-url']) : {}
|
||||
|
||||
var github = new GitHubApi({
|
||||
version: '3.0.0',
|
||||
port: config.port,
|
||||
protocol: (config.protocol || '').split(':')[0] || null,
|
||||
host: config.hostname
|
||||
})
|
||||
|
||||
notesGenerator(efh(cb)(function (log) {
|
||||
gitHead(efh(cb)(function (hash) {
|
||||
var ghRepo = parseSlug(repository)
|
||||
var release = {
|
||||
owner: ghRepo[0],
|
||||
@@ -43,10 +43,9 @@ module.exports = function (options, cb) {
|
||||
token: options.token
|
||||
})
|
||||
|
||||
github.releases.createRelease(release, function(err) {
|
||||
if (err) return cb(err)
|
||||
github.releases.createRelease(release, efh(cb)(function () {
|
||||
cb(null, true)
|
||||
})
|
||||
})
|
||||
})
|
||||
}))
|
||||
}))
|
||||
}))
|
||||
}
|
||||
|
||||
+16
-13
@@ -4,23 +4,26 @@ var fs = require('fs')
|
||||
|
||||
var semver = require('semver')
|
||||
|
||||
var type = require('../lib/type')
|
||||
var version = require('../lib/version')
|
||||
var getCommits = require('../lib/commits')
|
||||
var npmInfo = require('../lib/npm-info')
|
||||
var efh = require('../lib/error').efh
|
||||
|
||||
module.exports = function (options, cb) {
|
||||
type(function (err, type) {
|
||||
if (err) return cb(err)
|
||||
if (!type) return cb(null, null)
|
||||
module.exports = function (options, plugins, cb) {
|
||||
var path = './package.json'
|
||||
var pkg = JSON.parse(fs.readFileSync(path))
|
||||
|
||||
var path = './package.json'
|
||||
var pkg = JSON.parse(fs.readFileSync(path))
|
||||
version(pkg, function (err, version, unpublished) {
|
||||
if (err) return cb(err)
|
||||
if (!pkg.name) return cb(new Error('Package must have a name'))
|
||||
|
||||
pkg.version = unpublished ? '1.0.0' : semver.inc(version, type)
|
||||
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)
|
||||
pkg.version = res.version ? semver.inc(res.version, type) : '1.0.0'
|
||||
if (!options.debug) fs.writeFileSync(path, JSON.stringify(pkg, null, 2))
|
||||
|
||||
cb(null, pkg.version)
|
||||
})
|
||||
})
|
||||
}))
|
||||
}))
|
||||
}
|
||||
|
||||
+15
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
var spawn = require('child_process').spawn
|
||||
|
||||
module.exports = function () {
|
||||
var exports = module.exports = function (cb) {
|
||||
// npm loads package.json data before running the `prepublish` hook
|
||||
// changing the version on `prepublish` has no effect
|
||||
// see https://github.com/npm/npm/issues/7118
|
||||
@@ -10,7 +10,21 @@ module.exports = function () {
|
||||
// the package.json is then loaded again and the correct version will be published
|
||||
|
||||
var child = spawn('npm', ['publish', '--semantic-release-rerun'])
|
||||
var handler = exports.handleCloseAndExit.bind(null, cb)
|
||||
|
||||
child.stdout.pipe(process.stdout)
|
||||
child.stderr.pipe(process.stderr)
|
||||
|
||||
child.on('close', handler)
|
||||
child.on('exit', handler)
|
||||
child.on('error', cb)
|
||||
}
|
||||
|
||||
exports.handleCloseAndExit = function (cb, code, signal) {
|
||||
if (code === 0) return cb(null)
|
||||
cb({
|
||||
code: code,
|
||||
signal: signal,
|
||||
message: 'npm publish failed'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
'use strict'
|
||||
|
||||
var fs = require('fs')
|
||||
|
||||
var ini = require('ini')
|
||||
var ghUrl = require('github-url-from-git')
|
||||
|
||||
module.exports = function () {
|
||||
var pkg = JSON.parse(fs.readFileSync('./package.json') + '')
|
||||
|
||||
// ensure a yet unpublished version
|
||||
pkg.version = '0.0.0-semantically-released'
|
||||
|
||||
// set up scripts
|
||||
var pre = 'semantic-release pre'
|
||||
var post = 'semantic-release post'
|
||||
|
||||
if (!pkg.scripts) pkg.scripts = {}
|
||||
|
||||
if (!pkg.scripts.prepublish) pkg.scripts.prepublish = pre
|
||||
else if (!(new RegExp(pre).test(pkg.scripts.prepublish))) pkg.scripts.prepublish += ' && ' + pre
|
||||
|
||||
if (!pkg.scripts.postpublish) pkg.scripts.postpublish = post
|
||||
else if (!(new RegExp(post).test(pkg.scripts.postpublish))) pkg.scripts.postpublish += ' && ' + post
|
||||
|
||||
// set up repository
|
||||
if (!pkg.repository || !pkg.repository.url) {
|
||||
var config = ini.decode(fs.readFileSync('./.git/config') + '')
|
||||
var repo = config['remote "origin"'].url
|
||||
|
||||
if (repo) pkg.repository = { type: 'git', url: ghUrl(repo) }
|
||||
}
|
||||
|
||||
// set up devDependency
|
||||
if (!pkg.devDependencies) pkg.devDependencies = {}
|
||||
|
||||
if (!pkg.devDependencies['semantic-release']) {
|
||||
pkg.devDependencies['semantic-release'] = '^' + require('../package.json').version
|
||||
}
|
||||
|
||||
fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 2) + '\n')
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
'use strict'
|
||||
|
||||
var fs = require('fs')
|
||||
|
||||
var exports = module.exports = function (input) {
|
||||
var options = exports.verifyOptions(input)
|
||||
var pkg = exports.verifyPackage()
|
||||
var travis = exports.verifyTravis()
|
||||
return options && pkg && travis
|
||||
}
|
||||
|
||||
exports.verifyTravis = function () {
|
||||
try {
|
||||
var travis = fs.readFileSync('.travis.yml') + ''
|
||||
} catch (e) {
|
||||
return true
|
||||
}
|
||||
|
||||
var passed = true
|
||||
|
||||
if (!/\sdeploy:/m.test(travis)) {
|
||||
console.error('You should configure deployments inside the ".travis.yml".')
|
||||
passed = false
|
||||
}
|
||||
|
||||
if (!/skip_cleanup:/m.test(travis)) {
|
||||
console.error('You must set "skip_cleanup" to "true" inside the ".travis.yml".')
|
||||
passed = false
|
||||
}
|
||||
|
||||
return passed
|
||||
}
|
||||
|
||||
exports.verifyPackage = function () {
|
||||
var passed = true
|
||||
|
||||
try {
|
||||
var pkg = fs.readFileSync('./package.json') + ''
|
||||
} catch (e) {
|
||||
console.error('You must have a "package.json" present.')
|
||||
passed = false
|
||||
pkg = '{}'
|
||||
}
|
||||
|
||||
try {
|
||||
pkg = JSON.parse(pkg)
|
||||
} catch (e) {
|
||||
console.error('You must have a "package.json" that is valid JSON.')
|
||||
return false
|
||||
}
|
||||
|
||||
if (!pkg.repository || !pkg.repository.url) {
|
||||
console.error('You must define your GitHub "repository" inside the "package.json".')
|
||||
passed = false
|
||||
}
|
||||
|
||||
if (!pkg.scripts || !pkg.scripts.prepublish || !pkg.scripts.postpublish) {
|
||||
console.error('You must define your "scripts" inside the "package.json".')
|
||||
passed = false
|
||||
}
|
||||
|
||||
return passed
|
||||
}
|
||||
|
||||
exports.verifyOptions = function (options) {
|
||||
if (!options) return true
|
||||
if (options.token) return true
|
||||
|
||||
console.error('You must define a GitHub token.')
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
test:{SHA}C+7Hteo/D9vJXQ3UfzxbwnXaijM=
|
||||
@@ -0,0 +1,3 @@
|
||||
_auth=dGVzdDpmb28=
|
||||
email=test@example.com
|
||||
registry=http://127.0.0.1:4873/
|
||||
@@ -0,0 +1,17 @@
|
||||
storage: ../.tmp/.storage
|
||||
|
||||
auth:
|
||||
htpasswd:
|
||||
file: ./.htpasswd
|
||||
|
||||
uplinks:
|
||||
npmjs:
|
||||
url: https://registry.npmjs.org/
|
||||
|
||||
logs:
|
||||
- {type: stdout, format: pretty, level: silent}
|
||||
|
||||
packages:
|
||||
'*':
|
||||
allow_access: all
|
||||
allow_publish: all
|
||||
@@ -0,0 +1,13 @@
|
||||
'use strict'
|
||||
|
||||
var test = require('tape')
|
||||
|
||||
var createModule = require('./lib/create-module')
|
||||
|
||||
require('./scenarios/custom-analyzer')(test, createModule)
|
||||
require('./scenarios/ignore')(test, createModule)
|
||||
require('./scenarios/prepublish')(test, createModule)
|
||||
require('./scenarios/postpublish')(test, createModule)
|
||||
require('./scenarios/publish')(test, createModule)
|
||||
require('./scenarios/verify')(test, createModule)
|
||||
require('./scenarios/setup')(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)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
'use strict'
|
||||
|
||||
var exec = require('child_process').exec
|
||||
var join = require('path').join
|
||||
|
||||
var efh = require('error-first-handler')
|
||||
var defaults = require('lodash.defaults')
|
||||
var uid = require('nano-uid')()
|
||||
|
||||
module.exports = function (input) {
|
||||
var cb = Array.prototype.pop.call(arguments)
|
||||
uid.generate(5, efh(cb)(function (id) {
|
||||
var pkg = defaults((typeof input === 'object' ? input : {}), {
|
||||
name: id,
|
||||
version: '0.0.0',
|
||||
devDependencies: {
|
||||
'semantic-release': 'file:../../../'
|
||||
},
|
||||
scripts: {
|
||||
prepublish: 'semantic-release pre',
|
||||
postpublish: 'semantic-release post'
|
||||
},
|
||||
publishConfig: {
|
||||
registry: 'http://localhost:4873/'
|
||||
}
|
||||
})
|
||||
|
||||
id = pkg.name
|
||||
var cwd = join(__dirname, '../../.tmp/modules', id)
|
||||
|
||||
exec(
|
||||
'mkdir ' + cwd + ' && ' +
|
||||
'cd ' + cwd + ' && ' +
|
||||
'git init && ' +
|
||||
'echo \'' + JSON.stringify(pkg, null, 2) + '\' >> package.json && ' +
|
||||
'git add . && ' +
|
||||
'git config user.email "integration@test" && ' +
|
||||
'git config user.name "Integration Test" && ' +
|
||||
'git commit -m "initial" && ' +
|
||||
'npm install'
|
||||
, efh(cb)(function (stdout) {
|
||||
cb(null, id, cwd)
|
||||
}))
|
||||
}))
|
||||
}
|
||||
@@ -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,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,37 @@
|
||||
'use strict'
|
||||
|
||||
var fs = require('fs')
|
||||
|
||||
var efh = require('error-first-handler')
|
||||
var nixt = require('nixt')
|
||||
|
||||
module.exports = function (test, createModule) {
|
||||
createModule(efh()(function (name, cwd) {
|
||||
test('ignore', function (t) {
|
||||
ignoreTest(t, 'npm install', 'not doing anything when the module is installed')
|
||||
ignoreTest(t, 'npm i', 'not doing anything when the module is installed with abbrevd command')
|
||||
ignoreTest(t, 'npm link', 'not doing anything when the module is linked')
|
||||
ignoreTest(t, 'npm lin', 'not doing anything when the module is linked with abbrevd command')
|
||||
ignoreTest(t, 'npm pack', 'not doing anything when the module is packed')
|
||||
ignoreTest(t, 'npm pa', 'not doing anything when the module is packed with abbrevd command')
|
||||
})
|
||||
|
||||
function ignoreTest (t, command, name, last) {
|
||||
t.test(name, function (t) {
|
||||
t.plan(2)
|
||||
|
||||
var pkg = fs.readFileSync(cwd + '/package.json')
|
||||
|
||||
nixt()
|
||||
.cwd(cwd)
|
||||
.run(command)
|
||||
.code(0)
|
||||
.stdout(/> semantic-release pre\n$/m)
|
||||
.end(function (err) {
|
||||
t.is(pkg + '', fs.readFileSync(cwd + '/package.json') + '', 'package')
|
||||
t.error(err, 'nixt')
|
||||
})
|
||||
})
|
||||
}
|
||||
}))
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
'use strict'
|
||||
|
||||
var path = require('path')
|
||||
|
||||
var efh = require('error-first-handler')
|
||||
var GitHubApi = require('github')
|
||||
var nixt = require('nixt')
|
||||
|
||||
var github = new GitHubApi({
|
||||
version: '3.0.0',
|
||||
port: 4343,
|
||||
protocol: 'http',
|
||||
host: '127.0.0.1'
|
||||
})
|
||||
|
||||
github.authenticate({
|
||||
type: 'oauth',
|
||||
token: '***'
|
||||
})
|
||||
|
||||
module.exports = function (test, createModule) {
|
||||
createModule({
|
||||
version: '2.0.0',
|
||||
repository: {
|
||||
type: 'git',
|
||||
url: 'http://github.com/user/repo'
|
||||
}
|
||||
}, efh()(function (name, cwd) {
|
||||
test('postpublish', function (t) {
|
||||
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')
|
||||
})
|
||||
})
|
||||
|
||||
t.test('publish new version (with detached HEAD) to github releases', function (t) {
|
||||
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) {
|
||||
t.error(err, 'nixt')
|
||||
})
|
||||
})
|
||||
|
||||
t.test('correct data published', function (t) {
|
||||
t.plan(4)
|
||||
|
||||
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')
|
||||
t.ok(/\n\n\n#### Features\n\n\* \*\*cool:\*\*\n.*the next big thing/.test(res.body), 'body')
|
||||
})
|
||||
})
|
||||
})
|
||||
}))
|
||||
|
||||
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)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
'use strict'
|
||||
|
||||
var efh = require('error-first-handler')
|
||||
|
||||
var commitToVersionTest = require('../lib/commit-to-version-test')
|
||||
|
||||
module.exports = function (test, createModule) {
|
||||
createModule(efh()(function (name, cwd) {
|
||||
test('prepublish', function (t) {
|
||||
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)
|
||||
})
|
||||
}))
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
'use strict'
|
||||
|
||||
var efh = require('error-first-handler')
|
||||
var nixt = require('nixt')
|
||||
|
||||
module.exports = function (test, createModule) {
|
||||
test('publish', function (t) {
|
||||
publishTest(t, 'npm publish', 'pre and post hooks work as a part of publish')
|
||||
publishTest(t, 'npm pub', 'pre and post hooks work as a part of publish with abbrevd command')
|
||||
|
||||
function publishTest (t, command, testname, last) {
|
||||
createModule({
|
||||
repository: {
|
||||
type: 'git',
|
||||
url: 'http://github.com/user/repo'
|
||||
}
|
||||
}, efh()(function (name, cwd) {
|
||||
t.test(testname, function (t) {
|
||||
t.plan(1)
|
||||
|
||||
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: super"')
|
||||
.run(command)
|
||||
.code(1)
|
||||
.stdout(/Everything is alright/)
|
||||
.end(function (err) {
|
||||
t.error(err, 'nixt')
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
'use strict'
|
||||
|
||||
var join = require('path').join
|
||||
var readFile = require('fs').readFileSync
|
||||
|
||||
var efh = require('error-first-handler')
|
||||
var nixt = require('nixt')
|
||||
|
||||
module.exports = function (test, createModule) {
|
||||
createModule({
|
||||
repository: {},
|
||||
scripts: {
|
||||
postpublish: 'npm run gh-pages'
|
||||
}
|
||||
}, efh()(function (name, cwd) {
|
||||
test('setup', function (t) {
|
||||
t.test('setup "package.json"', function (t) {
|
||||
t.plan(5)
|
||||
|
||||
nixt()
|
||||
.cwd(cwd)
|
||||
.exec('git remote add origin git@github.com:user/repo.git')
|
||||
.run('./node_modules/.bin/semantic-release setup')
|
||||
.code(0)
|
||||
.end(function (err) {
|
||||
t.error(err, 'nixt')
|
||||
|
||||
var pkg = JSON.parse(readFile(join(cwd, 'package.json')))
|
||||
|
||||
t.is(pkg.version, '0.0.0-semantically-released', 'version')
|
||||
t.is(pkg.repository.url, 'https://github.com/user/repo', 'repo')
|
||||
t.is(pkg.scripts.prepublish, 'semantic-release pre', 'pre')
|
||||
t.is(pkg.scripts.postpublish, 'npm run gh-pages && semantic-release post', 'post')
|
||||
})
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
'use strict'
|
||||
|
||||
var efh = require('error-first-handler')
|
||||
var nixt = require('nixt')
|
||||
|
||||
module.exports = function (test, createModule) {
|
||||
createModule({
|
||||
repository: {},
|
||||
scripts: {
|
||||
prepublish: 'semantic-release pre --no-token'
|
||||
}
|
||||
}, efh()(function (name, cwd) {
|
||||
test('verify', function (t) {
|
||||
t.test('verify package and options before publishing', function (t) {
|
||||
t.plan(1)
|
||||
|
||||
nixt()
|
||||
.cwd(cwd)
|
||||
.env('CI', true)
|
||||
.run('npm publish')
|
||||
.stderr(new RegExp(
|
||||
'You must define a GitHub token\.\n' +
|
||||
'You must define your GitHub "repository" inside the "package.json"\.\n' +
|
||||
'You must define your "scripts" inside the "package.json"\.'
|
||||
, 'm'
|
||||
))
|
||||
.code(1)
|
||||
.end(function (err) {
|
||||
t.error(err, 'nixt')
|
||||
})
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
Reference in New Issue
Block a user