Compare commits

..
36 Commits
Author SHA1 Message Date
Stephan Bönnemann 875bb038a1 chore(package): change version to yet unpublished version
one last time hopefully >:(
2015-02-05 01:35:53 +01:00
Stephan Bönnemann 89f1928769 test(publish): initial scenario 2015-02-05 01:33:50 +01:00
Christoph Witzko 3799ad0cb6 test(postpublish): initial scenario 2015-02-05 01:04:52 +01:00
Christoph Witzko 7380d586ee feat(release): configure github api endpoint via environment variables 2015-02-05 01:00:42 +01:00
Christoph Witzko eb470712d7 test: added github-release-fake-server 2015-02-05 01:00:42 +01:00
Christoph Witzko f2484b8e42 test: set npm registry inside .npmrc 2015-02-04 20:18:19 +01:00
Stephan Bönnemann 73b888fdc3 docs(readme): remove usage outside of npm scripts 2015-02-04 19:02:37 +01:00
Stephan Bönnemann f44cedbaa7 text: expose correct registry to environment 2015-02-04 18:58:37 +01:00
Stephan Bönnemann a540c402a9 fix(version): use $npm_config_registry variable to ensure the right registry
BREAKING CHANGE: This breaks the usage of the `semantic-release` CLI outside of npm scripts.
2015-02-04 18:56:31 +01:00
Stephan Bönnemann ffbd39e78a test(prepublish): initial scenario 2015-02-04 15:39:05 +01:00
Stephan Bönnemann 81df21b924 test(install): initial scenario 2015-02-04 15:23:30 +01:00
Stephan Bönnemann d22b98a4ee test(create-module): helper to create fresh repo/module 2015-02-04 15:23:21 +01:00
Stephan Bönnemann c936e8be4b test: setup private npm registry w/sinopia 2015-02-04 15:23:16 +01:00
Stephan Bönnemann 019aeeabe1 refator: use error-first-handler 2015-02-03 20:45:03 +01:00
Stephan Bönnemann 19fd15c1dc refactor(cli): parse npmArgv w/minimist 2015-02-03 14:21:42 +01:00
Christoph WitzkoandStephan Bönnemann 16cf9aee9b fix(cli): hooks work correctly w/abbrevd npm commands 2015-02-03 14:09:02 +01:00
Stephan Bönnemann f2c701ca1b feat(cli): use --no-cli to publish locally w/o prompt 2015-02-02 23:30:55 +01:00
Stephan Bönnemann b39fecbdc2 fix(restart): correctly prevent double npm publish run 2015-02-02 17:57:06 +01:00
Stephan Bönnemann f7faebb175 docs(readme): fix json syntax 2015-02-02 16:33:57 +01:00
Stephan Bönnemann cf36c2fe9b chore(package): change dummy version to yet unpublished version 2015-02-02 16:26:23 +01:00
Stephan Bönnemann a48b0c957d docs(readme): document npm scripts automation capabilities 2015-02-02 16:26:23 +01:00
Stephan Bönnemann a1c86fc0d0 fix(post): correctly link issues and commits in changelog 2015-02-02 16:26:23 +01:00
Stephan Bönnemann bd90936927 feat(semantic-release): let the user confirm if they run hooks outside of CI 2015-02-02 16:26:22 +01:00
Stephan Bönnemann c0aebd9873 chore(package): configure prepublish hook 2015-02-02 15:37:16 +01:00
Stephan Bönnemann 9191260cb0 feat(pre): make hook "prepublish" compatible 2015-02-02 15:37:16 +01:00
Stephan Bönnemann 7fa0754ff2 chore: remove prepublish script and migrate to travis hook 2015-02-02 04:52:30 +01:00
Stephan Bönnemann 7d21697d78 chore(travis): correctly disable email notifications 2015-02-02 04:49:23 +01:00
Stephan Bönnemann 07c5d08d35 chore(package): provide dummy version so publish even starts 2015-02-02 04:37:11 +01:00
Stephan Bönnemann a89e7e6b1e chore(travis): skip_cleanup to provide version 2015-02-02 04:34:15 +01:00
Stephan Bönnemann 1d9350597a fix(semantic-release): not running prepublish on install 2015-02-02 04:31:00 +01:00
Stephan Bönnemann fd11c85692 chore(scripts): use relative path for own cli 2015-02-02 04:16:29 +01:00
Stephan Bönnemann fe750f7b9e feat(semantic-release): add initial version of cli 2015-02-02 04:13:58 +01:00
Stephan Bönnemann 17ad82bfbc feat(post): add initial version of command 2015-02-02 04:13:35 +01:00
Stephan Bönnemann 0ee9cc31e9 feat(pre): add initial version of command 2015-02-02 04:13:21 +01:00
Stephan Bönnemann f31a5dfd04 chore: meta files 2015-02-02 04:12:57 +01:00
Stephan Bönnemann 012dce2641 chore: inital commit 2014-09-15 18:18:52 +02:00
53 changed files with 582 additions and 1190 deletions
-11
View File
@@ -1,11 +0,0 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
-11
View File
@@ -1,14 +1,3 @@
# common
coverage
node_modules
test/registry/couch
test/registry/data
*.log
*.dump
.DS_Store
.nyc_output
.test
.tmp
# build-artifacts
dist
-18
View File
@@ -1,18 +0,0 @@
# common
coverage
node_modules
test/registry/couch
test/registry/data
*.log
*.dump
.DS_Store
.nyc_output
.test
.tmp
# source/config
src
*.yml
.gitignore
.editorconfig
.npmrc
+13 -15
View File
@@ -1,22 +1,20 @@
sudo: false
language: node_js
node_js:
- '0.10'
sudo: false
cache:
directories:
- node_modules
notifications:
email: false
node_js:
- iojs-v2
- iojs-v1
- '0.12'
- '0.10'
before_install:
- npm i -g npm@^2.0.0
before_script:
- npm prune
- curl -Lo travis_after_all.py https://git.io/vLSON
after_success:
- python travis_after_all.py
- export $(cat .to_export_back)
- if [[ $BUILD_LEADER = YES ]]; then npm run coverage:upload; fi
- npm run semantic-release
- npm i -g npm@^2.0.0
deploy:
provider: npm
email: stephan@boennemann.me
skip_cleanup: true
api_key:
secure: Lq1FZweaNr/Ah8M7h3oWQ59HTswzvcksTUfzWb/dpqNn5FECN9I+4gi79EQPD62ZbJDCuDHY0EEEDLdnaB1z8N7kOj1RtmvC1k0teTEXFsGBPS4evXakRj+AfoBAGsTaXHqBYBOvYBxJT2Md/UoOgPSQjtAdZSNsmoFb1xkngQ0=
on:
branch: master
repo: boennemann/semantic-release
+17 -13
View File
@@ -1,20 +1,24 @@
# semantic-release
[![Build Status](https://travis-ci.org/semantic-release/semantic-release.svg?branch=next)](https://travis-ci.org/semantic-release/semantic-release)
[![Coverage Status](https://coveralls.io/repos/semantic-release/semantic-release/badge.svg?branch=next&service=github)](https://coveralls.io/github/semantic-release/semantic-release?branch=next)
[![Dependency Status](https://david-dm.org/semantic-release/semantic-release/next.svg)](https://david-dm.org/semantic-release/semantic-release/next)
[![devDependency Status](https://david-dm.org/semantic-release/semantic-release/next/dev-status.svg)](https://david-dm.org/semantic-release/semantic-release/next#info=devDependencies)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://github.com/feross/standard)
[![Build Status](https://travis-ci.org/boennemann/semantic-release.svg)](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/)
## What is `semantic-release` about?
```bash
npm i semantic-release
```
You *need* to set it up inside your `package.json`:
At its core `semantic-release` is a set of conventions that gives you entirely automated, semver-compliant package publishing. _Coincidentally_ these conventions make sense on their own, like having meaningful commit messages.
```json
"scripts": {
"prepublish": "semantic-release pre",
"postpublish": "semantic-release post"
}
```
[![JSConfBP Talk](https://cloud.githubusercontent.com/assets/908178/8032541/e9bf6300-0dd6-11e5-92c9-8a39211368af.png)](https://www.youtube.com/watch?v=tc2UgG5L7WM&index=6&list=PLFZ5NyC0xHDaaTy6tY9p0C0jd_rRRl5Zm)
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).
> This talk gives you a complete introduction to the underlying concepts
The next branch is a completely rewritten version of `semantic-release`, that isn't fully tested and documented yet.
It has lots and lots of great new features, but also breaks a lot of things.
Unless you're adventurous you should look at the [stable master branch](https://github.com/semantic-release/semantic-release/tree/master).
MIT License
2015 Stephan Bönnemann
Executable
+9
View File
@@ -0,0 +1,9 @@
#!/bin/sh
cat .tmp/sinopia.pid | xargs kill
cat .tmp/ghrs.pid | xargs kill
cp .tmp/.npmrc ~/.npmrc
rm -rf .tmp
Executable
+14
View File
@@ -0,0 +1,14 @@
#!/bin/sh
set -e
mkdir -p .tmp/modules
./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
+78
View File
@@ -0,0 +1,78 @@
#!/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)))
}
-13
View File
@@ -1,13 +0,0 @@
#!/usr/bin/env node
/* istanbul ignore next */
try {
require('../dist')
} catch (err) {
if (err.code === 'MODULE_NOT_FOUND') {
require('babel/register')
require('../src')
} else {
console.log(err)
}
}
+14
View File
@@ -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)
if (err.message) return console.log(err.message)
console.log(err)
})
}
+20
View File
@@ -0,0 +1,20 @@
'use strict'
module.exports = function (commits) {
var type = null
commits.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
}
+13
View File
@@ -0,0 +1,13 @@
'use strict'
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)
}))
}))
}
+11
View File
@@ -0,0 +1,11 @@
'use strict'
var analyze = require('./analyze')
var commits = require('./commits')
var efh = require('../error').efh
module.exports = function (cb) {
commits(efh(cb)(function (commits) {
cb(null, analyze(commits))
}))
}
+17
View File
@@ -0,0 +1,17 @@
'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)
}))
}
+36 -71
View File
@@ -1,93 +1,58 @@
{
"name": "semantic-release",
"description": "automated semver compliant package publishing",
"author": "Stephan Bönnemann <stephan@boennemann.me> (http://boennemann.me)",
"bin": {
"semantic-release": "./bin/semantic-release.js"
},
"description": "semantic semver compliant package publishing",
"version": "0.0.6",
"author": "Stephan Bönnemann <stephan@boennemann.me>",
"bin": "./bin/semantic-release",
"bugs": {
"url": "https://github.com/semantic-release/semantic-release/issues"
},
"bundleDependencies": [
"@semantic-release/commit-analyzer",
"@semantic-release/condition-travis",
"@semantic-release/error",
"@semantic-release/release-notes-generator"
],
"config": {
"nyc": {
"exclude": [
".test",
"node_modules"
]
}
"url": "https://github.com/boennemann/semantic-release/issues"
},
"dependencies": {
"@semantic-release/commit-analyzer": "^2.0.0",
"@semantic-release/condition-travis": "^4.0.0",
"@semantic-release/error": "^1.0.0",
"@semantic-release/release-notes-generator": "^2.0.0",
"git-head": "^1.2.1",
"github": "^0.2.4",
"lodash": "^3.9.3",
"nopt": "^3.0.3",
"npm-registry-client": "^6.4.0",
"npmconf": "^2.1.2",
"npmlog": "^1.2.1",
"abbrev": "^1.0.5",
"confirm-simple": "^1.0.3",
"conventional-changelog": "0.0.11",
"error-first-handler": "^1.0.1",
"github": "^0.2.3",
"github-url-from-git": "^1.4.0",
"minimist": "^1.1.0",
"parse-github-repo-url": "^1.0.0",
"require-relative": "^0.8.7",
"run-auto": "^1.1.2",
"semver": "^5.0.1"
"semver": "^4.2.0"
},
"devDependencies": {
"babel": "^5.5.8",
"coveralls": "^2.11.2",
"mkdirp": "^0.5.1",
"github-release-fake-server": "^1.1.1",
"lodash.defaults": "^3.0.0",
"nano-uid": "^0.2.0",
"nixt": "^0.4.1",
"nock": "^2.5.0",
"npm-registry-couchapp": "^2.6.11",
"nyc": "^3.0.0",
"proxyquire": "^1.5.0",
"rimraf": "^2.4.0",
"standard": "^4.2.1",
"tap": "^1.3.1"
"sinopia": "^1.0.0",
"standard": "^2.3.1",
"tap-spec": "^2.2.0",
"tape": "^3.5.0"
},
"homepage": "https://github.com/semantic-release/semantic-release/tree/next#readme",
"engines": {
"node": "^0.10.0",
"npm": "^2.0.0"
},
"homepage": "https://github.com/boennemann/semantic-release",
"keywords": [
"author",
"automation",
"changelog",
"release",
"publish",
"module",
"package",
"publish",
"release",
"semver",
"version"
"version",
"changelog"
],
"license": "MIT",
"main": "dist/index.js",
"publishConfig": {
"tag": "next"
},
"release": {
"branch": "next"
},
"main": "index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/semantic-release/semantic-release.git"
"url": "https://github.com/boennemann/semantic-release.git"
},
"scripts": {
"build": "rimraf dist && mkdirp dist && babel src --out-dir dist",
"coverage": "nyc report",
"coverage:upload": "npm run coverage -- --reporter=lcovonly && coveralls < coverage/lcov.info",
"prepublish": "npm run build",
"pretest:integration": "npm run build && npm run test:build",
"pretest:unit": "npm run build && npm run test:build",
"semantic-release": "./bin/semantic-release.js pre && npm dedupe && npm publish && ./bin/semantic-release.js post",
"test": "npm run test:style && npm run test:unit",
"test:build": "rimraf .test && mkdirp .test && babel test --out-dir .test",
"test:integration": "tap --no-cov .test/scenarios/*.js",
"test:style": "standard",
"test:unit": "nyc tap --no-cov .test/specs/*.js"
"postpublish": "./bin/semantic-release post",
"posttest": "./bin/post-test",
"prepublish": "./bin/semantic-release pre",
"pretest": "./bin/pre-test",
"test": "standard && node tests | tap-spec"
}
}
-134
View File
@@ -1,134 +0,0 @@
const { readFileSync, writeFileSync } = require('fs')
const path = require('path')
const _ = require('lodash')
const log = require('npmlog')
const nopt = require('nopt')
const npmconf = require('npmconf')
const PREFIX = 'semantic-release'
const env = process.env
const pkg = JSON.parse(readFileSync('./package.json'))
const knownOptions = {
branch: String,
debug: Boolean,
'github-token': String,
'github-url': String,
'analyze-commits': [path, String],
'generate-notes': [path, String],
'verify-conditions': [path, String],
'verify-release': [path, String]
}
const options = _.defaults(
_.mapKeys(nopt(knownOptions), (value, key) => _.camelCase(key)),
pkg.release,
{
branch: 'master',
debug: !env.CI,
githubToken: env.GH_TOKEN || env.GITHUB_TOKEN,
githubUrl: env.GH_URL
}
)
const plugins = require('./lib/plugins')(options)
npmconf.load({}, (err, conf) => {
if (err) {
log.error(PREFIX, 'Failed to load npm config.', err)
process.exit(1)
}
let npm = {
auth: {
token: env.NPM_TOKEN
},
loglevel: conf.get('loglevel'),
registry: conf.get('registry'),
tag: (pkg.publishConfig || {}).tag || conf.get('tag') || 'latest'
}
if (npm.registry[npm.registry.length - 1] !== '/') npm.registry += '/'
log.level = npm.loglevel
const config = {PREFIX, log, env, pkg, options, plugins, npm}
log.verbose(PREFIX, 'options:', _.assign({
githubToken: options.githubToken ? '***' : undefined
}), options)
log.verbose(PREFIX, 'Verifying config.')
const errors = require('./lib/verify')(config)
errors.forEach((err) => log.error(PREFIX, `${err.message} ${err.code}`))
if (errors.length) process.exit(1)
if (options.argv.remain[0] === 'pre') {
log.verbose(PREFIX, 'Running pre-script.')
log.verbose(PREFIX, 'Veriying conditions.')
plugins.verifyConditions(config, (err) => {
if (err) {
log[options.debug ? 'warn' : 'error'](PREFIX, err.message)
if (!options.debug) process.exit(1)
}
const nerfDart = require('./lib/nerf-dart')(npm.registry)
let wroteNpmRc = false
if (env.NPM_TOKEN) {
conf.set(`${nerfDart}:_authToken`, '${NPM_TOKEN}', 'project')
wroteNpmRc = true
} else if (env.NPM_OLD_TOKEN && env.NPM_EMAIL) {
// Using the old auth token format is not considered part of the public API
// This might go away anytime (i.e. once we have a better testing strategy)
conf.set('_auth', '${NPM_OLD_TOKEN}', 'project')
conf.set('email', '${NPM_EMAIL}', 'project')
wroteNpmRc = true
}
conf.save('project', (err) => {
if (err) return log.error(PREFIX, 'Failed to save npm config.', err)
if (wroteNpmRc) log.verbose(PREFIX, 'Wrote authToken to .npmrc.')
require('./pre')(config, (err, release) => {
if (err) {
log.error(PREFIX, 'Failed to determine new version.')
const args = [PREFIX, (err.code ? `${err.code} ` : '') + err.message]
if (err.stack) args.push(err.stack)
log.error(...args)
process.exit(1)
}
const message = `Determined version ${release.version} as "${npm.tag}".`
log.verbose(PREFIX, message)
if (options.debug) {
log.error(PREFIX, `${message} Not publishing in debug mode.`, release)
process.exit(1)
}
writeFileSync('./package.json', JSON.stringify(_.assign(pkg, {
version: release.version
}), null, 2))
log.verbose(PREFIX, `Wrote version ${release.version} to package.json.`)
})
})
})
} else if (options.argv.remain[0] === 'post') {
log.verbose(PREFIX, 'Running post-script.')
require('./post')(config, (err, published, release) => {
if (err) {
log.error(PREFIX, 'Failed to publish release notes.', err)
process.exit(1)
}
log.verbose(PREFIX, `${published ? 'Published' : 'Generated'} release notes.`, release)
})
} else {
log.error(PREFIX, `Command "${options.argv.remain[0]}" not recognized. User either "pre" or "post"`)
}
})
-25
View File
@@ -1,25 +0,0 @@
const { exec } = require('child_process')
module.exports = function ({lastRelease}, cb) {
const from = lastRelease.gitHead
const range = (from ? from + '..' : '') + 'HEAD'
exec(
`git log -E --format=%H==SPLIT==%B==END== ${range}`,
(err, stdout) => {
if (err) return cb(err)
cb(null, String(stdout).split('==END==\n')
.filter((raw) => !!raw.trim())
.map((raw) => {
const data = raw.split('==SPLIT==')
return {
hash: data[0],
message: data[1]
}
}))
}
)
}
-26
View File
@@ -1,26 +0,0 @@
const SemanticReleaseError = require('@semantic-release/error')
const npmlog = require('npmlog')
const RegClient = require('npm-registry-client')
module.exports = function ({pkg, npm}, cb) {
npmlog.level = npm.loglevel || 'error'
const client = new RegClient({log: npmlog})
client.get(`${npm.registry}${pkg.name}`, {
auth: npm.auth
}, (err, data) => {
if (err && err.statusCode === 404) return cb(null, {})
if (err) return cb(err)
const version = data['dist-tags'][npm.tag]
if (!version) return cb(new SemanticReleaseError(`There is no release with the dist-tag "${npm.tag}" yet. Tag a version first.`, 'ENODISTTAG'))
cb(null, {
version,
gitHead: data.versions[version].gitHead,
tag: npm.tag
})
})
}
-14
View File
@@ -1,14 +0,0 @@
// borrowed from https://github.com/npm/npm/blob/master/lib/config/nerf-dart.js
const url = require('url')
/* istanbul ignore next */
module.exports = function toNerfDart (uri) {
let parsed = url.parse(uri)
delete parsed.protocol
delete parsed.auth
delete parsed.query
delete parsed.search
delete parsed.hash
return url.resolve(url.format(parsed), '.')
}
-4
View File
@@ -1,4 +0,0 @@
/* istanbul ignore next */
module.exports = function (config, options, cb) {
cb(null)
}
-20
View File
@@ -1,20 +0,0 @@
const relative = require('require-relative')
let exports = module.exports = function (options) {
return {
analyzeCommits: exports.normalize(options.analyzeCommits, '@semantic-release/commit-analyzer'),
generateNotes: exports.normalize(options.generateNotes, '@semantic-release/release-notes-generator'),
verifyConditions: exports.normalize(options.verifyConditions, '@semantic-release/condition-travis'),
verifyRelease: exports.normalize(options.verifyRelease, './plugin-noop')
}
}
exports.normalize = function (pluginConfig, fallback) {
if (typeof pluginConfig === 'string') return relative(pluginConfig).bind(null, {})
if (pluginConfig && (typeof pluginConfig.path === 'string')) {
return relative(pluginConfig.path).bind(null, pluginConfig)
}
return require(fallback).bind(null, pluginConfig)
}
-20
View File
@@ -1,20 +0,0 @@
const SemanticReleaseError = require('@semantic-release/error')
module.exports = function (config, cb) {
const { plugins, lastRelease } = config
plugins.analyzeCommits(config, (err, type) => {
if (err) return cb(err)
if (!type) {
return cb(new SemanticReleaseError(
'There are no relevant changes, so no new version is released.',
'ENOCHANGE'
))
}
if (!lastRelease.version) return cb(null, 'initial')
cb(null, type)
})
}
-44
View File
@@ -1,44 +0,0 @@
const parseSlug = require('parse-github-repo-url')
const SemanticReleaseError = require('@semantic-release/error')
module.exports = function ({pkg, options, env}) {
let errors = []
if (!pkg.name) {
errors.push(new SemanticReleaseError(
'No "name" found in package.json.',
'ENOPKGNAME'
))
}
if (!pkg.repository || !pkg.repository.url) {
errors.push(new SemanticReleaseError(
'No "repository" found in package.json.',
'ENOPKGREPO'
))
} else if (!parseSlug(pkg.repository.url)) {
errors.push(new SemanticReleaseError(
'The "repository" field in the package.json is malformed.',
'EMALFORMEDPKGREPO'
))
}
if (options.debug) return errors
if (!options.githubToken) {
errors.push(new SemanticReleaseError(
'No github token specified.',
'ENOGHTOKEN'
))
}
if (!(env.NPM_TOKEN || (env.NPM_OLD_TOKEN && env.NPM_EMAIL))) {
errors.push(new SemanticReleaseError(
'No npm token specified.',
'ENONPMTOKEN'
))
}
return errors
}
+38 -34
View File
@@ -1,51 +1,55 @@
const url = require('url')
'use strict'
const gitHead = require('git-head')
const GitHubApi = require('github')
const parseSlug = require('parse-github-repo-url')
var exec = require('child_process').exec
var readFile = require('fs').readFileSync
var url = require('url')
module.exports = function (config, cb) {
const { pkg, options, plugins } = config
const ghConfig = options.githubUrl ? url.parse(options.githubUrl) : {}
var changelog = require('conventional-changelog')
var GitHubApi = require('github')
var parseSlug = require('parse-github-repo-url')
var parseUrl = require('github-url-from-git')
const github = new GitHubApi({
var efh = require('../lib/error').efh
module.exports = function (options, 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 config = options['github-url'] ? url.parse(options['github-url']) : {}
var github = new GitHubApi({
version: '3.0.0',
port: ghConfig.port,
protocol: (ghConfig.protocol || '').split(':')[0] || null,
host: ghConfig.hostname
port: config.port,
protocol: (config.protocol || '').split(':')[0] || null,
host: config.hostname
})
plugins.generateNotes(config, (err, log) => {
if (err) return cb(err)
gitHead((err, hash) => {
if (err) return cb(err)
const ghRepo = parseSlug(pkg.repository.url)
const release = {
changelog({
version: pkg.version,
repository: parseUrl(repository),
file: false
}, efh(cb)(function (log) {
exec('git rev-parse HEAD', efh(cb)(function (hash) {
var ghRepo = parseSlug(repository)
var release = {
owner: ghRepo[0],
repo: ghRepo[1],
name: `v${pkg.version}`,
tag_name: `v${pkg.version}`,
tag_name: 'v' + pkg.version,
target_commitish: hash,
draft: !!options.debug,
draft: options.debug,
body: log
}
if (options.debug && !options.githubToken) {
return cb(null, false, release)
}
github.authenticate({
type: 'oauth',
token: options.githubToken
token: options.token
})
github.releases.createRelease(release, (err) => {
if (err) return cb(err)
cb(null, true, release)
})
})
})
github.releases.createRelease(release, efh(cb)(function () {
cb(null, true)
}))
}))
}))
}
+19 -40
View File
@@ -1,45 +1,24 @@
const _ = require('lodash')
const auto = require('run-auto')
const semver = require('semver')
'use strict'
const getLastRelease = require('./lib/last-release')
const getCommits = require('./lib/commits')
const getType = require('./lib/type')
var fs = require('fs')
module.exports = function (config, cb) {
const {plugins} = config
auto({
lastRelease: getLastRelease.bind(null, config),
commits: ['lastRelease', (cb, results) => {
getCommits(_.assign({
lastRelease: results.lastRelease
}, config),
cb)
}],
type: ['commits', 'lastRelease', (cb, results) => {
getType(_.assign({
commits: results.commits,
lastRelease: results.lastRelease
}, config),
cb)
}]
}, (err, results) => {
if (err) return cb(err)
var semver = require('semver')
const nextRelease = {
type: results.type,
version: results.type === 'initial' ?
'1.0.0' :
semver.inc(results.lastRelease.version, results.type)
}
var type = require('../lib/type')
var version = require('../lib/version')
var efh = require('../lib/error').efh
plugins.verifyRelease(_.assign({
commits: results.commits,
lastRelease: results.lastRelease,
nextRelease
}, config), (err) => {
if (err) return cb(err)
cb(null, nextRelease)
})
})
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)
if (!options.debug) fs.writeFileSync(path, JSON.stringify(pkg, null, 2))
cb(null, pkg.version)
}))
}))
}
+30
View File
@@ -0,0 +1,30 @@
'use strict'
var spawn = require('child_process').spawn
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
// to circumvent this behavior we are calling `npm publish` inside `prepublish`
// 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'
})
}
-14
View File
@@ -1,14 +0,0 @@
const nixt = require('nixt')
module.exports = function (cwd, uri) {
return nixt()
.cwd(cwd)
.env('NPM_OLD_TOKEN', 'aW50ZWdyYXRpb246c3VjaHNlY3VyZQ==')
.env('NPM_EMAIL', 'integration@test.com')
.env('GH_TOKEN', 'ghtoken')
.env('CI', 'true')
.env('TRAVIS', 'true')
.env('TRAVIS_BRANCH', 'master')
.env('npm_config_registry', uri)
.clone()
}
-45
View File
@@ -1,45 +0,0 @@
const { exec } = require('child_process')
const { join } = require('path')
const { writeFileSync } = require('fs')
const mkdirp = require('mkdirp')
module.exports = function (name, cb) {
const cwd = join(__dirname, '../tmp', name)
mkdirp.sync(cwd)
writeFileSync(join(cwd, '.npmrc'), `
//localhost:1337/registry/_design/app/_rewrite/:username=integration
//localhost:1337/registry/_design/app/_rewrite/:email=integration@test.com`, null, 2)
writeFileSync(join(cwd, 'package.json'), JSON.stringify({
name,
repository: {
url: 'git+https://github.com/semantic-release/test'
},
_npmUser: {
name: 'integration',
email: 'integration@test.com'
},
maintainers: [{
name: 'integration',
email: 'integration@test.com'
}]
}, null, 2))
exec(`
git init &&
git config user.email "integration@test" &&
git config user.name "Integration Test" &&
git add . &&
git commit -m "chore: root"`
, {cwd}, (err, stdout, stderr) => {
if (err) {
console.log(stdout, stderr)
return cb(err)
}
cb(null, cwd)
})
}
-16
View File
@@ -1,16 +0,0 @@
const rawCommits = [
'hash-one==SPLIT==commit-one==END==\n',
'hash-two==SPLIT==commit-two==END==\n'
]
module.exports = {
exec: (command, cb) => {
cb(
null,
/\.\.HEAD/.test(command) ?
rawCommits[0] :
rawCommits.join()
)
},
'@noCallThru': true
}
-3
View File
@@ -1,3 +0,0 @@
module.exports = function (cb) {
cb(null, 'bar')
}
-6
View File
@@ -1,6 +0,0 @@
module.exports = () => ({
authenticate: () => true,
releases: {
createRelease: (release, cb) => cb(null)
}
})
-28
View File
@@ -1,28 +0,0 @@
const nock = require('nock')
const availableModule = {
'dist-tags': {
latest: '1.33.7',
foo: '0.8.15'
},
versions: {
'0.8.15': {
gitHead: 'bar'
},
'1.33.7': {
gitHead: 'HEAD'
}
}
}
module.exports = nock('http://registry.npmjs.org')
.get('/available')
.reply(200, availableModule)
.get('/tagged')
.reply(200, availableModule)
.get('/untagged')
.reply(200, availableModule)
.get('/@scoped/available')
.reply(200, availableModule)
.get('/unavailable')
.reply(404, {})
-12
View File
@@ -1,12 +0,0 @@
const { exec } = require('child_process')
const { join } = require('path')
const opts = {
cwd: join(__dirname, '../../test/registry')
}
module.exports = {
start: exec.bind(null, './start.sh', opts),
stop: exec.bind(null, './stop.sh', opts),
uri: 'http://localhost:15986/registry/_design/app/_rewrite/'
}
-19
View File
@@ -1,19 +0,0 @@
[couchdb]
database_dir = data
view_index_dir = data
delayed_commits = false
[couch_httpd_auth]
public_fields = appdotnet, avatar, avatarMedium, avatarLarge, date, email, fields, freenode, fullname, github, homepage, name, roles, twitter, type, _id, _rev
users_db_public = true
[httpd]
port = 15986
bind_address = 127.0.0.1
secure_rewrites = false
[log]
file = couch/couch.log
[admins]
admin = -pbkdf2-89582b49cd2e8443e29a841f5a76d367956a8e58,1afa2f1531a17ac97f2ac9e334293753,10
-36
View File
@@ -1,36 +0,0 @@
#!/bin/bash
# exit if an error occurs
set -e
cd $(dirname $0)
mkdir -p couch
# start couchdb as a background process, load local config, specify writable logfiles
if [[ $TRAVIS = true ]]
then
echo 'starting couch with sudo'
sudo couchdb -b -a local.ini -p couch/pid -o couch/stdout.log -e couch/stderr.log
else
couchdb -b -a local.ini -p couch/pid -o couch/stdout.log -e couch/stderr.log
fi
# wait for couch to start
sleep 5
COUCH=http://admin:password@127.0.0.1:15986
# create "registry" database
curl -X PUT $COUCH/registry
# create sample npm user
curl -X PUT $COUCH/_users/org.couchdb.user:integration -H Content-Type:application/json --data-binary '{"_id": "org.couchdb.user:integration","name": "integration","roles": [],"type": "user","password": "suchsecure","email": "integration@test.com"}'
# npm-registry-couchpp needs this variable set to run
export DEPLOY_VERSION=nope
# setup npm-registry-couchapp
npm explore npm-registry-couchapp -- npm start --npm-registry-couchapp:couch=$COUCH/registry
npm explore npm-registry-couchapp -- npm run load --npm-registry-couchapp:couch=$COUCH/registry
npm explore npm-registry-couchapp -- NO_PROMPT=yes npm run copy --npm-registry-couchapp:couch=$COUCH/registry
-12
View File
@@ -1,12 +0,0 @@
#!/bin/bash
# close couchdb background process
couchdb -d
# delete data and logs
cd $(dirname $0)
cat couch/{couch,stdout,stderr}.log
rm -rf couch
rm -rf data
-98
View File
@@ -1,98 +0,0 @@
const { join } = require('path')
const { test, tearDown } = require('tap')
const rimraf = require('rimraf')
const registry = require('../registry')
const testModule = require('../lib/test-module')
const baseScenario = require('../lib/base-scenario')
test('change version', (t) => {
t.plan(7)
registry.start((err) => {
t.error(err, 'registry started')
if (err) {
t.end()
t.bailout('registry not started')
}
testModule('change-version', (err, cwd) => {
t.error(err, 'test-module created')
if (err) {
t.end()
t.bailout('test-module not created')
}
t.test('no version', (tt) => {
tt.plan(1)
baseScenario(cwd, registry.uri)
.env('npm_config_loglevel', 'info')
.run('node ../../../bin/semantic-release.js pre')
.stderr(/ENOCHANGE/)
.code(1)
.end(tt.error)
})
t.test('initial version', (tt) => {
tt.plan(1)
baseScenario(cwd, registry.uri)
.exec('git commit -m "feat: initial" --allow-empty')
.exec('node ../../../bin/semantic-release.js pre')
.run('npm publish')
.stdout(/1\.0\.0/)
.code(0)
.end(tt.error)
})
t.test('patch version', (tt) => {
tt.plan(1)
baseScenario(cwd, registry.uri)
.exec('git commit -m "fix: foo" --allow-empty')
.exec('node ../../../bin/semantic-release.js pre')
.run('npm publish')
.stdout(/1\.0\.1/)
.code(0)
.end(tt.error)
})
t.test('feature version', (tt) => {
tt.plan(1)
baseScenario(cwd, registry.uri)
.exec('git commit -m "feat: foo" --allow-empty')
.exec('node ../../../bin/semantic-release.js pre')
.run('npm publish')
.code(0)
.stdout(/1\.1\.0/)
.end(tt.error)
})
t.test('breaking version', (tt) => {
tt.plan(1)
baseScenario(cwd, registry.uri)
.exec('git commit -m "feat: foo\n\n BREAKING CHANGE: bar" --allow-empty')
.exec('node ../../../bin/semantic-release.js pre')
.run('npm publish')
.code(0)
.stdout(/2\.0\.0/)
.end(tt.error)
})
})
})
})
tearDown(() => {
function cb (err, stdout, stderr) {
if (err) console.log(err)
if (stdout) console.log(stdout)
if (stderr) console.log(stderr)
}
rimraf(join(__dirname, '../tmp'), cb)
registry.stop(cb)
})
-32
View File
@@ -1,32 +0,0 @@
const test = require('tap').test
const proxyquire = require('proxyquire')
const commits = proxyquire('../../dist/lib/commits', {
'child_process': require('../mocks/child-process')
})
test('commits since last release', (t) => {
t.test('get all commits', (tt) => {
commits({lastRelease: {}}, (err, commits) => {
tt.error(err)
tt.is(commits.length, 2, 'all commits')
tt.is(commits[0].hash, 'hash-one', 'parsed hash')
tt.is(commits[1].message, 'commit-two', 'parsed message')
tt.end()
})
})
t.test('get commits since hash', (tt) => {
commits({lastRelease: {gitHead: 'hash'}}, (err, commits) => {
tt.error(err)
tt.is(commits.length, 1, 'specified commits')
tt.is(commits[0].hash, 'hash-one', 'parsed hash')
tt.is(commits[0].message, 'commit-one', 'parsed message')
tt.end()
})
})
t.end()
})
-79
View File
@@ -1,79 +0,0 @@
const { defaults } = require('lodash')
const test = require('tap').test
require('../mocks/registry')
const lastRelease = require('../../dist/lib/last-release')
const npm = {
registry: 'http://registry.npmjs.org/',
tag: 'latest'
}
test('last release from registry', (t) => {
t.plan(5)
t.test('get release from package name', (tt) => {
lastRelease({
pkg: {name: 'available'},
npm
}, (err, release) => {
tt.error(err)
tt.is(release.version, '1.33.7', 'version')
tt.is(release.gitHead, 'HEAD', 'gitHead')
tt.is(release.tag, 'latest', 'dist-tag')
tt.end()
})
})
t.test('get release from a tagged package\'s name', (tt) => {
lastRelease({
pkg: {name: 'tagged'},
npm: defaults({tag: 'foo'}, npm)
}, (err, release) => {
tt.error(err)
tt.is(release.version, '0.8.15', 'version')
tt.is(release.gitHead, 'bar', 'gitHead')
tt.is(release.tag, 'foo', 'dist-tag')
tt.end()
})
})
t.test('get error from an untagged package\'s name', (tt) => {
lastRelease({
pkg: {name: 'untagged'},
npm: defaults({tag: 'bar'}, npm)
}, (err) => {
tt.is(err.code, 'ENODISTTAG', 'error')
tt.end()
})
})
t.test('get release from scoped package name', (tt) => {
lastRelease({
pkg: {name: '@scoped/available'},
npm
}, (err, release) => {
tt.error(err)
tt.is(release.version, '1.33.7', 'version')
tt.is(release.gitHead, 'HEAD', 'gitHead')
tt.is(release.tag, 'latest', 'dist-tag')
tt.end()
})
})
t.test('get nothing from not yet published package name', (tt) => {
lastRelease({
pkg: {name: 'unavailable'},
npm
}, (err, release) => {
tt.error(err)
tt.is(release.version, undefined, 'no version')
tt.end()
})
})
})
-43
View File
@@ -1,43 +0,0 @@
const test = require('tap').test
const plugins = require('../../dist/lib/plugins')
test('export plugins', (t) => {
t.plan(4)
const defaultPlugins = plugins({})
t.is(typeof defaultPlugins.analyzeCommits, 'function')
t.is(typeof defaultPlugins.generateNotes, 'function')
t.is(typeof defaultPlugins.verifyConditions, 'function')
t.is(typeof defaultPlugins.verifyRelease, 'function')
})
test('normalize and load plugin', (t) => {
t.test('load from string', (tt) => {
const plugin = plugins.normalize('./dist/lib/plugin-noop')
tt.is(typeof plugin, 'function')
tt.end()
})
t.test('load from object', (tt) => {
const plugin = plugins.normalize({
path: './dist/lib/plugin-noop'
})
tt.is(typeof plugin, 'function')
tt.end()
})
t.test('load from object', (tt) => {
const plugin = plugins.normalize(null, '../../dist/lib/plugin-noop')
tt.is(typeof plugin, 'function')
tt.end()
})
})
-68
View File
@@ -1,68 +0,0 @@
const { defaults } = require('lodash')
const test = require('tap').test
const proxyquire = require('proxyquire')
const post = proxyquire('../../dist/post', {
'git-head': require('../mocks/git-head'),
github: require('../mocks/github')
})
const pkg = {
version: '1.0.0',
repository: {url: 'http://github.com/whats/up.git'}
}
const plugins = {generateNotes: (pkg, cb) => cb(null, 'the log')}
const defaultRelease = {
owner: 'whats',
repo: 'up',
name: 'v1.0.0',
tag_name: 'v1.0.0',
target_commitish: 'bar',
body: 'the log'
}
test('full post run', (t) => {
t.test('in debug mode w/o token', (tt) => {
post({
options: {debug: true},
pkg,
plugins
}, (err, published, release) => {
tt.error(err)
tt.is(published, false)
tt.match(release, defaults({draft: true}, defaultRelease))
tt.end()
})
})
t.test('in debug mode w/token', (tt) => {
post({
options: {debug: true, githubToken: 'yo'},
pkg,
plugins
}, (err, published, release) => {
tt.error(err)
tt.is(published, true)
tt.match(release, defaults({draft: true}, defaultRelease))
tt.end()
})
})
t.test('production', (tt) => {
post({
options: {githubToken: 'yo'},
pkg,
plugins
}, (err, published, release) => {
tt.error(err)
tt.is(published, true)
tt.match(release, defaultRelease)
tt.end()
})
})
})
-50
View File
@@ -1,50 +0,0 @@
const test = require('tap').test
const proxyquire = require('proxyquire')
require('../mocks/registry')
const pre = proxyquire('../../dist/pre', {
'child_process': require('../mocks/child-process')
})
const plugins = {
verifyRelease: (release, cb) => cb(null, release),
analyzeCommits: (commits, cb) => cb(null, 'major')
}
const npm = {
registry: 'http://registry.npmjs.org/',
tag: 'latest'
}
test('full pre run', (t) => {
t.test('increase version', (tt) => {
tt.plan(3)
pre({
npm,
pkg: {name: 'available'},
plugins
}, (err, release) => {
tt.error(err)
tt.is(release.type, 'major')
tt.is(release.version, '2.0.0')
})
})
t.test('increase version', (tt) => {
tt.plan(3)
pre({
npm,
pkg: {name: 'unavailable'},
plugins
}, (err, release) => {
tt.error(err)
tt.is(release.type, 'initial')
tt.is(release.version, '1.0.0')
})
})
t.end()
})
-48
View File
@@ -1,48 +0,0 @@
const test = require('tap').test
const type = require('../../dist/lib/type')
test('get type from commits', (t) => {
t.test('get type from plugin', (tt) => {
tt.plan(2)
type({
commits: [{
hash: '0',
message: 'a'
}],
lastRelease: {version: '1.0.0'},
plugins: {analyzeCommits: (config, cb) => cb(null, 'major')}
}, (err, type) => {
tt.error(err)
tt.is(type, 'major')
})
})
t.test('error when no changes', (tt) => {
tt.plan(1)
type({
commits: [],
lastRelease: {},
plugins: {analyzeCommits: (config, cb) => cb(null, null)}
}, (err) => {
tt.is(err.code, 'ENOCHANGE')
})
})
t.test('initial version', (tt) => {
tt.plan(2)
type({
commits: [],
lastRelease: {},
plugins: {analyzeCommits: (config, cb) => cb(null, 'major')}
}, (err, type) => {
tt.error(err)
tt.is(type, 'initial')
})
})
t.end()
})
-68
View File
@@ -1,68 +0,0 @@
const test = require('tap').test
const verify = require('../../dist/lib/verify')
test('verify pkg, options and env', (t) => {
t.test('dry run verification', (tt) => {
const noErrors = verify({
options: {debug: true},
pkg: {
name: 'package',
repository: {
url: 'http://github.com/whats/up.git'
}
}
})
tt.is(noErrors.length, 0)
const errors = verify({
options: {debug: true},
pkg: {}
})
tt.is(errors.length, 2)
tt.is(errors[0].code, 'ENOPKGNAME')
tt.is(errors[1].code, 'ENOPKGREPO')
const errors2 = verify({
options: {debug: true},
pkg: {
name: 'package',
repository: {
url: 'lol'
}
}
})
tt.is(errors2.length, 1)
tt.is(errors2[0].code, 'EMALFORMEDPKGREPO')
tt.end()
})
t.test('publish verification', (tt) => {
const noErrors = verify({
env: {NPM_TOKEN: 'yo'},
options: {githubToken: 'sup'},
pkg: {
name: 'package',
repository: {
url: 'http://github.com/whats/up.git'
}
}
})
tt.is(noErrors.length, 0)
const errors = verify({env: {}, options: {}, pkg: {}})
tt.is(errors.length, 4)
tt.is(errors[0].code, 'ENOPKGNAME')
tt.is(errors[1].code, 'ENOPKGREPO')
tt.is(errors[2].code, 'ENOGHTOKEN')
tt.is(errors[3].code, 'ENONPMTOKEN')
tt.end()
})
})
+1
View File
@@ -0,0 +1 @@
test:{SHA}C+7Hteo/D9vJXQ3UfzxbwnXaijM=
+3
View File
@@ -0,0 +1,3 @@
_auth=dGVzdDpmb28=
email=test@example.com
registry=http://127.0.0.1:4873/
+17
View File
@@ -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
+10
View File
@@ -0,0 +1,10 @@
'use strict'
var test = require('tape')
var createModule = require('./lib/create-module')
require('./scenarios/install')(test, createModule)
require('./scenarios/prepublish')(test, createModule)
require('./scenarios/postpublish')(test, createModule)
require('./scenarios/publish')(test, createModule)
+45
View File
@@ -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)
}))
}))
}
+33
View File
@@ -0,0 +1,33 @@
'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('install', function (t) {
installTest(t, 'npm install', 'not doing anything when the module is installed')
installTest(t, 'npm i', 'not doing anything when the module is installed with abbrevd command')
})
function installTest (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')
})
})
}
}))
}
+57
View File
@@ -0,0 +1,57 @@
'use strict'
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) {
t.test('publish new version to github releases', 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(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.error(err, 'nixt')
})
})
t.test('correct data published', function (t) {
t.plan(4)
github.releases.getRelease({ owner: 'user', repo: 'repo', id: 1}, function (err, res) {
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')
})
})
})
}))
}
+50
View File
@@ -0,0 +1,50 @@
'use strict'
var fs = require('fs')
var exec = require('child_process').exec
var efh = require('error-first-handler')
var nixt = require('nixt')
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')
})
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)
})
})
})
}
}))
}
+37
View File
@@ -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')
})
})
}))
}
})
}