Compare commits

..
12 Commits
Author SHA1 Message Date
Pierre Vanduynslager eec4e68615 test: Isolate environment variables passed to semantic-release
`npm` is called through `semantic-release` and in the integration test to make some assertion.
By isolating the the environment variables passed to `semantic-release` it's easier to avoid a mistake that would pass the test environment that contains is own auth variables.
2017-11-29 18:06:14 -05:00
Pierre Vanduynslager 8371a03da0 test: Verify Error instance type and SemanticReleaseError name 2017-11-29 18:06:14 -05:00
Pierre Vanduynslager 2491032a99 test: Add test to check unexpected plugin return values 2017-11-29 18:06:14 -05:00
Pierre Vanduynslager 02ddf34f21 Fix: Remove redundant test of commitAnalyzer plugin output 2017-11-29 18:06:14 -05:00
Pierre Vanduynslager 685959107b chore: Clean up mistakenly added configs 2017-11-29 18:06:14 -05:00
Pierre Vanduynslager 613a646363 fix: Typo in error messages 2017-11-29 18:06:14 -05:00
Pierre Vanduynslager d7b323dd00 fix: Accept undefined values for the getLastRelease and generateNotes plugins
Adapt tests and default value to the plugin definitions (`definitions.js`)
2017-11-29 18:06:14 -05:00
Pierre Vanduynslager a7359bffb6 test: Improve docker start/stop script
- Simplify the loop that check availability
- Increase timeout
- Remove the container after stopping
2017-11-29 18:06:14 -05:00
Pierre Vanduynslager fcb832bbe1 fix: remove name from log as it's not an existing option anymore 2017-11-29 18:06:14 -05:00
greenkeeper[bot]andPierre Vanduynslager 89f5e07408 chore(package): update ava to version 0.24.0 2017-11-27 15:22:17 -05:00
Pierre Vanduynslager ce3841f553 test: Ignore the ~/.npmrc file during tests
When the test are run npm read the ~/.npmrc and ./.npmrc files and set some environment variables starting with `npm_`.
When the test create temporary folders and created a `.npmrc` the values there are ignored as the environment variables take precedence.
This commit remove this environment variable (from the local `process.env`) before starting the integrations test and restore them after. This way the `./.npmrc` files created in temp directory for the test are correctly used.
2017-11-25 14:50:44 -05:00
Pierre Vanduynslager 40c58c9b42 ci: Run npm registry in Docker 2017-11-25 14:50:44 -05:00
23 changed files with 259 additions and 165 deletions
-4
View File
@@ -129,7 +129,3 @@ $RECYCLE.BIN/
package-lock.json
yarn.lock
# Registry tests
test/helpers/registry/couch
test/helpers/registry/data
+3 -1
View File
@@ -1,11 +1,13 @@
language: node_js
services:
- couchdb
- docker
notifications:
email: false
node_js:
- 9
- 8
os:
- linux
# Trigger a push build on caribou and greenkeeper branches + PRs build on every branches
# Avoid double build on PRs (See https://github.com/travis-ci/travis-ci/issues/1147)
+1 -1
View File
@@ -19,7 +19,7 @@ module.exports = async opts => {
throw new SemanticReleaseError('The repositoryUrl option is required', 'ENOREPOURL');
}
logger.log('Run automated release from branch %s', options.name, options.branch);
logger.log('Run automated release from branch %s', options.branch);
if (!options.dryRun) {
logger.log('Call plugin %s', 'verify-conditions');
+2 -1
View File
@@ -18,6 +18,7 @@ const getVersionHead = require('./get-version-head');
* @typedef {Object} LastRelease
* @property {string} version The version number of the last release.
* @property {string} [gitHead] The commit sha used to make the last release.
* @property {string} [gitTag] The tag used to make the last release.
*/
/**
@@ -45,7 +46,7 @@ const getVersionHead = require('./get-version-head');
* @throws {SemanticReleaseError} with code `ENOTINHISTORY` if `lastRelease.gitHead` or the commit sha derived from `config.lastRelease.version` is not in the direct history of `branch`.
* @throws {SemanticReleaseError} with code `ENOGITHEAD` if `lastRelease.gitHead` is undefined and no commit sha can be found for the `config.lastRelease.version`.
*/
module.exports = async ({version, gitHead}, branch, logger) => {
module.exports = async ({version, gitHead} = {}, branch, logger) => {
let gitTag;
if (gitHead || version) {
try {
-4
View File
@@ -1,13 +1,9 @@
const semver = require('semver');
const SemanticReleaseError = require('@semantic-release/error');
module.exports = (type, lastRelease, logger) => {
let version;
if (lastRelease.version) {
version = semver.inc(lastRelease.version, type);
if (!version) {
throw new SemanticReleaseError(`Invalid release type ${type}`, 'EINVALIDTYPE');
}
logger.log('The next release version is %s', version);
} else {
version = '1.0.0';
+3 -3
View File
@@ -38,7 +38,7 @@ module.exports = {
},
output: {
validator: output => !output || RELEASE_TYPE.includes(output),
message: 'The "analyzeCommits" plugin output must be either undefined or a valid semver release type.',
message: 'The "analyzeCommits" plugin output, if defined, must be a valid semver release type.',
},
},
verifyRelease: {
@@ -57,8 +57,8 @@ module.exports = {
'The "generateNotes" plugin, if defined, must be a single plugin definition. A plugin definition is either a string or an object with a path property.',
},
output: {
validator: output => isString(output),
message: 'The "generateNotes" plugin output must be a string.',
validator: output => !output || isString(output),
message: 'The "generateNotes" plugin output, if defined, must be a string.',
},
},
publish: {
+1 -1
View File
@@ -27,7 +27,7 @@ module.exports = (pluginType, pluginConfig, logger, validator) => {
const result = await func(cloneDeep(input));
if (validator && !validator.validator(result)) {
throw new Error(`${validator.message}. Received: ${inspect(result)}`);
throw new Error(`${validator.message} Received: ${inspect(result)}`);
}
return result;
};
+4 -4
View File
@@ -37,7 +37,7 @@
"semver": "^5.4.1"
},
"devDependencies": {
"ava": "^0.23.0",
"ava": "^0.24.0",
"codecov": "^3.0.0",
"commitizen": "^2.9.6",
"cz-conventional-changelog": "^2.0.0",
@@ -46,11 +46,12 @@
"eslint-plugin-prettier": "^2.3.0",
"file-url": "^2.0.2",
"fs-extra": "^4.0.2",
"got": "^8.0.0",
"js-yaml": "^3.10.0",
"mockserver-client": "^2.0.0",
"nock": "^9.0.2",
"npm-registry-couchapp": "^2.6.12",
"nyc": "^11.2.1",
"p-retry": "^1.0.0",
"prettier": "~1.8.0",
"proxyquire": "^1.8.0",
"sinon": "^4.0.0",
@@ -126,8 +127,7 @@
"prettier"
],
"rules": {
"prettier/prettier": 2,
"no-duplicate-imports": 2
"prettier/prettier": 2
}
}
}
+5 -6
View File
@@ -1,6 +1,5 @@
import test from 'ava';
import {stub} from 'sinon';
import SemanticReleaseError from '@semantic-release/error';
import getCommits from '../lib/get-commits';
import {
gitRepo,
@@ -409,7 +408,7 @@ test.serial('Throws ENOGITHEAD error if the gitHead of the last release cannot b
// Verify error code and type
t.is(error.code, 'ENOGITHEAD');
t.true(error instanceof SemanticReleaseError);
t.is(error.name, 'SemanticReleaseError');
// Verify the log function has been called with a message explaining the error
t.regex(
t.context.error.firstCall.args[0],
@@ -428,7 +427,7 @@ test.serial('Throws ENOTINHISTORY error if gitHead is not in history', async t =
// Verify error code and type
t.is(error.code, 'ENOTINHISTORY');
t.true(error instanceof SemanticReleaseError);
t.is(error.name, 'SemanticReleaseError');
// Verify the log function has been called with a message mentionning the branch
t.regex(t.context.error.firstCall.args[0], /history of the "master" branch/);
// Verify the log function has been called with a message mentionning the missing gitHead
@@ -453,7 +452,7 @@ test.serial('Throws ENOTINHISTORY error if gitHead is not in branch history but
// Verify error code and type
t.is(error.code, 'ENOTINHISTORY');
t.true(error instanceof SemanticReleaseError);
t.is(error.name, 'SemanticReleaseError');
// Verify the log function has been called with a message mentionning the branch
t.regex(t.context.error.firstCall.args[0], /history of the "master" branch/);
// Verify the log function has been called with a message mentionning the missing gitHead
@@ -482,7 +481,7 @@ test.serial('Throws ENOTINHISTORY error if gitHead is not in detached head but p
// Verify error code and type
t.is(error.code, 'ENOTINHISTORY');
t.true(error instanceof SemanticReleaseError);
t.is(error.name, 'SemanticReleaseError');
// Verify the log function has been called with a message mentionning the branch
t.regex(t.context.error.firstCall.args[0], /history of the "master" branch/);
// Verify the log function has been called with a message mentionning the missing gitHead
@@ -508,7 +507,7 @@ test.serial('Throws ENOTINHISTORY error when a tag is not in branch history but
const error = await t.throws(getCommits({version: '1.0.0'}, 'master', t.context.logger));
// Verify error code and type
t.is(error.code, 'ENOTINHISTORY');
t.true(error instanceof SemanticReleaseError);
t.is(error.name, 'SemanticReleaseError');
// Verify the log function has been called with a message mentionning the branch
t.regex(t.context.error.firstCall.args[0], /history of the "master" branch/);
// Verify the log function has been called with a message mentionning the missing gitHead
-7
View File
@@ -1,6 +1,5 @@
import test from 'ava';
import {stub} from 'sinon';
import SemanticReleaseError from '@semantic-release/error';
import getNextVersion from '../lib/get-next-version';
test.beforeEach(t => {
@@ -28,9 +27,3 @@ test('Return 1.0.0 if there is no previous release', t => {
const version = getNextVersion('minor', {}, t.context.logger);
t.is(version, '1.0.0');
});
test('Return an error if the release type is invalid', t => {
const error = t.throws(() => getNextVersion('invalid', {version: '1.0.0'}, t.context.logger));
t.is(error.code, 'EINVALIDTYPE');
t.true(error instanceof SemanticReleaseError);
});
+1 -1
View File
@@ -36,7 +36,7 @@ test.serial('Throw error if the last commit sha cannot be found', async t => {
// Create a git repository, set the current working directory at the root of the repo
await gitRepo();
await t.throws(gitHead());
await t.throws(gitHead(), Error);
});
test.serial('Unshallow repository', async t => {
+21 -5
View File
@@ -1,7 +1,10 @@
import Docker from 'dockerode';
import getStream from 'get-stream';
import got from 'got';
import pRetry from 'p-retry';
import {mockServerClient} from 'mockserver-client';
const IMAGE = 'jamesdbloom/mockserver:latest';
const MOCK_SERVER_PORT = 1080;
const MOCK_SERVER_HOST = 'localhost';
const docker = new Docker();
@@ -13,22 +16,35 @@ let container;
* @return {Promise} Promise that resolves when the container is started.
*/
async function start() {
await getStream(await docker.pull('jamesdbloom/mockserver:latest'));
await getStream(await docker.pull(IMAGE));
container = await docker.createContainer({
Image: 'jamesdbloom/mockserver',
Tty: true,
Image: IMAGE,
PortBindings: {[`${MOCK_SERVER_PORT}/tcp`]: [{HostPort: `${MOCK_SERVER_PORT}`}]},
});
return container.start();
await container.start();
try {
// Wait for the mock server to be ready
await pRetry(() => got.put(`http://${MOCK_SERVER_HOST}:${MOCK_SERVER_PORT}/status`, {cache: false}), {
retries: 7,
minTimeout: 1000,
factor: 2,
});
} catch (err) {
throw new Error(`Couldn't start mock-server after 2 min`);
}
}
/**
* Stop the `mockserver` Docker container.
* Stop and remote the `mockserver` Docker container.
*
* @return {Promise} Promise that resolves when the container is stopped.
*/
async function stop() {
return container.stop();
await container.stop();
await container.remove();
}
/**
+78
View File
@@ -0,0 +1,78 @@
import Docker from 'dockerode';
import getStream from 'get-stream';
import got from 'got';
import pRetry from 'p-retry';
const IMAGE = 'npmjs/npm-docker-couchdb:1.6.1';
const SERVER_PORT = 15986;
const COUCHDB_PORT = 5984;
const SERVER_HOST = 'localhost';
const NPM_USERNAME = 'integration';
const NPM_PASSWORD = 'suchsecure';
const NPM_EMAIL = 'integration@test.com';
const docker = new Docker();
let container;
/**
* Download the `npm-docker-couchdb` Docker image, create a new container and start it.
*
* @return {Promise} Promise that resolves when the container is started.
*/
async function start() {
await getStream(await docker.pull(IMAGE));
container = await docker.createContainer({
Tty: true,
Image: IMAGE,
PortBindings: {[`${COUCHDB_PORT}/tcp`]: [{HostPort: `${SERVER_PORT}`}]},
});
await container.start();
try {
// Wait for the registry to be ready
await pRetry(() => got(`http://${SERVER_HOST}:${SERVER_PORT}/registry/_design/app`, {cache: false}), {
retries: 7,
minTimeout: 1000,
factor: 2,
});
} catch (err) {
throw new Error(`Couldn't start npm-docker-couchdb after 2 min`);
}
// Create user
await got(`http://${SERVER_HOST}:${SERVER_PORT}/_users/org.couchdb.user:${NPM_USERNAME}`, {
json: true,
auth: 'admin:admin',
method: 'PUT',
body: {
_id: `org.couchdb.user:${NPM_USERNAME}`,
name: NPM_USERNAME,
roles: [],
type: 'user',
password: NPM_PASSWORD,
email: NPM_EMAIL,
},
});
}
const url = `http://${SERVER_HOST}:${SERVER_PORT}/registry/_design/app/_rewrite/`;
const authEnv = {
npm_config_registry: url, // eslint-disable-line camelcase
NPM_USERNAME,
NPM_PASSWORD,
NPM_EMAIL,
};
/**
* Stop and remote the `npm-docker-couchdb` Docker container.
*
* @return {Promise} Promise that resolves when the container is stopped.
*/
async function stop() {
await container.stop();
await container.remove();
}
export default {start, stop, authEnv, url};
-14
View File
@@ -1,14 +0,0 @@
import execa from 'execa';
const opts = {cwd: __dirname};
const uri = 'http://localhost:' + (process.env.TRAVIS === 'true' ? 5984 : 15986) + '/registry/_design/app/_rewrite/';
function start() {
return execa('./start.sh', opts);
}
function stop() {
return execa('./stop.sh', opts);
}
export default {start, stop, uri};
-20
View File
@@ -1,20 +0,0 @@
[couchdb]
database_dir = data
view_index_dir = data
delayed_commits = false
uuid = bf4ecd84a7c89d60b5b2540fdf8c322c
[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
-41
View File
@@ -1,41 +0,0 @@
#!/bin/bash
# exit if an error occurs
set -e
cd $(dirname $0)
mkdir -p couch
if [[ $TRAVIS = true ]]
then
COUCH=http://admin:password@127.0.0.1:5984
curl -X PUT http://127.0.0.1:5984/_config/admins/admin -d '"password"'
curl -X PUT $COUCH/_config/couchdb/delayed_commits -d '"false"'
curl -X PUT $COUCH/_config/couch_httpd_auth/users_db_public -d '"true"'
curl -X PUT $COUCH/_config/couch_httpd_auth/public_fields -d '"appdotnet, avatar, avatarMedium, avatarLarge, date, email, fields, freenode, fullname, github, homepage, name, roles, twitter, type, _id, _rev"'
curl -X PUT $COUCH/_config/httpd/secure_rewrites -d '"false"'
else
COUCH=http://admin:password@127.0.0.1:15986
couchdb -b -a local.ini -p couch/pid -o couch/stdout.log -e couch/stderr.log
# wait for couch to start
sleep 1
fi
# 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
export NO_PROMPT=yes
npm explore npm-registry-couchapp -- npm run copy --npm-registry-couchapp:couch=$COUCH/registry
-13
View File
@@ -1,13 +0,0 @@
#!/bin/bash
# close couchdb background process
couchdb -d
# delete data and logs
cd $(dirname $0)
cat couch/{couch,stdout,stderr}.log
cat couch/pid | xargs kill
rm -rf couch
rm -rf data
+79 -4
View File
@@ -2,7 +2,7 @@ import test from 'ava';
import proxyquire from 'proxyquire';
import {stub} from 'sinon';
import tempy from 'tempy';
import SemanticReleaseError from '@semantic-release/error';
import DEFINITIONS from '../lib/plugins/definitions';
import {gitHead as getGitHead} from '../lib/git';
import {gitRepo, gitCommits, gitTagVersion} from './helpers/git-utils';
@@ -193,6 +193,54 @@ test.serial('Dry-run skips verifyConditions and publish', async t => {
t.true(publish.notCalled);
});
test.serial('Accept "undefined" values for the "getLastRelease" and "generateNotes" plugins', async t => {
// Create a git repository, set the current working directory at the root of the repo
await gitRepo();
// Add commits to the master branch
await gitCommits(['First']);
// Create the tag corresponding to version 1.0.0
await gitTagVersion('v1.0.0');
// Add new commits to the master branch
await gitCommits(['Second']);
const lastRelease = {gitHead: undefined, gitTag: undefined, version: undefined};
const nextRelease = {type: 'major', version: '2.0.0', gitHead: await getGitHead(), gitTag: 'v2.0.0'};
const verifyConditions = stub().resolves();
const getLastRelease = stub().resolves();
const analyzeCommits = stub().resolves(nextRelease.type);
const verifyRelease = stub().resolves();
const generateNotes = stub().resolves();
const publish = stub().resolves();
const options = {
branch: 'master',
repositoryUrl: 'git@hostname.com:owner/module.git',
verifyConditions: [verifyConditions],
getLastRelease,
analyzeCommits,
verifyRelease,
generateNotes,
publish,
};
await t.context.semanticRelease(options);
t.true(getLastRelease.calledOnce);
t.true(analyzeCommits.calledOnce);
t.deepEqual(analyzeCommits.firstCall.args[1].lastRelease, lastRelease);
t.true(verifyRelease.calledOnce);
t.deepEqual(verifyRelease.firstCall.args[1].lastRelease, lastRelease);
t.true(generateNotes.calledOnce);
t.deepEqual(generateNotes.firstCall.args[1].lastRelease, lastRelease);
t.true(publish.calledOnce);
t.deepEqual(publish.firstCall.args[1].lastRelease, lastRelease);
t.falsy(publish.firstCall.args[1].nextRelease.notes);
});
test.serial('Throw SemanticReleaseError if not running from a git repository', async t => {
// Set the current working directory to a temp directory
process.chdir(tempy.directory());
@@ -201,10 +249,10 @@ test.serial('Throw SemanticReleaseError if not running from a git repository', a
// Verify error code and type
t.is(error.code, 'ENOGITREPO');
t.true(error instanceof SemanticReleaseError);
t.is(error.name, 'SemanticReleaseError');
});
test.serial('Throw SemanticReleaseError if repositoryUrl is not set and canot be found', async t => {
test.serial('Throw SemanticReleaseError if repositoryUrl is not set and cannot be found', async t => {
// Create a git repository, set the current working directory at the root of the repo
await gitRepo();
@@ -212,5 +260,32 @@ test.serial('Throw SemanticReleaseError if repositoryUrl is not set and canot be
// Verify error code and type
t.is(error.code, 'ENOREPOURL');
t.true(error instanceof SemanticReleaseError);
t.is(error.name, 'SemanticReleaseError');
});
test.serial('Throw an Error if returns an unexpected value', async t => {
// Create a git repository, set the current working directory at the root of the repo
await gitRepo();
// Add commits to the master branch
await gitCommits(['First']);
// Create the tag corresponding to version 1.0.0
await gitTagVersion('v1.0.0');
// Add new commits to the master branch
await gitCommits(['Second']);
const verifyConditions = stub().resolves();
const getLastRelease = stub().resolves('string');
const options = {
branch: 'master',
repositoryUrl: 'git@hostname.com:owner/module.git',
verifyConditions: [verifyConditions],
getLastRelease,
};
const error = await t.throws(t.context.semanticRelease(options), Error);
// Verify error message
t.regex(error.message, new RegExp(DEFINITIONS.getLastRelease.output.message));
t.regex(error.message, /Received: 'string'/);
});
+49 -26
View File
@@ -3,30 +3,35 @@ import {writeJson, readJson} from 'fs-extra';
import {stub} from 'sinon';
import execa from 'execa';
import {gitRepo, gitCommits, gitHead, gitTagVersion, gitPackRefs, gitAmmendCommit} from './helpers/git-utils';
import registry from './helpers/registry';
import mockServer from './helpers/mockserver';
import npmRegistry from './helpers/npm-registry';
import semanticRelease from '..';
/* eslint camelcase: ["error", {properties: "never"}] */
// Environment variables used with cli
// Environment variables used with semantic-release cli (similar to what a user would setup)
const env = {
npm_config_registry: registry.uri,
GH_TOKEN: 'github_token',
GITHUB_URL: mockServer.url,
NPM_EMAIL: 'integration@test.com',
NPM_USERNAME: 'integration',
NPM_PASSWORD: 'suchsecure',
};
// Environment variables used only for the local npm command used to do verification
const testEnv = Object.assign({}, process.env, {
npm_config_registry: npmRegistry.url,
NPM_EMAIL: 'integration@test.com',
LEGACY_TOKEN: Buffer.from(`${process.env.NPM_USERNAME}:${process.env.NPM_PASSWORD}`, 'utf8').toString('base64'),
});
const cli = require.resolve('../bin/semantic-release');
const pluginError = require.resolve('./fixtures/plugin-error');
const pluginInheritedError = require.resolve('./fixtures/plugin-error-inherited');
test.before(async () => {
// Start the local NPM registry
await npmRegistry.start();
// Start Mock Server
await mockServer.start();
// Start the local NPM registry
await registry.start();
});
test.beforeEach(t => {
@@ -34,7 +39,24 @@ test.beforeEach(t => {
t.context.env = Object.assign({}, process.env);
// Save the current working diretory
t.context.cwd = process.cwd();
// Delete env paramaters that could have been set on the machine running the tests
delete process.env.NPM_TOKEN;
delete process.env.NPM_USERNAME;
delete process.env.NPM_PASSWORD;
delete process.env.NPM_EMAIL;
delete process.env.GH_TOKEN;
delete process.env.GITHUB_TOKEN;
delete process.env.GH_URL;
delete process.env.GITHUB_URL;
delete process.env.GH_PREFIX;
delete process.env.GITHUB_PREFIX;
// Delete all `npm_config` environment variable set by CI as they take precedence over the `.npmrc` because the process that runs the tests is started before the `.npmrc` is created
for (let i = 0, keys = Object.keys(process.env); i < keys.length; i++) {
if (keys[i].startsWith('npm_config')) {
delete process.env[keys[i]];
}
}
// Disable logs during tests
t.context.log = stub(console, 'log');
t.context.error = stub(console, 'error');
t.context.stdout = stub(process.stdout, 'write');
@@ -46,7 +68,7 @@ test.afterEach.always(t => {
process.env = Object.assign({}, t.context.env);
// Restore the current working directory
process.chdir(t.context.cwd);
// Restore the logs
t.context.log.restore();
t.context.error.restore();
t.context.stdout.restore();
@@ -54,9 +76,10 @@ test.afterEach.always(t => {
});
test.after.always(async () => {
await mockServer.stop();
// Stop the local NPM registry
await registry.stop();
await npmRegistry.stop();
// Stop Mock Server
await mockServer.stop();
});
test.serial('Release patch, minor and major versions', async t => {
@@ -71,10 +94,10 @@ test.serial('Release patch, minor and major versions', async t => {
version: '0.0.0-dev',
repository: {url: `git+https://github.com/${owner}/${packageName}`},
release: {verifyConditions: ['@semantic-release/github', '@semantic-release/npm']},
publishConfig: {registry: registry.uri},
publishConfig: {registry: npmRegistry.url},
});
// Create a npm-shrinkwrap.json file
await execa('npm', ['shrinkwrap'], {env});
await execa('npm', ['shrinkwrap'], {env: testEnv});
/* No release */
@@ -125,7 +148,7 @@ test.serial('Release patch, minor and major versions', async t => {
// Retrieve the published package from the registry and check version and gitHead
let [, releasedVersion, releasedGitHead] = /^version = '(.+)'\s+gitHead = '(.+)'$/.exec(
(await execa('npm', ['show', packageName, 'version', 'gitHead'], {env})).stdout
(await execa('npm', ['show', packageName, 'version', 'gitHead'], {env: testEnv})).stdout
);
t.is(releasedVersion, version);
t.is(releasedGitHead, await gitHead());
@@ -170,7 +193,7 @@ test.serial('Release patch, minor and major versions', async t => {
// Retrieve the published package from the registry and check version and gitHead
[, releasedVersion, releasedGitHead] = /^version = '(.+)'\s+gitHead = '(.+)'$/.exec(
(await execa('npm', ['show', packageName, 'version', 'gitHead'], {env})).stdout
(await execa('npm', ['show', packageName, 'version', 'gitHead'], {env: testEnv})).stdout
);
t.is(releasedVersion, version);
t.is(releasedGitHead, await gitHead());
@@ -215,7 +238,7 @@ test.serial('Release patch, minor and major versions', async t => {
// Retrieve the published package from the registry and check version and gitHead
[, releasedVersion, releasedGitHead] = /^version = '(.+)'\s+gitHead = '(.+)'$/.exec(
(await execa('npm', ['show', packageName, 'version', 'gitHead'], {env})).stdout
(await execa('npm', ['show', packageName, 'version', 'gitHead'], {env: testEnv})).stdout
);
t.is(releasedVersion, version);
t.is(releasedGitHead, await gitHead());
@@ -260,7 +283,7 @@ test.serial('Release patch, minor and major versions', async t => {
// Retrieve the published package from the registry and check version and gitHead
[, releasedVersion, releasedGitHead] = /^version = '(.+)'\s+gitHead = '(.+)'$/.exec(
(await execa('npm', ['show', packageName, 'version', 'gitHead'], {env})).stdout
(await execa('npm', ['show', packageName, 'version', 'gitHead'], {env: testEnv})).stdout
);
t.is(releasedVersion, version);
t.is(releasedGitHead, await gitHead());
@@ -284,7 +307,7 @@ test.serial('Release versions from a packed git repository, using tags to determ
version: '0.0.0-dev',
repository: {url: `git@github.com:${owner}/${packageName}.git`},
release: {verifyConditions: ['@semantic-release/github', '@semantic-release/npm']},
publishConfig: {registry: registry.uri},
publishConfig: {registry: npmRegistry.url},
});
/* Initial release */
@@ -319,7 +342,7 @@ test.serial('Release versions from a packed git repository, using tags to determ
// Verify package.json has been updated
t.is((await readJson('./package.json')).version, version);
// Retrieve the published package from the registry and check version
let releasedVersion = (await execa('npm', ['show', packageName, 'version'], {env})).stdout;
let releasedVersion = (await execa('npm', ['show', packageName, 'version'], {env: testEnv})).stdout;
t.is(releasedVersion, version);
t.log(`+ released ${releasedVersion}`);
await mockServer.verify(verifyMock);
@@ -360,7 +383,7 @@ test.serial('Release versions from a packed git repository, using tags to determ
t.is((await readJson('./package.json')).version, version);
// Retrieve the published package from the registry and check version
releasedVersion = (await execa('npm', ['show', packageName, 'version'], {env})).stdout;
releasedVersion = (await execa('npm', ['show', packageName, 'version'], {env: testEnv})).stdout;
t.is(releasedVersion, version);
t.log(`+ released ${releasedVersion}`);
await mockServer.verify(verifyMock);
@@ -399,7 +422,7 @@ test.serial('Create a tag as a recovery solution for "ENOTINHISTORY" error', asy
version: '0.0.0-dev',
repository: {url: `git+https://github.com/${owner}/${packageName}`},
release: {verifyConditions: ['@semantic-release/github', '@semantic-release/npm']},
publishConfig: {registry: registry.uri},
publishConfig: {registry: npmRegistry.url},
});
/* Initial release */
@@ -434,7 +457,7 @@ test.serial('Create a tag as a recovery solution for "ENOTINHISTORY" error', asy
// Retrieve the published package from the registry and check version and gitHead
let [, releasedVersion, releasedGitHead] = /^version = '(.+)'\s+gitHead = '(.+)'$/.exec(
(await execa('npm', ['show', packageName, 'version', 'gitHead'], {env})).stdout
(await execa('npm', ['show', packageName, 'version', 'gitHead'], {env: testEnv})).stdout
);
const head = await gitHead();
t.is(releasedGitHead, head);
@@ -509,7 +532,7 @@ test.serial('Create a tag as a recovery solution for "ENOTINHISTORY" error', asy
t.is((await readJson('./package.json')).version, version);
// Retrieve the published package from the registry and check version and gitHead
releasedVersion = (await execa('npm', ['show', packageName, 'version'], {env})).stdout;
releasedVersion = (await execa('npm', ['show', packageName, 'version'], {env: testEnv})).stdout;
t.is(releasedVersion, version);
t.log(`+ released ${releasedVersion}`);
await mockServer.verify(verifyMock);
@@ -528,7 +551,7 @@ test.serial('Dry-run', async t => {
name: packageName,
version: '0.0.0-dev',
repository: {url: `git+https://github.com/${owner}/${packageName}`},
publishConfig: {registry: registry.uri},
publishConfig: {registry: npmRegistry.url},
});
/* Initial release */
@@ -557,7 +580,7 @@ test.serial('Pass options via CLI arguments', async t => {
name: packageName,
version: '0.0.0-dev',
repository: {url: `git+https://github.com/${owner}/${packageName}`},
publishConfig: {registry: registry.uri},
publishConfig: {registry: npmRegistry.url},
});
/* Initial release */
@@ -578,7 +601,7 @@ test.serial('Pass options via CLI arguments', async t => {
// Retrieve the published package from the registry and check version and gitHead
const [, releasedVersion, releasedGitHead] = /^version = '(.+)'\s+gitHead = '(.+)'$/.exec(
(await execa('npm', ['show', packageName, 'version', 'gitHead'], {env})).stdout
(await execa('npm', ['show', packageName, 'version', 'gitHead'], {env: testEnv})).stdout
);
t.is(releasedVersion, version);
t.is(releasedGitHead, await gitHead());
@@ -597,7 +620,7 @@ test.serial('Run via JS API', async t => {
name: packageName,
version: '0.0.0-dev',
repository: {url: `git+https://github.com/${owner}/${packageName}`},
publishConfig: {registry: registry.uri},
publishConfig: {registry: npmRegistry.url},
});
/* Initial release */
@@ -640,7 +663,7 @@ test.serial('Run via JS API', async t => {
// Retrieve the published package from the registry and check version and gitHead
const [, releasedVersion, releasedGitHead] = /^version = '(.+)'\s+gitHead = '(.+)'$/.exec(
(await execa('npm', ['show', packageName, 'version', 'gitHead'], {env})).stdout
(await execa('npm', ['show', packageName, 'version', 'gitHead'], {env: testEnv})).stdout
);
t.is(releasedVersion, version);
t.is(releasedGitHead, await gitHead());
+3 -3
View File
@@ -89,12 +89,12 @@ test('The "analyzeCommits" plugin output must be either undefined or a valid sem
t.true(definitions.analyzeCommits.output.validator('major'));
});
test('The "generateNotes" plugin output must be a string', t => {
t.false(definitions.generateNotes.output.validator());
t.false(definitions.generateNotes.output.validator(null));
test('The "generateNotes" plugin output, if defined, must be a string', t => {
t.false(definitions.generateNotes.output.validator(1));
t.false(definitions.generateNotes.output.validator({}));
t.true(definitions.generateNotes.output.validator());
t.true(definitions.generateNotes.output.validator(null));
t.true(definitions.generateNotes.output.validator(''));
t.true(definitions.generateNotes.output.validator('string'));
});
+3 -3
View File
@@ -40,13 +40,13 @@ test('Wrap plugin in a function that validate the output of the plugin', async t
const pluginFunction = stub().resolves(1);
const plugin = normalize('', pluginFunction, t.context.logger, {
validator: output => output === 1,
message: 'The output must be 1',
message: 'The output must be 1.',
});
await t.notThrows(plugin());
pluginFunction.resolves(2);
const error = await t.throws(plugin());
const error = await t.throws(plugin(), Error);
t.is(error.message, 'The output must be 1. Received: 2');
});
@@ -104,7 +104,7 @@ test('Always pass a defined "pluginConfig" for plugin defined with path', async
});
test('Throws an error if the plugin return an object without the expected plugin function', t => {
const error = t.throws(() => normalize('inexistantPlugin', './test/fixtures/multi-plugin', t.context.logger));
const error = t.throws(() => normalize('inexistantPlugin', './test/fixtures/multi-plugin', t.context.logger), Error);
t.is(
error.message,
+1 -1
View File
@@ -32,7 +32,7 @@ test('Stop execution and throw error is a step rejects', async t => {
const step2 = stub().throws(new Error('test error'));
const step3 = stub().resolves(3);
const error = await t.throws(pipeline([step1, step2, step3])(0));
const error = await t.throws(pipeline([step1, step2, step3])(0), Error);
t.is(error.message, 'test error');
t.true(step1.calledWith(0));
t.true(step2.calledWith(0));
+5 -2
View File
@@ -49,7 +49,7 @@ test('Use default when only options are passed for a single plugin', t => {
});
test('Throw an error if plugin configuration is missing a path for plugin pipeline', t => {
const error = t.throws(() => getPlugins({verifyConditions: {}}, t.context.logger));
const error = t.throws(() => getPlugins({verifyConditions: {}}, t.context.logger), Error);
t.is(
error.message,
@@ -58,7 +58,10 @@ test('Throw an error if plugin configuration is missing a path for plugin pipeli
});
test('Throw an error if an array of plugin configuration is missing a path for plugin pipeline', t => {
const error = t.throws(() => getPlugins({verifyConditions: [{path: '@semantic-release/npm'}, {}]}, t.context.logger));
const error = t.throws(
() => getPlugins({verifyConditions: [{path: '@semantic-release/npm'}, {}]}, t.context.logger),
Error
);
t.is(
error.message,