feat: Make semantic-release language agnostic
- Do not rely on `package.json` anymore - Use `cosmiconfig` to load the configation. `semantic-release` can be configured: - via CLI options (including plugin names but not plugin options) - in the `release` property of `package.json` (as before) - in a `.releaserc.yml` or `.releaserc.js` or `.releaserc.js` or `release.config.js` file - in a `.releaserc` file containing `json`, `yaml` or `javascript` module - Add the `repositoryUrl` options (used across `semantic-release` and plugins). The value is determined from CLi option, or option configuration, or package.json or the git remote url - Verifies that `semantic-release` runs from a git repository - `pkg` and `env` are not passed to plugin anymore - `semantic-release` can be run both locally and globally. If ran globally with non default plugins, the plugins can be installed both globally or locally. BREAKING CHANGE: `pkg` and `env` are not passed to plugin anymore. Plugins relying on a `package.json` must verify the presence of a valid `package.json` and load it. Plugins can use `process.env` instead of `env`.
This commit is contained in:
parent
5bec59b26b
commit
0c67ba517f
@ -167,6 +167,7 @@ semantic-release
|
|||||||
|
|
||||||
These options are currently available:
|
These options are currently available:
|
||||||
- `branch`: The branch on which releases should happen. Default: `'master'`
|
- `branch`: The branch on which releases should happen. Default: `'master'`
|
||||||
|
- `repositoryUrl`: The git repository URL. Default: `repository` property in `package.json` or git origin url. Any valid git url format is supported (See [Git protocols](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols)). If the [Github plugin](https://github.com/semantic-release/github) is used the URL must be a valid Github URL that include the `owner`, the `repository` name and the `host`. The Github shorthand URL is not supported.
|
||||||
- `dry-run`: Dry-run mode, skipping verifyConditions, publishing and release, printing next version and release notes
|
- `dry-run`: Dry-run mode, skipping verifyConditions, publishing and release, printing next version and release notes
|
||||||
- `debug`: Output debugging information
|
- `debug`: Output debugging information
|
||||||
|
|
||||||
@ -206,9 +207,7 @@ module.exports = function (pluginConfig, config, callback) {}
|
|||||||
|
|
||||||
- `pluginConfig`: If the user of your plugin specifies additional plugin config in the `package.json` (see the `verifyConditions` example above) then it’s this object.
|
- `pluginConfig`: If the user of your plugin specifies additional plugin config in the `package.json` (see the `verifyConditions` example above) then it’s this object.
|
||||||
- `config`: A config object containing a lot of information to act upon.
|
- `config`: A config object containing a lot of information to act upon.
|
||||||
- `env`: All environment variables
|
|
||||||
- `options`: `semantic-release` options like `debug`, or `branch`
|
- `options`: `semantic-release` options like `debug`, or `branch`
|
||||||
- `pkg`: Parsed `package.json`
|
|
||||||
- For certain plugins the `config` object contains even more information. See below.
|
- For certain plugins the `config` object contains even more information. See below.
|
||||||
|
|
||||||
### `analyzeCommits`
|
### `analyzeCommits`
|
||||||
|
3
cli.js
3
cli.js
@ -10,6 +10,7 @@ module.exports = async () => {
|
|||||||
.name('semantic-release')
|
.name('semantic-release')
|
||||||
.description('Run automated package publishing')
|
.description('Run automated package publishing')
|
||||||
.option('-b, --branch <branch>', 'Branch to release from')
|
.option('-b, --branch <branch>', 'Branch to release from')
|
||||||
|
.option('-r, --repositoryUrl <repositoryUrl>', 'Git repository URL')
|
||||||
.option(
|
.option(
|
||||||
'--verify-conditions <paths>',
|
'--verify-conditions <paths>',
|
||||||
'Comma separated list of paths or packages name for the verifyConditions plugin(s)',
|
'Comma separated list of paths or packages name for the verifyConditions plugin(s)',
|
||||||
@ -41,7 +42,7 @@ module.exports = async () => {
|
|||||||
program.outputHelp();
|
program.outputHelp();
|
||||||
process.exitCode = 1;
|
process.exitCode = 1;
|
||||||
} else {
|
} else {
|
||||||
await require('./index')(program.opts());
|
await require('.')(program.opts());
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// If error is a SemanticReleaseError then it's an expected exception case (no release to be done, running on a PR etc..) and the cli will return with 0
|
// If error is a SemanticReleaseError then it's an expected exception case (no release to be done, running on a PR etc..) and the cli will return with 0
|
||||||
|
30
index.js
30
index.js
@ -1,32 +1,40 @@
|
|||||||
const marked = require('marked');
|
const marked = require('marked');
|
||||||
const TerminalRenderer = require('marked-terminal');
|
const TerminalRenderer = require('marked-terminal');
|
||||||
const SemanticReleaseError = require('@semantic-release/error');
|
const SemanticReleaseError = require('@semantic-release/error');
|
||||||
const {gitHead: getGitHead} = require('./lib/git');
|
|
||||||
const getConfig = require('./lib/get-config');
|
const getConfig = require('./lib/get-config');
|
||||||
const getNextVersion = require('./lib/get-next-version');
|
const getNextVersion = require('./lib/get-next-version');
|
||||||
const getCommits = require('./lib/get-commits');
|
const getCommits = require('./lib/get-commits');
|
||||||
const logger = require('./lib/logger');
|
const logger = require('./lib/logger');
|
||||||
|
const {gitHead: getGitHead, isGitRepo} = require('./lib/git');
|
||||||
|
|
||||||
module.exports = async opts => {
|
module.exports = async opts => {
|
||||||
const config = await getConfig(opts, logger);
|
if (!await isGitRepo()) {
|
||||||
const {plugins, env, options, pkg} = config;
|
throw new SemanticReleaseError('Semantic-release must run from a git repository', 'ENOGITREPO');
|
||||||
|
}
|
||||||
|
|
||||||
logger.log('Run automated release for branch %s', options.branch);
|
const config = await getConfig(opts, logger);
|
||||||
|
const {plugins, options} = config;
|
||||||
|
|
||||||
|
if (!options.repositoryUrl) {
|
||||||
|
throw new SemanticReleaseError('The repositoryUrl option is required', 'ENOREPOURL');
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.log('Run automated release from branch %s', options.name, options.branch);
|
||||||
|
|
||||||
if (!options.dryRun) {
|
if (!options.dryRun) {
|
||||||
logger.log('Call plugin %s', 'verify-conditions');
|
logger.log('Call plugin %s', 'verify-conditions');
|
||||||
await plugins.verifyConditions({env, options, pkg, logger});
|
await plugins.verifyConditions({options, logger});
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.log('Call plugin %s', 'get-last-release');
|
logger.log('Call plugin %s', 'get-last-release');
|
||||||
const {commits, lastRelease} = await getCommits(
|
const {commits, lastRelease} = await getCommits(
|
||||||
await plugins.getLastRelease({env, options, pkg, logger}),
|
await plugins.getLastRelease({options, logger}),
|
||||||
options.branch,
|
options.branch,
|
||||||
logger
|
logger
|
||||||
);
|
);
|
||||||
|
|
||||||
logger.log('Call plugin %s', 'analyze-commits');
|
logger.log('Call plugin %s', 'analyze-commits');
|
||||||
const type = await plugins.analyzeCommits({env, options, pkg, logger, lastRelease, commits});
|
const type = await plugins.analyzeCommits({options, logger, lastRelease, commits});
|
||||||
if (!type) {
|
if (!type) {
|
||||||
throw new SemanticReleaseError('There are no relevant changes, so no new version is released.', 'ENOCHANGE');
|
throw new SemanticReleaseError('There are no relevant changes, so no new version is released.', 'ENOCHANGE');
|
||||||
}
|
}
|
||||||
@ -34,9 +42,9 @@ module.exports = async opts => {
|
|||||||
const nextRelease = {type, version, gitHead: await getGitHead(), gitTag: `v${version}`};
|
const nextRelease = {type, version, gitHead: await getGitHead(), gitTag: `v${version}`};
|
||||||
|
|
||||||
logger.log('Call plugin %s', 'verify-release');
|
logger.log('Call plugin %s', 'verify-release');
|
||||||
await plugins.verifyRelease({env, options, pkg, logger, lastRelease, commits, nextRelease});
|
await plugins.verifyRelease({options, logger, lastRelease, commits, nextRelease});
|
||||||
|
|
||||||
const generateNotesParam = {env, options, pkg, logger, lastRelease, commits, nextRelease};
|
const generateNotesParam = {options, logger, lastRelease, commits, nextRelease};
|
||||||
|
|
||||||
if (options.dryRun) {
|
if (options.dryRun) {
|
||||||
logger.log('Call plugin %s', 'generate-notes');
|
logger.log('Call plugin %s', 'generate-notes');
|
||||||
@ -49,7 +57,7 @@ module.exports = async opts => {
|
|||||||
nextRelease.notes = await plugins.generateNotes(generateNotesParam);
|
nextRelease.notes = await plugins.generateNotes(generateNotesParam);
|
||||||
|
|
||||||
logger.log('Call plugin %s', 'publish');
|
logger.log('Call plugin %s', 'publish');
|
||||||
await plugins.publish({options, pkg, logger, lastRelease, commits, nextRelease}, async prevInput => {
|
await plugins.publish({options, logger, lastRelease, commits, nextRelease}, async prevInput => {
|
||||||
const newGitHead = await getGitHead();
|
const newGitHead = await getGitHead();
|
||||||
// If previous publish plugin has created a commit (gitHead changed)
|
// If previous publish plugin has created a commit (gitHead changed)
|
||||||
if (prevInput.nextRelease.gitHead !== newGitHead) {
|
if (prevInput.nextRelease.gitHead !== newGitHead) {
|
||||||
@ -59,7 +67,7 @@ module.exports = async opts => {
|
|||||||
nextRelease.notes = await plugins.generateNotes(generateNotesParam);
|
nextRelease.notes = await plugins.generateNotes(generateNotesParam);
|
||||||
}
|
}
|
||||||
// Call the next publish plugin with the updated `nextRelease`
|
// Call the next publish plugin with the updated `nextRelease`
|
||||||
return {options, pkg, logger, lastRelease, commits, nextRelease};
|
return {options, logger, lastRelease, commits, nextRelease};
|
||||||
});
|
});
|
||||||
logger.log('Published release: %s', nextRelease.version);
|
logger.log('Published release: %s', nextRelease.version);
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,27 @@
|
|||||||
const {readJson} = require('fs-extra');
|
const readPkgUp = require('read-pkg-up');
|
||||||
const {defaults} = require('lodash');
|
const {defaults} = require('lodash');
|
||||||
const normalizeData = require('normalize-package-data');
|
const cosmiconfig = require('cosmiconfig');
|
||||||
const debug = require('debug')('semantic-release:config');
|
const debug = require('debug')('semantic-release:config');
|
||||||
|
const {repoUrl} = require('./git');
|
||||||
const plugins = require('./plugins');
|
const plugins = require('./plugins');
|
||||||
|
|
||||||
module.exports = async (opts, logger) => {
|
module.exports = async (opts, logger) => {
|
||||||
const pkg = await readJson('./package.json');
|
const {config} = (await cosmiconfig('release', {rcExtensions: true}).load(process.cwd())) || {};
|
||||||
normalizeData(pkg);
|
const options = defaults(opts, config, {branch: 'master', repositoryUrl: (await pkgRepoUrl()) || (await repoUrl())});
|
||||||
const options = defaults(opts, pkg.release, {branch: 'master'});
|
|
||||||
|
debug('name: %O', options.name);
|
||||||
debug('branch: %O', options.branch);
|
debug('branch: %O', options.branch);
|
||||||
|
debug('repositoryUrl: %O', options.repositoryUrl);
|
||||||
debug('analyzeCommits: %O', options.analyzeCommits);
|
debug('analyzeCommits: %O', options.analyzeCommits);
|
||||||
debug('generateNotes: %O', options.generateNotes);
|
debug('generateNotes: %O', options.generateNotes);
|
||||||
debug('verifyConditions: %O', options.verifyConditions);
|
debug('verifyConditions: %O', options.verifyConditions);
|
||||||
debug('verifyRelease: %O', options.verifyRelease);
|
debug('verifyRelease: %O', options.verifyRelease);
|
||||||
debug('publish: %O', options.publish);
|
debug('publish: %O', options.publish);
|
||||||
|
|
||||||
return {env: process.env, pkg, options, plugins: await plugins(options, logger), logger};
|
return {options, plugins: await plugins(options, logger)};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async function pkgRepoUrl() {
|
||||||
|
const {pkg} = await readPkgUp();
|
||||||
|
return pkg && pkg.repository ? pkg.repository.url : null;
|
||||||
|
}
|
||||||
|
18
lib/git.js
18
lib/git.js
@ -72,4 +72,20 @@ async function gitHead() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {gitTagHead, gitCommitTag, isCommitInHistory, unshallow, gitHead};
|
/**
|
||||||
|
* @return {string|null} The value of the remote git URL.
|
||||||
|
*/
|
||||||
|
async function repoUrl() {
|
||||||
|
return (await execa.stdout('git', ['remote', 'get-url', 'origin'], {reject: false})) || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {Boolean} `true` if the current working directory is in a git repository, `false` otherwise.
|
||||||
|
*/
|
||||||
|
async function isGitRepo() {
|
||||||
|
const shell = await execa('git', ['rev-parse', '--git-dir'], {reject: false});
|
||||||
|
debugShell('Check if the current working directory is a git repository', shell, debug);
|
||||||
|
return shell.code === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {gitTagHead, gitCommitTag, isCommitInHistory, unshallow, gitHead, repoUrl, isGitRepo};
|
||||||
|
21
package.json
21
package.json
@ -15,25 +15,25 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@semantic-release/commit-analyzer": "^4.0.0",
|
"@semantic-release/commit-analyzer": "^5.0.0",
|
||||||
"@semantic-release/condition-travis": "^6.0.0",
|
"@semantic-release/condition-travis": "^7.0.0",
|
||||||
"@semantic-release/error": "^2.1.0",
|
"@semantic-release/error": "^2.1.0",
|
||||||
"@semantic-release/github": "^1.0.0",
|
"@semantic-release/github": "^2.0.0",
|
||||||
"@semantic-release/npm": "^1.0.0",
|
"@semantic-release/npm": "^2.0.0",
|
||||||
"@semantic-release/release-notes-generator": "^5.0.0",
|
"@semantic-release/release-notes-generator": "^6.0.0",
|
||||||
"chalk": "^2.3.0",
|
"chalk": "^2.3.0",
|
||||||
"commander": "^2.11.0",
|
"commander": "^2.11.0",
|
||||||
|
"cosmiconfig": "^3.1.0",
|
||||||
"debug": "^3.1.0",
|
"debug": "^3.1.0",
|
||||||
"execa": "^0.8.0",
|
"execa": "^0.8.0",
|
||||||
"fs-extra": "^4.0.2",
|
|
||||||
"get-stream": "^3.0.0",
|
"get-stream": "^3.0.0",
|
||||||
"git-log-parser": "^1.2.0",
|
"git-log-parser": "^1.2.0",
|
||||||
"import-from": "^2.1.0",
|
"import-from": "^2.1.0",
|
||||||
"lodash": "^4.0.0",
|
"lodash": "^4.0.0",
|
||||||
"marked": "^0.3.6",
|
"marked": "^0.3.6",
|
||||||
"marked-terminal": "^2.0.0",
|
"marked-terminal": "^2.0.0",
|
||||||
"normalize-package-data": "^2.3.4",
|
|
||||||
"p-reduce": "^1.0.0",
|
"p-reduce": "^1.0.0",
|
||||||
|
"read-pkg-up": "^3.0.0",
|
||||||
"semver": "^5.4.1"
|
"semver": "^5.4.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -44,11 +44,13 @@
|
|||||||
"dockerode": "^2.5.2",
|
"dockerode": "^2.5.2",
|
||||||
"eslint-config-prettier": "^2.5.0",
|
"eslint-config-prettier": "^2.5.0",
|
||||||
"eslint-plugin-prettier": "^2.3.0",
|
"eslint-plugin-prettier": "^2.3.0",
|
||||||
|
"file-url": "^2.0.2",
|
||||||
|
"fs-extra": "^4.0.2",
|
||||||
|
"js-yaml": "^3.10.0",
|
||||||
"mockserver-client": "^2.0.0",
|
"mockserver-client": "^2.0.0",
|
||||||
"nock": "^9.0.2",
|
"nock": "^9.0.2",
|
||||||
"npm-registry-couchapp": "^2.6.12",
|
"npm-registry-couchapp": "^2.6.12",
|
||||||
"nyc": "^11.2.1",
|
"nyc": "^11.2.1",
|
||||||
"p-map-series": "^1.0.0",
|
|
||||||
"prettier": "~1.8.0",
|
"prettier": "~1.8.0",
|
||||||
"proxyquire": "^1.8.0",
|
"proxyquire": "^1.8.0",
|
||||||
"sinon": "^4.0.0",
|
"sinon": "^4.0.0",
|
||||||
@ -124,7 +126,8 @@
|
|||||||
"prettier"
|
"prettier"
|
||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
"prettier/prettier": 2
|
"prettier/prettier": 2,
|
||||||
|
"no-duplicate-imports": 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import test from 'ava';
|
import test from 'ava';
|
||||||
import {writeJson} from 'fs-extra';
|
import {writeFile, writeJson} from 'fs-extra';
|
||||||
import proxyquire from 'proxyquire';
|
import proxyquire from 'proxyquire';
|
||||||
import {stub} from 'sinon';
|
import {stub} from 'sinon';
|
||||||
import normalizeData from 'normalize-package-data';
|
import yaml from 'js-yaml';
|
||||||
import {gitRepo} from './helpers/git-utils';
|
import {gitRepo, gitCommits, gitShallowClone, gitAddConfig} from './helpers/git-utils';
|
||||||
|
|
||||||
test.beforeEach(t => {
|
test.beforeEach(t => {
|
||||||
// Save the current process.env
|
// Save the current process.env
|
||||||
@ -21,85 +21,175 @@ test.afterEach.always(t => {
|
|||||||
process.env = Object.assign({}, t.context.env);
|
process.env = Object.assign({}, t.context.env);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.serial('Default values', async t => {
|
test.serial('Default values, reading repositoryUrl from package.json', async t => {
|
||||||
const pkg = {name: 'package_name', release: {}};
|
const pkg = {repository: 'git@package.com:owner/module.git'};
|
||||||
|
// Create a git repository, set the current working directory at the root of the repo
|
||||||
|
await gitRepo();
|
||||||
|
await gitCommits(['First']);
|
||||||
|
// Add remote.origin.url config
|
||||||
|
await gitAddConfig('remote.origin.url', 'git@repo.com:owner/module.git');
|
||||||
|
// Create package.json in repository root
|
||||||
|
await writeJson('./package.json', pkg);
|
||||||
|
|
||||||
|
const {options} = await t.context.getConfig();
|
||||||
|
|
||||||
|
// Verify the default options are set
|
||||||
|
t.is(options.branch, 'master');
|
||||||
|
t.is(options.repositoryUrl, 'git@package.com:owner/module.git');
|
||||||
|
});
|
||||||
|
|
||||||
|
test.serial('Default values, reading repositoryUrl from repo if not set in package.json', async t => {
|
||||||
|
// Create a git repository, set the current working directory at the root of the repo
|
||||||
|
await gitRepo();
|
||||||
|
// Add remote.origin.url config
|
||||||
|
await gitAddConfig('remote.origin.url', 'git@repo.com:owner/module.git');
|
||||||
|
|
||||||
|
const {options} = await t.context.getConfig();
|
||||||
|
|
||||||
|
// Verify the default options are set
|
||||||
|
t.is(options.branch, 'master');
|
||||||
|
t.is(options.repositoryUrl, 'git@repo.com:owner/module.git');
|
||||||
|
});
|
||||||
|
|
||||||
|
test.serial('Default values, reading repositoryUrl (http url) from package.json if not set in repo', async t => {
|
||||||
|
const pkg = {repository: 'git+https://hostname.com/owner/module.git'};
|
||||||
// Create a git repository, set the current working directory at the root of the repo
|
// Create a git repository, set the current working directory at the root of the repo
|
||||||
await gitRepo();
|
await gitRepo();
|
||||||
// Create package.json in repository root
|
// Create package.json in repository root
|
||||||
await writeJson('./package.json', pkg);
|
await writeJson('./package.json', pkg);
|
||||||
|
|
||||||
const result = await t.context.getConfig();
|
const {options} = await t.context.getConfig();
|
||||||
|
|
||||||
// Verify the normalized package is returned
|
|
||||||
normalizeData(pkg);
|
|
||||||
t.deepEqual(result.pkg, pkg);
|
|
||||||
// Verify the default options are set
|
// Verify the default options are set
|
||||||
t.is(result.options.branch, 'master');
|
t.is(options.branch, 'master');
|
||||||
|
t.is(options.repositoryUrl, pkg.repository);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.serial('Read package.json configuration', async t => {
|
test.serial('Read options from package.json', async t => {
|
||||||
const release = {
|
const release = {
|
||||||
analyzeCommits: 'analyzeCommits',
|
analyzeCommits: 'analyzeCommits',
|
||||||
generateNotes: 'generateNotes',
|
generateNotes: 'generateNotes',
|
||||||
getLastRelease: {
|
getLastRelease: {path: 'getLastRelease', param: 'getLastRelease_param'},
|
||||||
path: 'getLastRelease',
|
|
||||||
param: 'getLastRelease_param',
|
|
||||||
},
|
|
||||||
branch: 'test_branch',
|
branch: 'test_branch',
|
||||||
|
repositoryUrl: 'git+https://hostname.com/owner/module.git',
|
||||||
};
|
};
|
||||||
const pkg = {name: 'package_name', release};
|
|
||||||
|
|
||||||
// Create a git repository, set the current working directory at the root of the repo
|
// Create a git repository, set the current working directory at the root of the repo
|
||||||
await gitRepo();
|
await gitRepo();
|
||||||
// Create package.json in repository root
|
// Create package.json in repository root
|
||||||
await writeJson('./package.json', pkg);
|
await writeJson('./package.json', {release});
|
||||||
|
|
||||||
const result = await t.context.getConfig();
|
const {options} = await t.context.getConfig();
|
||||||
|
|
||||||
// Verify the options contains the plugin config from package.json
|
// Verify the options contains the plugin config from package.json
|
||||||
t.is(result.options.analyzeCommits, release.analyzeCommits);
|
t.deepEqual(options, release);
|
||||||
t.is(result.options.generateNotes, release.generateNotes);
|
|
||||||
t.deepEqual(result.options.getLastRelease, release.getLastRelease);
|
|
||||||
t.is(result.options.branch, release.branch);
|
|
||||||
|
|
||||||
// Verify the plugins module is called with the plugin options from package.json
|
// Verify the plugins module is called with the plugin options from package.json
|
||||||
t.is(t.context.plugins.firstCall.args[0].analyzeCommits, release.analyzeCommits);
|
t.deepEqual(t.context.plugins.firstCall.args[0], release);
|
||||||
t.is(t.context.plugins.firstCall.args[0].generateNotes, release.generateNotes);
|
|
||||||
t.deepEqual(t.context.plugins.firstCall.args[0].getLastRelease, release.getLastRelease);
|
|
||||||
t.is(t.context.plugins.firstCall.args[0].branch, release.branch);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test.serial('Prioritise cli parameters over package.json configuration', async t => {
|
test.serial('Read options from .releaserc.yml', async t => {
|
||||||
const release = {
|
const release = {
|
||||||
analyzeCommits: 'analyzeCommits',
|
getLastRelease: {path: 'getLastRelease', param: 'getLastRelease_param'},
|
||||||
generateNotes: 'generateNotes',
|
branch: 'test_branch',
|
||||||
getLastRelease: {
|
repositoryUrl: 'git+https://hostname.com/owner/module.git',
|
||||||
path: 'getLastRelease',
|
};
|
||||||
param: 'getLastRelease_pkg',
|
|
||||||
},
|
// Create a git repository, set the current working directory at the root of the repo
|
||||||
|
await gitRepo();
|
||||||
|
// Create package.json in repository root
|
||||||
|
await writeFile('.releaserc.yml', yaml.safeDump(release));
|
||||||
|
|
||||||
|
const {options} = await t.context.getConfig();
|
||||||
|
|
||||||
|
// Verify the options contains the plugin config from package.json
|
||||||
|
t.deepEqual(options, release);
|
||||||
|
// Verify the plugins module is called with the plugin options from package.json
|
||||||
|
t.deepEqual(t.context.plugins.firstCall.args[0], release);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.serial('Read options from .releaserc.json', async t => {
|
||||||
|
const release = {
|
||||||
|
getLastRelease: {path: 'getLastRelease', param: 'getLastRelease_param'},
|
||||||
|
branch: 'test_branch',
|
||||||
|
repositoryUrl: 'git+https://hostname.com/owner/module.git',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a git repository, set the current working directory at the root of the repo
|
||||||
|
await gitRepo();
|
||||||
|
// Create package.json in repository root
|
||||||
|
await writeJson('.releaserc.json', release);
|
||||||
|
|
||||||
|
const {options} = await t.context.getConfig();
|
||||||
|
|
||||||
|
// Verify the options contains the plugin config from package.json
|
||||||
|
t.deepEqual(options, release);
|
||||||
|
// Verify the plugins module is called with the plugin options from package.json
|
||||||
|
t.deepEqual(t.context.plugins.firstCall.args[0], release);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.serial('Read options from .releaserc.js', async t => {
|
||||||
|
const release = {
|
||||||
|
getLastRelease: {path: 'getLastRelease', param: 'getLastRelease_param'},
|
||||||
|
branch: 'test_branch',
|
||||||
|
repositoryUrl: 'git+https://hostname.com/owner/module.git',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a git repository, set the current working directory at the root of the repo
|
||||||
|
await gitRepo();
|
||||||
|
// Create package.json in repository root
|
||||||
|
await writeFile('.releaserc.js', `module.exports = ${JSON.stringify(release)}`);
|
||||||
|
|
||||||
|
const {options} = await t.context.getConfig();
|
||||||
|
|
||||||
|
// Verify the options contains the plugin config from package.json
|
||||||
|
t.deepEqual(options, release);
|
||||||
|
// Verify the plugins module is called with the plugin options from package.json
|
||||||
|
t.deepEqual(t.context.plugins.firstCall.args[0], release);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.serial('Read options from release.config.js', async t => {
|
||||||
|
const release = {
|
||||||
|
getLastRelease: {path: 'getLastRelease', param: 'getLastRelease_param'},
|
||||||
|
branch: 'test_branch',
|
||||||
|
repositoryUrl: 'git+https://hostname.com/owner/module.git',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a git repository, set the current working directory at the root of the repo
|
||||||
|
await gitRepo();
|
||||||
|
// Create package.json in repository root
|
||||||
|
await writeFile('release.config.js', `module.exports = ${JSON.stringify(release)}`);
|
||||||
|
|
||||||
|
const {options} = await t.context.getConfig();
|
||||||
|
|
||||||
|
// Verify the options contains the plugin config from package.json
|
||||||
|
t.deepEqual(options, release);
|
||||||
|
// Verify the plugins module is called with the plugin options from package.json
|
||||||
|
t.deepEqual(t.context.plugins.firstCall.args[0], release);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.serial('Prioritise cli parameters over file configuration and git repo', async t => {
|
||||||
|
const release = {
|
||||||
|
getLastRelease: {path: 'getLastRelease', param: 'getLastRelease_pkg'},
|
||||||
branch: 'branch_pkg',
|
branch: 'branch_pkg',
|
||||||
};
|
};
|
||||||
const options = {
|
const options = {
|
||||||
getLastRelease: {
|
getLastRelease: {path: 'getLastRelease', param: 'getLastRelease_cli'},
|
||||||
path: 'getLastRelease',
|
|
||||||
param: 'getLastRelease_cli',
|
|
||||||
},
|
|
||||||
branch: 'branch_cli',
|
branch: 'branch_cli',
|
||||||
|
repositoryUrl: 'http://cli-url.com/owner/package',
|
||||||
};
|
};
|
||||||
const pkg = {name: 'package_name', release};
|
const pkg = {release, repository: 'git@hostname.com:owner/module.git'};
|
||||||
|
|
||||||
// Create a git repository, set the current working directory at the root of the repo
|
// Create a git repository, set the current working directory at the root of the repo
|
||||||
await gitRepo();
|
const repo = await gitRepo();
|
||||||
|
await gitCommits(['First']);
|
||||||
|
// Create a clone
|
||||||
|
await gitShallowClone(repo);
|
||||||
// Create package.json in repository root
|
// Create package.json in repository root
|
||||||
await writeJson('./package.json', pkg);
|
await writeJson('./package.json', pkg);
|
||||||
|
|
||||||
const result = await t.context.getConfig(options);
|
const result = await t.context.getConfig(options);
|
||||||
|
|
||||||
// Verify the options contains the plugin config from cli
|
// Verify the options contains the plugin config from cli
|
||||||
t.deepEqual(result.options.getLastRelease, options.getLastRelease);
|
t.deepEqual(result.options, options);
|
||||||
t.is(result.options.branch, options.branch);
|
|
||||||
|
|
||||||
// Verify the plugins module is called with the plugin options from cli
|
// Verify the plugins module is called with the plugin options from cli
|
||||||
t.deepEqual(t.context.plugins.firstCall.args[0].getLastRelease, options.getLastRelease);
|
t.deepEqual(t.context.plugins.firstCall.args[0], options);
|
||||||
t.is(t.context.plugins.firstCall.args[0].branch, options.branch);
|
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
import test from 'ava';
|
import test from 'ava';
|
||||||
import {gitTagHead, gitCommitTag, isCommitInHistory, unshallow, gitHead} from '../lib/git';
|
import fileUrl from 'file-url';
|
||||||
import {gitRepo, gitCommits, gitCheckout, gitTagVersion, gitShallowClone, gitLog} from './helpers/git-utils';
|
import {gitTagHead, gitCommitTag, isCommitInHistory, unshallow, gitHead, repoUrl} from '../lib/git';
|
||||||
|
import {
|
||||||
|
gitRepo,
|
||||||
|
gitCommits,
|
||||||
|
gitCheckout,
|
||||||
|
gitTagVersion,
|
||||||
|
gitShallowClone,
|
||||||
|
gitLog,
|
||||||
|
gitAddConfig,
|
||||||
|
} from './helpers/git-utils';
|
||||||
|
|
||||||
test.beforeEach(t => {
|
test.beforeEach(t => {
|
||||||
// Save the current working diretory
|
// Save the current working diretory
|
||||||
@ -93,3 +102,29 @@ test.serial('Get the commit sha for a given tag or "null" if the tag does not ex
|
|||||||
t.is((await gitTagHead('v1.0.0')).substring(0, 7), commits[0].hash);
|
t.is((await gitTagHead('v1.0.0')).substring(0, 7), commits[0].hash);
|
||||||
t.falsy(await gitTagHead('missing_tag'));
|
t.falsy(await gitTagHead('missing_tag'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test.serial('Return git remote repository url from config', async t => {
|
||||||
|
// Create a git repository, set the current working directory at the root of the repo
|
||||||
|
await gitRepo();
|
||||||
|
// Add remote.origin.url config
|
||||||
|
await gitAddConfig('remote.origin.url', 'git@hostname.com:owner/package.git');
|
||||||
|
|
||||||
|
t.is(await repoUrl(), 'git@hostname.com:owner/package.git');
|
||||||
|
});
|
||||||
|
|
||||||
|
test.serial('Return git remote repository url set while cloning', async t => {
|
||||||
|
// Create a git repository, set the current working directory at the root of the repo
|
||||||
|
const repo = await gitRepo();
|
||||||
|
await gitCommits(['First']);
|
||||||
|
// Create a clone
|
||||||
|
await gitShallowClone(repo);
|
||||||
|
|
||||||
|
t.is(await repoUrl(), fileUrl(repo));
|
||||||
|
});
|
||||||
|
|
||||||
|
test.serial('Return "null" if git repository url is not set', async t => {
|
||||||
|
// Create a git repository, set the current working directory at the root of the repo
|
||||||
|
await gitRepo();
|
||||||
|
|
||||||
|
t.is(await repoUrl(), null);
|
||||||
|
});
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import tempy from 'tempy';
|
import tempy from 'tempy';
|
||||||
import execa from 'execa';
|
import execa from 'execa';
|
||||||
import pMapSeries from 'p-map-series';
|
import fileUrl from 'file-url';
|
||||||
|
import pReduce from 'p-reduce';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Commit message informations.
|
* Commit message informations.
|
||||||
@ -33,11 +34,16 @@ export async function gitRepo() {
|
|||||||
* @returns {Array<Commit>} The created commits, in reverse order (to match `git log` order).
|
* @returns {Array<Commit>} The created commits, in reverse order (to match `git log` order).
|
||||||
*/
|
*/
|
||||||
export async function gitCommits(messages) {
|
export async function gitCommits(messages) {
|
||||||
return (await pMapSeries(messages, async msg => {
|
return (await pReduce(
|
||||||
const {stdout} = await execa('git', ['commit', '-m', msg, '--allow-empty', '--no-gpg-sign']);
|
messages,
|
||||||
const [, branch, hash, message] = /^\[(\w+)\(?.*?\)?(\w+)\] (.+)$/.exec(stdout);
|
async (commits, msg) => {
|
||||||
return {branch, hash, message};
|
const {stdout} = await execa('git', ['commit', '-m', msg, '--allow-empty', '--no-gpg-sign']);
|
||||||
})).reverse();
|
const [, branch, hash, message] = /^\[(\w+)\(?.*?\)?(\w+)\] (.+)$/.exec(stdout);
|
||||||
|
commits.push({branch, hash, message});
|
||||||
|
return commits;
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
)).reverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -109,7 +115,7 @@ export async function gitShallowClone(origin, branch = 'master', depth = 1) {
|
|||||||
const dir = tempy.directory();
|
const dir = tempy.directory();
|
||||||
|
|
||||||
process.chdir(dir);
|
process.chdir(dir);
|
||||||
await execa('git', ['clone', '--no-hardlinks', '--no-tags', '-b', branch, '--depth', depth, `file://${origin}`, dir]);
|
await execa('git', ['clone', '--no-hardlinks', '--no-tags', '-b', branch, '--depth', depth, fileUrl(origin), dir]);
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,3 +143,13 @@ export async function gitDetachedHead(origin, head) {
|
|||||||
export async function gitPackRefs() {
|
export async function gitPackRefs() {
|
||||||
await execa('git', ['pack-refs', '--all']);
|
await execa('git', ['pack-refs', '--all']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new Git configuration.
|
||||||
|
*
|
||||||
|
* @param {string} name Config name.
|
||||||
|
* @param {string} value Config value.
|
||||||
|
*/
|
||||||
|
export async function gitAddConfig(name, value) {
|
||||||
|
await execa('git', ['config', '--add', name, value]);
|
||||||
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import test from 'ava';
|
import test from 'ava';
|
||||||
import {writeJson} from 'fs-extra';
|
|
||||||
import proxyquire from 'proxyquire';
|
import proxyquire from 'proxyquire';
|
||||||
import {stub} from 'sinon';
|
import {stub} from 'sinon';
|
||||||
import normalizeData from 'normalize-package-data';
|
import tempy from 'tempy';
|
||||||
|
import SemanticReleaseError from '@semantic-release/error';
|
||||||
import {gitHead as getGitHead} from '../lib/git';
|
import {gitHead as getGitHead} from '../lib/git';
|
||||||
import {gitRepo, gitCommits, gitTagVersion} from './helpers/git-utils';
|
import {gitRepo, gitCommits, gitTagVersion} from './helpers/git-utils';
|
||||||
|
|
||||||
@ -41,11 +41,9 @@ test.serial('Plugins are called with expected values', async t => {
|
|||||||
// Add new commits to the master branch
|
// Add new commits to the master branch
|
||||||
commits = (await gitCommits(['Second'])).concat(commits);
|
commits = (await gitCommits(['Second'])).concat(commits);
|
||||||
|
|
||||||
const name = 'package-name';
|
|
||||||
const lastRelease = {version: '1.0.0', gitHead: commits[commits.length - 1].hash, gitTag: 'v1.0.0'};
|
const lastRelease = {version: '1.0.0', gitHead: commits[commits.length - 1].hash, gitTag: 'v1.0.0'};
|
||||||
const nextRelease = {type: 'major', version: '2.0.0', gitHead: await getGitHead(), gitTag: 'v2.0.0'};
|
const nextRelease = {type: 'major', version: '2.0.0', gitHead: await getGitHead(), gitTag: 'v2.0.0'};
|
||||||
const notes = 'Release notes';
|
const notes = 'Release notes';
|
||||||
|
|
||||||
const verifyConditions1 = stub().resolves();
|
const verifyConditions1 = stub().resolves();
|
||||||
const verifyConditions2 = stub().resolves();
|
const verifyConditions2 = stub().resolves();
|
||||||
const getLastRelease = stub().resolves(lastRelease);
|
const getLastRelease = stub().resolves(lastRelease);
|
||||||
@ -56,6 +54,7 @@ test.serial('Plugins are called with expected values', async t => {
|
|||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
branch: 'master',
|
branch: 'master',
|
||||||
|
repositoryUrl: 'git@hostname.com:owner/module.git',
|
||||||
verifyConditions: [verifyConditions1, verifyConditions2],
|
verifyConditions: [verifyConditions1, verifyConditions2],
|
||||||
getLastRelease,
|
getLastRelease,
|
||||||
analyzeCommits,
|
analyzeCommits,
|
||||||
@ -63,34 +62,26 @@ test.serial('Plugins are called with expected values', async t => {
|
|||||||
generateNotes,
|
generateNotes,
|
||||||
publish,
|
publish,
|
||||||
};
|
};
|
||||||
const pkg = {name, version: '0.0.0-dev'};
|
|
||||||
normalizeData(pkg);
|
|
||||||
|
|
||||||
await writeJson('./package.json', pkg);
|
|
||||||
|
|
||||||
await t.context.semanticRelease(options);
|
await t.context.semanticRelease(options);
|
||||||
|
|
||||||
t.true(verifyConditions1.calledOnce);
|
t.true(verifyConditions1.calledOnce);
|
||||||
t.deepEqual(verifyConditions1.firstCall.args[1], {env: process.env, options, pkg, logger: t.context.logger});
|
t.deepEqual(verifyConditions1.firstCall.args[1], {options, logger: t.context.logger});
|
||||||
t.true(verifyConditions2.calledOnce);
|
t.true(verifyConditions2.calledOnce);
|
||||||
t.deepEqual(verifyConditions2.firstCall.args[1], {env: process.env, options, pkg, logger: t.context.logger});
|
t.deepEqual(verifyConditions2.firstCall.args[1], {options, logger: t.context.logger});
|
||||||
|
|
||||||
t.true(getLastRelease.calledOnce);
|
t.true(getLastRelease.calledOnce);
|
||||||
t.deepEqual(getLastRelease.firstCall.args[1], {env: process.env, options, pkg, logger: t.context.logger});
|
t.deepEqual(getLastRelease.firstCall.args[1], {options, logger: t.context.logger});
|
||||||
|
|
||||||
t.true(analyzeCommits.calledOnce);
|
t.true(analyzeCommits.calledOnce);
|
||||||
t.deepEqual(analyzeCommits.firstCall.args[1].env, process.env);
|
|
||||||
t.deepEqual(analyzeCommits.firstCall.args[1].options, options);
|
t.deepEqual(analyzeCommits.firstCall.args[1].options, options);
|
||||||
t.deepEqual(analyzeCommits.firstCall.args[1].pkg, pkg);
|
|
||||||
t.deepEqual(analyzeCommits.firstCall.args[1].logger, t.context.logger);
|
t.deepEqual(analyzeCommits.firstCall.args[1].logger, t.context.logger);
|
||||||
t.deepEqual(analyzeCommits.firstCall.args[1].lastRelease, lastRelease);
|
t.deepEqual(analyzeCommits.firstCall.args[1].lastRelease, lastRelease);
|
||||||
t.deepEqual(analyzeCommits.firstCall.args[1].commits[0].hash.substring(0, 7), commits[0].hash);
|
t.deepEqual(analyzeCommits.firstCall.args[1].commits[0].hash.substring(0, 7), commits[0].hash);
|
||||||
t.deepEqual(analyzeCommits.firstCall.args[1].commits[0].message, commits[0].message);
|
t.deepEqual(analyzeCommits.firstCall.args[1].commits[0].message, commits[0].message);
|
||||||
|
|
||||||
t.true(verifyRelease.calledOnce);
|
t.true(verifyRelease.calledOnce);
|
||||||
t.deepEqual(verifyRelease.firstCall.args[1].env, process.env);
|
|
||||||
t.deepEqual(verifyRelease.firstCall.args[1].options, options);
|
t.deepEqual(verifyRelease.firstCall.args[1].options, options);
|
||||||
t.deepEqual(verifyRelease.firstCall.args[1].pkg, pkg);
|
|
||||||
t.deepEqual(verifyRelease.firstCall.args[1].logger, t.context.logger);
|
t.deepEqual(verifyRelease.firstCall.args[1].logger, t.context.logger);
|
||||||
t.deepEqual(verifyRelease.firstCall.args[1].lastRelease, lastRelease);
|
t.deepEqual(verifyRelease.firstCall.args[1].lastRelease, lastRelease);
|
||||||
t.deepEqual(verifyRelease.firstCall.args[1].commits[0].hash.substring(0, 7), commits[0].hash);
|
t.deepEqual(verifyRelease.firstCall.args[1].commits[0].hash.substring(0, 7), commits[0].hash);
|
||||||
@ -98,9 +89,7 @@ test.serial('Plugins are called with expected values', async t => {
|
|||||||
t.deepEqual(verifyRelease.firstCall.args[1].nextRelease, nextRelease);
|
t.deepEqual(verifyRelease.firstCall.args[1].nextRelease, nextRelease);
|
||||||
|
|
||||||
t.true(generateNotes.calledOnce);
|
t.true(generateNotes.calledOnce);
|
||||||
t.deepEqual(generateNotes.firstCall.args[1].env, process.env);
|
|
||||||
t.deepEqual(generateNotes.firstCall.args[1].options, options);
|
t.deepEqual(generateNotes.firstCall.args[1].options, options);
|
||||||
t.deepEqual(generateNotes.firstCall.args[1].pkg, pkg);
|
|
||||||
t.deepEqual(generateNotes.firstCall.args[1].logger, t.context.logger);
|
t.deepEqual(generateNotes.firstCall.args[1].logger, t.context.logger);
|
||||||
t.deepEqual(generateNotes.firstCall.args[1].lastRelease, lastRelease);
|
t.deepEqual(generateNotes.firstCall.args[1].lastRelease, lastRelease);
|
||||||
t.deepEqual(generateNotes.firstCall.args[1].commits[0].hash.substring(0, 7), commits[0].hash);
|
t.deepEqual(generateNotes.firstCall.args[1].commits[0].hash.substring(0, 7), commits[0].hash);
|
||||||
@ -109,7 +98,6 @@ test.serial('Plugins are called with expected values', async t => {
|
|||||||
|
|
||||||
t.true(publish.calledOnce);
|
t.true(publish.calledOnce);
|
||||||
t.deepEqual(publish.firstCall.args[1].options, options);
|
t.deepEqual(publish.firstCall.args[1].options, options);
|
||||||
t.deepEqual(publish.firstCall.args[1].pkg, pkg);
|
|
||||||
t.deepEqual(publish.firstCall.args[1].logger, t.context.logger);
|
t.deepEqual(publish.firstCall.args[1].logger, t.context.logger);
|
||||||
t.deepEqual(publish.firstCall.args[1].lastRelease, lastRelease);
|
t.deepEqual(publish.firstCall.args[1].lastRelease, lastRelease);
|
||||||
t.deepEqual(publish.firstCall.args[1].commits[0].hash.substring(0, 7), commits[0].hash);
|
t.deepEqual(publish.firstCall.args[1].commits[0].hash.substring(0, 7), commits[0].hash);
|
||||||
@ -139,6 +127,7 @@ test.serial('Use new gitHead, and recreate release notes if a publish plugin cre
|
|||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
branch: 'master',
|
branch: 'master',
|
||||||
|
repositoryUrl: 'git@hostname.com:owner/module.git',
|
||||||
verifyConditions: stub().resolves(),
|
verifyConditions: stub().resolves(),
|
||||||
getLastRelease: stub().resolves(lastRelease),
|
getLastRelease: stub().resolves(lastRelease),
|
||||||
analyzeCommits: stub().resolves(nextRelease.type),
|
analyzeCommits: stub().resolves(nextRelease.type),
|
||||||
@ -147,7 +136,6 @@ test.serial('Use new gitHead, and recreate release notes if a publish plugin cre
|
|||||||
publish: [publish1, publish2],
|
publish: [publish1, publish2],
|
||||||
};
|
};
|
||||||
|
|
||||||
await writeJson('./package.json', {});
|
|
||||||
await t.context.semanticRelease(options);
|
await t.context.semanticRelease(options);
|
||||||
|
|
||||||
t.true(generateNotes.calledTwice);
|
t.true(generateNotes.calledTwice);
|
||||||
@ -172,7 +160,6 @@ test.serial('Dry-run skips verifyConditions and publish', async t => {
|
|||||||
// Add new commits to the master branch
|
// Add new commits to the master branch
|
||||||
commits = (await gitCommits(['Second'])).concat(commits);
|
commits = (await gitCommits(['Second'])).concat(commits);
|
||||||
|
|
||||||
const name = 'package-name';
|
|
||||||
const lastRelease = {version: '1.0.0', gitHead: commits[commits.length - 1].hash, gitTag: 'v1.0.0'};
|
const lastRelease = {version: '1.0.0', gitHead: commits[commits.length - 1].hash, gitTag: 'v1.0.0'};
|
||||||
const nextRelease = {type: 'major', version: '2.0.0', gitHead: await getGitHead(), gitTag: 'v2.0.0'};
|
const nextRelease = {type: 'major', version: '2.0.0', gitHead: await getGitHead(), gitTag: 'v2.0.0'};
|
||||||
const notes = 'Release notes';
|
const notes = 'Release notes';
|
||||||
@ -187,6 +174,7 @@ test.serial('Dry-run skips verifyConditions and publish', async t => {
|
|||||||
const options = {
|
const options = {
|
||||||
dryRun: true,
|
dryRun: true,
|
||||||
branch: 'master',
|
branch: 'master',
|
||||||
|
repositoryUrl: 'git@hostname.com:owner/module.git',
|
||||||
verifyConditions,
|
verifyConditions,
|
||||||
getLastRelease,
|
getLastRelease,
|
||||||
analyzeCommits,
|
analyzeCommits,
|
||||||
@ -194,10 +182,6 @@ test.serial('Dry-run skips verifyConditions and publish', async t => {
|
|||||||
generateNotes,
|
generateNotes,
|
||||||
publish,
|
publish,
|
||||||
};
|
};
|
||||||
const pkg = {name, version: '0.0.0-dev'};
|
|
||||||
normalizeData(pkg);
|
|
||||||
|
|
||||||
await writeJson('./package.json', pkg);
|
|
||||||
|
|
||||||
await t.context.semanticRelease(options);
|
await t.context.semanticRelease(options);
|
||||||
|
|
||||||
@ -208,3 +192,25 @@ test.serial('Dry-run skips verifyConditions and publish', async t => {
|
|||||||
t.true(generateNotes.calledOnce);
|
t.true(generateNotes.calledOnce);
|
||||||
t.true(publish.notCalled);
|
t.true(publish.notCalled);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
const error = await t.throws(t.context.semanticRelease());
|
||||||
|
|
||||||
|
// Verify error code and type
|
||||||
|
t.is(error.code, 'ENOGITREPO');
|
||||||
|
t.true(error instanceof SemanticReleaseError);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.serial('Throw SemanticReleaseError if repositoryUrl is not set and canot be found', async t => {
|
||||||
|
// Create a git repository, set the current working directory at the root of the repo
|
||||||
|
await gitRepo();
|
||||||
|
|
||||||
|
const error = await t.throws(t.context.semanticRelease());
|
||||||
|
|
||||||
|
// Verify error code and type
|
||||||
|
t.is(error.code, 'ENOREPOURL');
|
||||||
|
t.true(error instanceof SemanticReleaseError);
|
||||||
|
});
|
||||||
|
@ -7,7 +7,7 @@ import registry from './helpers/registry';
|
|||||||
import mockServer from './helpers/mockserver';
|
import mockServer from './helpers/mockserver';
|
||||||
import semanticRelease from '..';
|
import semanticRelease from '..';
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint camelcase: ["error", {properties: "never"}] */
|
||||||
|
|
||||||
// Environment variables used with cli
|
// Environment variables used with cli
|
||||||
const env = {
|
const env = {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user