Compare commits

..
45 Commits
Author SHA1 Message Date
Stephan Bönnemann f74f764a80 fix(npm-info): registry unexpectedly returned no json formatted error
This only affected publishing of yet unreleased packages.
2015-04-03 19:37:39 +02:00
Stephan Bönnemann d5a8cb1935 style: adhere to standard style 2015-03-22 10:44:19 +01:00
Stephan Bönnemann f32a8e7d03 chore(package): update standard 2015-03-22 10:44:06 +01:00
Stephan Bönnemann 30fd1c19eb Merge pull request #16 from tlvince/15-oauth-scope
docs(readme): add GitHub token scope notes
2015-03-22 10:33:50 +01:00
Tom Vincent f192acc1ff docs(readme): add GitHub token scope notes
Closes #15.
2015-03-22 00:15:43 +00:00
Stephan Bönnemann 4ccda66a39 docs(readme): fix language and formatting 2015-03-01 17:18:37 +01:00
Stephan Bönnemann c2d963be70 Merge pull request #12 from davidpfahler/master
docs(readme): fix ignore scripts flag
2015-02-22 00:08:59 +01:00
David Pfahler f8c4e495fd docs(readme): fix ignore scripts flag 2015-02-22 00:07:53 +01:00
Stephan Bönnemann c3b59d6a06 Merge pull request #10 from boennemann/githead-registry
refactor(pre): use `gitHead` information from registry
2015-02-13 09:13:13 +01:00
Christoph Witzko 53c0adb365 refactor(pre): use gitHead information from registry 2015-02-12 22:07:04 +01:00
Christoph Witzko 045c913342 chore(pretest): automatically clean up 2015-02-11 15:28:46 +01:00
Stephan Bönnemann 5c12e718cb docs(readme): clarify npm abbrevs 2015-02-10 12:31:48 +01:00
Christoph Witzko 4e32c7dde0 chore: updated git-head 2015-02-09 14:32:46 +01:00
Stephan Bönnemann 6f891ed781 Merge pull request #6 from boennemann/fix-git-node
refactor(post): use git-head instead of exec
2015-02-09 00:11:50 +01:00
Christoph Witzko e43ff5573b refactor(post): use git-head instead of exec 2015-02-09 00:08:52 +01:00
Christoph Witzko 19af8b7ef2 test(postpublish): get commit hash in detached HEAD mode 2015-02-09 00:07:11 +01:00
Stephan Bönnemann bf69c1ae93 fix(post): revert to execing git commands
`git-node` is nice in theory, but actually unstable and inconsistent.
2015-02-08 19:14:32 +01:00
Stephan Bönnemann 486ebed9f3 test(standard): ensure cli is tested by standard 2015-02-08 17:58:04 +01:00
Stephan Bönnemann 918e2c08a0 fix(cli): remove unused require call 2015-02-08 17:48:56 +01:00
Stephan Bönnemann a5e50e0d3d chore(travis): npm prune before running tests 2015-02-08 17:48:39 +01:00
Stephan Bönnemann 36f8643f3e docs(readme): add travis encrypt commands 2015-02-08 17:03:36 +01:00
Stephan Bönnemann c7862b8d0d docs(readme): update setup section 2015-02-08 17:03:36 +01:00
Stephan Bönnemann fee6d6baba feat(setup): setup package.json 2015-02-08 17:03:36 +01:00
Stephan Bönnemann 44eb633458 test(setup): setup package.json 2015-02-08 17:03:35 +01:00
Stephan Bönnemann e92bd610bb feat(verify): setup requirement verification 2015-02-08 17:03:35 +01:00
Stephan Bönnemann 5f96cd4589 test(verify): setup requirement verification 2015-02-08 14:19:22 +01:00
Stephan Bönnemann 6f7b382130 docs(readme): show only build status of master 2015-02-08 14:19:21 +01:00
Stephan Bönnemann ed39847510 docs(readme): add link to where you can get a github token 2015-02-08 14:19:21 +01:00
Stephan Bönnemann 7b170b1167 docs(readme): add synopsis of commit message conventions 2015-02-08 14:19:21 +01:00
Stephan Bönnemann c957308716 docs(readme): clarifications for ci and non-ci environments 2015-02-08 14:19:21 +01:00
Stephan Bönnemann 54fe414bab fix(cli): prepublish is executed on link; does nothing then 2015-02-08 14:19:21 +01:00
Stephan Bönnemann e0fc4840de fix(cli): automatically run in debug mode locally
BREAKING CHANGE: The `--no-ci` flag is gone. If you want to run `semantic-release` locally now you have to explicitly run `semantic-release pre --debug=false` && `semantic-release post --debug=false`
2015-02-08 14:19:21 +01:00
Stephan Bönnemann d94c6b76d3 chore(travis): actually require that all minions pass
I'm so good at bash, I'm using string concatenation for this.
2015-02-08 10:31:09 +01:00
Stephan Bönnemann be249fa0e0 chore(package): improve description and keywords 2015-02-08 10:30:35 +01:00
Stephan Bönnemann f5c6c9622a chore(package): clarify that the version is a placeholder 2015-02-08 00:40:01 +01:00
Stephan Bönnemann b309732953 docs(readme): add faq and clarify requirements 2015-02-08 00:35:55 +01:00
Stephan Bönnemann 6ef503001f docs(readme): typos, clarity and formating 2015-02-07 14:21:31 +01:00
Stephan Bönnemann 5610fafb25 chore(travis): also test on node 0.12 2015-02-07 12:26:39 +01:00
Stephan Bönnemann a4dc9c3ef9 docs(readme): verbose instructions and explanations 2015-02-07 12:21:53 +01:00
Stephan Bönnemann 466be0eb7e chore(travis): set up travis_after_all to deploy once 2015-02-05 23:49:00 +01:00
Stephan Bönnemann 7bf436fe8a chore(travis): add iojs to build matrix 2015-02-05 23:34:26 +01:00
Christoph Witzko 4ed5f73a04 chore: updated github-release-fake-server 2015-02-05 14:55:40 +01:00
Stephan Bönnemann 782c992755 Merge pull request #4 from boennemann/refactor-exec
Refactor exec
2015-02-05 13:14:42 +01:00
Christoph Witzko 5d8f6561a8 refactor: use git-node instead of exec git 2015-02-05 13:09:14 +01:00
Christoph Witzko 96fe49662a refactor: use request instead of exec curl 2015-02-05 12:39:20 +01:00
22 changed files with 566 additions and 144 deletions
+17 -1
View File
@@ -1,6 +1,8 @@
language: node_js
node_js:
- iojs-v1
- '0.10'
- '0.12'
sudo: false
cache:
directories:
@@ -8,7 +10,20 @@ cache:
notifications:
email: false
before_install:
- npm i -g npm@^2.0.0
- 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
@@ -18,3 +33,4 @@ deploy:
on:
branch: master
repo: boennemann/semantic-release
condition: "$BUILD_LEADER$BUILD_AGGREGATE_STATUS = YESothers_succeeded"
+196 -8
View File
@@ -1,14 +1,110 @@
# semantic-release
[![Build Status](https://travis-ci.org/boennemann/semantic-release.svg)](https://travis-ci.org/boennemann/semantic-release)
[![Build Status](https://travis-ci.org/boennemann/semantic-release.svg?branch=master)](https://travis-ci.org/boennemann/semantic-release)
[![Dependency Status](https://david-dm.org/boennemann/semantic-release.svg)](https://david-dm.org/boennemann/semantic-release)
[![devDependency Status](https://david-dm.org/boennemann/semantic-release/dev-status.svg)](https://david-dm.org/boennemann/semantic-release#info=devDependencies)
[![NPM](https://nodei.co/npm/semantic-release.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/semantic-release/)
```bash
npm i semantic-release
## What is this thing even?
`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.
This is fully integrated with the `npm` lifecycle, so all you have to do is to setup your CI to `npm publish`.
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.
![https://twitter.com/trodrigues/status/509301317467373571](https://cloud.githubusercontent.com/assets/908178/6091690/cc86f58c-aeb8-11e4-94cb-15f15f486cde.png)
## How does this 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.
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.
```
You *need* to set it up inside your `package.json`:
<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.
### 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
### The `publish` step
`npm` does its thing.
### The `postpublish` step
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
Note: The GitHub Release automatically creates a tag, too.
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).
## How do I set this up?
### Installation
First of all you need to install `semantic-release` and save it as a `devDependency`.
```bash
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
```
### Package
```bash
./node_modules/.bin/semantic-release setup
```
What this does:
#### Scripts
The setup command configures `scripts` inside the `package.json`:
```json
"scripts": {
@@ -17,8 +113,100 @@ You *need* to set it up inside your `package.json`:
}
```
Note: `semantic-release` works around a limitation in npm's "prepublish" hook. Once a version is published 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 6to5 && 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
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>
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: 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: 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 when 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 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.
### 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)
+4
View File
@@ -2,8 +2,12 @@
set -e
[ -d ".tmp" ] && ./bin/post-test
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
-78
View File
@@ -1,78 +0,0 @@
#!/usr/bin/env node
'use strict'
var abbrev = require('abbrev')
var confirm = require('confirm-simple')
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'
},
default: {
token: process.env.GH_TOKEN || process.env.TOKEN || process.env.GITHUB_TOKEN,
'github-url': process.env.GH_URL
}
})
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')) process.exit(0)
return confirmCI(function () {
console.log('Determining new version')
var publish = false
if (isAbbrev(npmArgv, 'publish')) publish = true
require('../src/pre')(argv, efh(function (result) {
if (!result) {
console.log('Nothing changed. Not publishing.')
process.exit(1)
}
console.log('Publishing v' + result)
if (!publish) process.exit(0)
require('../src/restart')(efh(function () {
process.exit(1)
}))
}))
})
}
if (~argv._.indexOf('post')) {
return confirmCI(function () {
require('../src/post')(argv, 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.')
}
}))
})
}
function confirmCI (cb) {
if (process.env.CI || argv.ci === false) 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)
})
}
function isAbbrev (argv, command) {
return argv._.some(Object.prototype.hasOwnProperty.bind(abbrev(command)))
}
+79
View File
@@ -0,0 +1,79 @@
#!/usr/bin/env node
'use strict'
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 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')) 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, 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, 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)))
}
+1 -1
View File
@@ -4,7 +4,7 @@ var efh = require('error-first-handler')
module.exports = {
efh: efh,
standard: efh(function(err) {
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)
+27
View File
@@ -0,0 +1,27 @@
'use strict'
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 res = {
version: null,
gitHead: null,
pkg: null
}
if (response.statusCode === 404 || !body) return cb(null, res)
var pkg = JSON.parse(body)
if (pkg.error && response.statusCode !== 404) return cb(pkg.error)
res.version = pkg['dist-tags'].latest
res.gitHead = pkg.versions[res.version].gitHead
res.pkg = pkg
cb(null, res)
}))
}
+3 -5
View File
@@ -4,10 +4,8 @@ var git = require('conventional-changelog/lib/git')
var efh = require('../error').efh
module.exports = function (cb) {
git.latestTag(efh(cb)(function (from) {
git.getCommits({from: from}, efh(cb)(function (commits) {
cb(null, commits)
}))
module.exports = function (from, cb) {
git.getCommits({from: from}, efh(cb)(function (commits) {
cb(null, commits)
}))
}
+2 -2
View File
@@ -4,8 +4,8 @@ var analyze = require('./analyze')
var commits = require('./commits')
var efh = require('../error').efh
module.exports = function (cb) {
commits(efh(cb)(function (commits) {
module.exports = function (gitHead, cb) {
commits(gitHead, efh(cb)(function (commits) {
cb(null, analyze(commits))
}))
}
-17
View File
@@ -1,17 +0,0 @@
'use strict'
var exec = require('child_process').exec
var efh = require('./error').efh
module.exports = function (pkg, cb) {
if (!pkg.name) return cb(new Error('Package must have a name'))
exec('curl -s "' + process.env.npm_config_registry + pkg.name + '"', efh(cb)(function(stdout) {
var pkg = JSON.parse(stdout)
if (pkg.error) return cb(null, null, true)
cb(null, pkg['dist-tags'].latest)
}))
}
+15 -10
View File
@@ -1,39 +1,44 @@
{
"name": "semantic-release",
"description": "semantic semver compliant package publishing",
"version": "0.0.6",
"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": {
"abbrev": "^1.0.5",
"confirm-simple": "^1.0.3",
"conventional-changelog": "0.0.11",
"error-first-handler": "^1.0.1",
"git-head": "^1.2.1",
"github": "^0.2.3",
"github-url-from-git": "^1.4.0",
"ini": "^1.3.2",
"minimist": "^1.1.0",
"parse-github-repo-url": "^1.0.0",
"request": "^2.53.0",
"semver": "^4.2.0"
},
"devDependencies": {
"github-release-fake-server": "^1.1.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": "^2.3.1",
"standard": "^3.2.1",
"tap-spec": "^2.2.0",
"tape": "^3.5.0"
},
"engines": {
"node": "^0.10.0",
"npm": "^2.0.0"
"iojs": "^1",
"node": "^0.10",
"npm": "^2"
},
"homepage": "https://github.com/boennemann/semantic-release",
"keywords": [
"author",
"automation",
"release",
"publish",
"module",
@@ -49,9 +54,9 @@
"url": "https://github.com/boennemann/semantic-release.git"
},
"scripts": {
"postpublish": "./bin/semantic-release post",
"postpublish": "./bin/semantic-release.js post",
"posttest": "./bin/post-test",
"prepublish": "./bin/semantic-release pre",
"prepublish": "./bin/semantic-release.js pre",
"pretest": "./bin/pre-test",
"test": "standard && node tests | tap-spec"
}
+2 -2
View File
@@ -1,10 +1,10 @@
'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')
@@ -31,7 +31,7 @@ module.exports = function (options, cb) {
repository: parseUrl(repository),
file: false
}, efh(cb)(function (log) {
exec('git rev-parse HEAD', efh(cb)(function (hash) {
gitHead(efh(cb)(function (hash) {
var ghRepo = parseSlug(repository)
var release = {
owner: ghRepo[0],
+8 -8
View File
@@ -5,17 +5,17 @@ var fs = require('fs')
var semver = require('semver')
var type = require('../lib/type')
var version = require('../lib/version')
var npmInfo = require('../lib/npm-info')
var efh = require('../lib/error').efh
module.exports = function (options, cb) {
type(efh(cb)(function (type) {
if (!type) return cb(null, null)
var path = './package.json'
var pkg = JSON.parse(fs.readFileSync(path))
version(pkg, efh(cb)(function (version, unpublished) {
pkg.version = unpublished ? '1.0.0' : semver.inc(version, type)
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)
+42
View File
@@ -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))
}
+71
View File
@@ -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
}
+2
View File
@@ -8,3 +8,5 @@ require('./scenarios/install')(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)
+1 -1
View File
@@ -23,7 +23,7 @@ module.exports = function (test, createModule) {
.run(command)
.code(0)
.stdout(/> semantic-release pre\n$/m)
.end(function(err) {
.end(function (err) {
t.is(pkg + '', fs.readFileSync(cwd + '/package.json') + '', 'package')
t.error(err, 'nixt')
})
+20 -7
View File
@@ -25,19 +25,32 @@ module.exports = function (test, createModule) {
}
}, efh()(function (name, cwd) {
test('postpublish', function (t) {
t.test('publish new version to github releases', function (t) {
t.plan(1)
nixt()
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"')
.run('npm run postpublish')
.code(0)
.stdout(/> semantic-release post\n\nGenerating changelog from.*\nParsed/m)
.end(function(err) {
t.test('publish new version to github releases', function (t) {
t.plan(1)
base.clone()
.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()
.exec('git checkout `git rev-parse HEAD`')
.run('npm run postpublish')
.end(function (err) {
t.error(err, 'nixt')
})
})
@@ -49,7 +62,7 @@ module.exports = function (test, createModule) {
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:\*\* the next big thing/.test(res.body), 'body')
t.ok(/\n\n\n#### Features\n\n\* \*\*cool:\*\*\n.*the next big thing/.test(res.body), 'body')
})
})
})
+3 -3
View File
@@ -28,7 +28,7 @@ module.exports = function (test, createModule) {
.run('npm run prepublish')
.code(code)
.stdout(/> semantic-release pre\n\nDetermining new version\n/m)
.end(function(err) {
.end(function (err) {
t.error(err, 'nixt')
var pkg = JSON.parse(fs.readFileSync(cwd + '/package.json'))
@@ -38,8 +38,8 @@ module.exports = function (test, createModule) {
return t.error(null, 'no publish')
}
exec('npm publish --ignore-scripts', {cwd: cwd}, function(err) {
setTimeout(function() {
exec('npm publish --ignore-scripts', {cwd: cwd}, function (err) {
setTimeout(function () {
t.error(err, 'publish')
}, 300)
})
+1 -1
View File
@@ -27,7 +27,7 @@ module.exports = function (test, createModule) {
.run(command)
.code(1)
.stdout(/Everything is alright/)
.end(function(err) {
.end(function (err) {
t.error(err, 'nixt')
})
})
+38
View File
@@ -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')
})
})
})
}))
}
+34
View File
@@ -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')
})
})
})
}))
}