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:
Pierre Vanduynslager
2017-11-24 21:56:15 -05:00
parent 5bec59b26b
commit 0c67ba517f
11 changed files with 292 additions and 110 deletions
+19 -11
View File
@@ -1,32 +1,40 @@
const marked = require('marked');
const TerminalRenderer = require('marked-terminal');
const SemanticReleaseError = require('@semantic-release/error');
const {gitHead: getGitHead} = require('./lib/git');
const getConfig = require('./lib/get-config');
const getNextVersion = require('./lib/get-next-version');
const getCommits = require('./lib/get-commits');
const logger = require('./lib/logger');
const {gitHead: getGitHead, isGitRepo} = require('./lib/git');
module.exports = async opts => {
const config = await getConfig(opts, logger);
const {plugins, env, options, pkg} = config;
if (!await isGitRepo()) {
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) {
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');
const {commits, lastRelease} = await getCommits(
await plugins.getLastRelease({env, options, pkg, logger}),
await plugins.getLastRelease({options, logger}),
options.branch,
logger
);
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) {
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}`};
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) {
logger.log('Call plugin %s', 'generate-notes');
@@ -49,7 +57,7 @@ module.exports = async opts => {
nextRelease.notes = await plugins.generateNotes(generateNotesParam);
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();
// If previous publish plugin has created a commit (gitHead changed)
if (prevInput.nextRelease.gitHead !== newGitHead) {
@@ -59,7 +67,7 @@ module.exports = async opts => {
nextRelease.notes = await plugins.generateNotes(generateNotesParam);
}
// 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);
}