Compare commits

...
6 Commits
Author SHA1 Message Date
Stephan Bönnemann 451378117d fix(registry): be better at using the correct registry (relevant for npme)
Closes #53
2015-08-22 23:32:49 +02:00
Stephan Bönnemann 23221cc044 chore(package): update last-release-npm to 1.2.1 2015-08-22 21:48:00 +02:00
Stephan Bönnemann 7a4c89f131 feat: add fallbackTag functionality and map "next" to "latest"
You can now map dist-tags onto "fallbackTags". E.g. if you want a
development channel like "next" and no version is currently published as "next"
semantic-release will fallback to "latest" to determine the new "next" version.
This is now the default for "next" -> "latest", but you can specify your own
mappings by adding "fallbackTags" to your `package.json`'s "release" field.

BREAKING CHANGE: In cases where you pushed a new commit with a "dist-tag"
configuration of "next" and no version was previously published as "next",
semanitc-release failed and did not publish a new version. It will now
automatically fall back to to "latest".
2015-08-22 21:36:11 +02:00
Stephan Bönnemann 2405453f2d docs(README): nice badge pyramid 2015-08-22 19:53:36 +02:00
Stephan Bönnemann a16c36ed4d style: branch available in options not root of config 2015-08-22 19:49:09 +02:00
Stephan Bönnemann 5cc7da6035 fix(commits): add helpful error when lastRelease not in history
Closes #61, Closes #50
2015-08-22 19:31:29 +02:00
9 changed files with 129 additions and 28 deletions
+4 -5
View File
@@ -1,16 +1,15 @@
# semantic-release
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://github.com/feross/standard)
[![Join the chat at https://gitter.im/semantic-release/semantic-release](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/semantic-release/semantic-release?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![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)
[![Join the chat at https://gitter.im/semantic-release/semantic-release](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/semantic-release/semantic-release?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://github.com/feross/standard)
`semantic-release` builds upon a set of conventions to give you **fully automated, semver-compliant package publishing**. It's mostly about _commit-messages_, but you can define more _heuristics_.
  | Commands | Comment
+1 -1
View File
@@ -24,7 +24,7 @@
"@semantic-release/commit-analyzer": "^2.0.0",
"@semantic-release/condition-travis": "^4.0.0",
"@semantic-release/error": "^1.0.0",
"@semantic-release/last-release-npm": "^1.1.1",
"@semantic-release/last-release-npm": "^1.2.1",
"@semantic-release/release-notes-generator": "^2.0.0",
"git-head": "^1.2.1",
"github": "^0.2.4",
+7 -2
View File
@@ -1,5 +1,6 @@
const { readFileSync, writeFileSync } = require('fs')
const path = require('path')
const url = require('url')
const _ = require('lodash')
const log = require('npmlog')
@@ -24,6 +25,9 @@ const options = _.defaults(
pkg.release,
{
branch: 'master',
fallbackTags: {
next: 'latest'
},
debug: !env.CI,
githubToken: env.GH_TOKEN || env.GITHUB_TOKEN,
githubUrl: env.GH_URL
@@ -42,11 +46,12 @@ npmconf.load({}, (err, conf) => {
token: env.NPM_TOKEN
},
loglevel: conf.get('loglevel'),
registry: conf.get('registry'),
registry: require('./lib/get-registry')(pkg, conf),
tag: (pkg.publishConfig || {}).tag || conf.get('tag') || 'latest'
}
if (npm.registry[npm.registry.length - 1] !== '/') npm.registry += '/'
// normalize trailing slash
npm.registry = url.format(url.parse(npm.registry))
log.level = npm.loglevel
+55 -15
View File
@@ -1,25 +1,65 @@
const { exec } = require('child_process')
module.exports = function ({lastRelease}, cb) {
const log = require('npmlog')
const SemanticReleaseError = require('@semantic-release/error')
module.exports = function ({lastRelease, options}, cb) {
const branch = options.branch
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)
if (!from) return extract()
cb(null, String(stdout).split('==END==\n')
exec(`git branch --contains ${from}`, (err, stdout) => {
if (err) return cb(err)
let inHistory = false
.filter((raw) => !!raw.trim())
const branches = stdout.split('\n')
.map((result) => {
if (branch === result.replace('*', '').trim()) {
inHistory = true
return null
}
return result.trim()
})
.filter(branch => !!branch)
.map((raw) => {
const data = raw.split('==SPLIT==')
return {
hash: data[0],
message: data[1]
}
}))
if (!inHistory) {
log.error('commits',
`The commit the last release of this package was derived from is no longer
in the direct history of the "${branch}" branch.
This means semantic-release can not extract the commits between now and then.
This is usually caused by force pushing or releasing from an unrelated branch.
You can recover from this error by publishing manually or restoring
the commit "${from}".` + (branches.length ?
`\nHere is a list of branches that still contain the commit in question: \n * ${branches.join('\n * ')}` :
''
))
return cb(new SemanticReleaseError('Commit not in history', 'ENOTINHISTORY'))
}
)
extract()
})
function extract () {
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]
}
}))
}
)
}
}
+12
View File
@@ -0,0 +1,12 @@
module.exports = function (pkg, conf) {
if (pkg.publishConfig && pkg.publishConfig.registry) return pkg.publishConfig.registry
if (pkg.name[0] !== '@') return conf.get('registry') || 'https://registry.npmjs.org/'
const scope = pkg.name.split('/')[0]
const scopedRegistry = conf.get(`${scope}/registry`)
if (scopedRegistry) return scopedRegistry
return conf.get('registry') || 'https://registry.npmjs.org/'
}
+4
View File
@@ -5,6 +5,10 @@ const rawCommits = [
module.exports = {
exec: (command, cb) => {
if (/contains/.test(command)) {
return cb(null, `whatever\nmaster\n`)
}
cb(
null,
/\.\.HEAD/.test(command) ?
+10 -2
View File
@@ -7,7 +7,7 @@ const commits = proxyquire('../../dist/lib/commits', {
test('commits since last release', (t) => {
t.test('get all commits', (tt) => {
commits({lastRelease: {}}, (err, commits) => {
commits({lastRelease: {}, options: {branch: 'master'}}, (err, commits) => {
tt.error(err)
tt.is(commits.length, 2, 'all commits')
tt.is(commits[0].hash, 'hash-one', 'parsed hash')
@@ -18,7 +18,7 @@ test('commits since last release', (t) => {
})
t.test('get commits since hash', (tt) => {
commits({lastRelease: {gitHead: 'hash'}}, (err, commits) => {
commits({lastRelease: {gitHead: 'hash'}, options: {branch: 'master'}}, (err, commits) => {
tt.error(err)
tt.is(commits.length, 1, 'specified commits')
tt.is(commits[0].hash, 'hash-one', 'parsed hash')
@@ -28,5 +28,13 @@ test('commits since last release', (t) => {
})
})
t.test('get commits since hash', (tt) => {
commits({lastRelease: {gitHead: 'notinhistory'}, options: {branch: 'notmaster'}}, (err, commits) => {
tt.ok(err)
tt.is(err.code, 'ENOTINHISTORY')
tt.end()
})
})
t.end()
})
+30
View File
@@ -0,0 +1,30 @@
const test = require('tap').test
const getRegistry = require('../../dist/lib/get-registry')
test('get correct registry', (t) => {
t.is(getRegistry({
name: 'publish-config',
publishConfig: {
registry: 'a'
}},
{}), 'a')
t.is(getRegistry({name: 'normal'}, {get: () => 'b'}), 'b')
t.is(getRegistry({name: 'normal'}, {get: () => null}), 'https://registry.npmjs.org/')
t.is(getRegistry({name: '@scoped/foo'}, {
get: (input) => input === '@scoped/registry' ? 'c' : 'd'
}), 'c')
t.is(getRegistry({name: '@scoped/bar'}, {
get: () => 'e'
}), 'e')
t.is(getRegistry({name: '@scoped/baz'}, {
get: () => null
}), 'https://registry.npmjs.org/')
t.end()
})
+6 -3
View File
@@ -3,7 +3,9 @@ const proxyquire = require('proxyquire')
require('../mocks/registry')
const pre = proxyquire('../../dist/pre', {
'child_process': require('../mocks/child-process')
'./lib/commits': proxyquire('../../dist/lib/commits', {
'child_process': require('../mocks/child-process')
})
})
const versions = {
@@ -14,14 +16,13 @@ const plugins = {
verifyRelease: (release, cb) => cb(null, release),
analyzeCommits: (commits, cb) => cb(null, 'major'),
getLastRelease: ({ pkg }, cb) => {
cb(null, { version: versions[pkg.name] || null, gitHead: 'HEAD' })
cb(null, {version: versions[pkg.name] || null, gitHead: 'HEAD'})
}
}
const npm = {
registry: 'http://registry.npmjs.org/',
tag: 'latest'
}
test('full pre run', (t) => {
@@ -29,6 +30,7 @@ test('full pre run', (t) => {
tt.plan(3)
pre({
options: {branch: 'master'},
npm,
pkg: {name: 'available'},
plugins
@@ -43,6 +45,7 @@ test('full pre run', (t) => {
tt.plan(3)
pre({
options: {branch: 'master'},
npm,
pkg: {name: 'unavailable'},
plugins