feat: pass cwd and env context to plugins

- Allow to run semantic-release (via API) from anywhere passing the current working directory.
- Allows to simplify the tests and to run them in parallel in both the core and plugins.
This commit is contained in:
Pierre Vanduynslager
2018-07-17 00:42:04 -04:00
parent 12e4155cd3
commit a94e08de9a
32 changed files with 1361 additions and 1332 deletions
+53 -25
View File
@@ -5,23 +5,28 @@ const debug = require('debug')('semantic-release:git');
* Get the commit sha for a given tag.
*
* @param {string} tagName Tag name for which to retrieve the commit sha.
* @param {Object} [execaOpts] Options to pass to `execa`.
*
* @return {string} The commit sha of the tag in parameter or `null`.
*/
async function gitTagHead(tagName) {
async function gitTagHead(tagName, execaOpts) {
try {
return await execa.stdout('git', ['rev-list', '-1', tagName]);
return await execa.stdout('git', ['rev-list', '-1', tagName], execaOpts);
} catch (err) {
debug(err);
}
}
/**
* Get all the repository tags.
*
* @param {Object} [execaOpts] Options to pass to `execa`.
*
* @return {Array<String>} List of git tags.
* @throws {Error} If the `git` command fails.
*/
async function gitTags() {
return (await execa.stdout('git', ['tag']))
async function gitTags(execaOpts) {
return (await execa.stdout('git', ['tag'], execaOpts))
.split('\n')
.map(tag => tag.trim())
.filter(tag => Boolean(tag));
@@ -31,12 +36,13 @@ async function gitTags() {
* Verify if the `ref` is in the direct history of the current branch.
*
* @param {string} ref The reference to look for.
* @param {Object} [execaOpts] Options to pass to `execa`.
*
* @return {boolean} `true` if the reference is in the history of the current branch, falsy otherwise.
*/
async function isRefInHistory(ref) {
async function isRefInHistory(ref, execaOpts) {
try {
await execa('git', ['merge-base', '--is-ancestor', ref, 'HEAD']);
await execa('git', ['merge-base', '--is-ancestor', ref, 'HEAD'], execaOpts);
return true;
} catch (err) {
if (err.code === 1) {
@@ -52,39 +58,52 @@ async function isRefInHistory(ref) {
* Unshallow the git repository if necessary and fetch all the tags.
*
* @param {String} repositoryUrl The remote repository URL.
* @param {Object} [execaOpts] Options to pass to `execa`.
*/
async function fetch(repositoryUrl) {
async function fetch(repositoryUrl, execaOpts) {
try {
await execa('git', ['fetch', '--unshallow', '--tags', repositoryUrl]);
await execa('git', ['fetch', '--unshallow', '--tags', repositoryUrl], execaOpts);
} catch (err) {
await execa('git', ['fetch', '--tags', repositoryUrl]);
await execa('git', ['fetch', '--tags', repositoryUrl], execaOpts);
}
}
/**
* Get the HEAD sha.
*
* @param {Object} [execaOpts] Options to pass to `execa`.
*
* @return {string} the sha of the HEAD commit.
*/
async function gitHead() {
return execa.stdout('git', ['rev-parse', 'HEAD']);
async function gitHead(execaOpts) {
return execa.stdout('git', ['rev-parse', 'HEAD'], execaOpts);
}
/**
* Get the repository remote URL.
*
* @param {Object} [execaOpts] Options to pass to `execa`.
*
* @return {string} The value of the remote git URL.
*/
async function repoUrl() {
async function repoUrl(execaOpts) {
try {
return await execa.stdout('git', ['config', '--get', 'remote.origin.url']);
return await execa.stdout('git', ['config', '--get', 'remote.origin.url'], execaOpts);
} catch (err) {
debug(err);
}
}
/**
* Test if the current working directory is a Git repository.
*
* @param {Object} [execaOpts] Options to pass to `execa`.
*
* @return {Boolean} `true` if the current working directory is in a git repository, falsy otherwise.
*/
async function isGitRepo() {
async function isGitRepo(execaOpts) {
try {
return (await execa('git', ['rev-parse', '--git-dir'])).code === 0;
return (await execa('git', ['rev-parse', '--git-dir'], execaOpts)).code === 0;
} catch (err) {
debug(err);
}
@@ -95,12 +114,13 @@ async function isGitRepo() {
*
* @param {String} repositoryUrl The remote repository URL.
* @param {String} branch The repositoru branch for which to verify write access.
* @param {Object} [execaOpts] Options to pass to `execa`.
*
* @throws {Error} if not authorized to push.
*/
async function verifyAuth(repositoryUrl, branch) {
async function verifyAuth(repositoryUrl, branch, execaOpts) {
try {
await execa('git', ['push', '--dry-run', repositoryUrl, `HEAD:${branch}`]);
await execa('git', ['push', '--dry-run', repositoryUrl, `HEAD:${branch}`], execaOpts);
} catch (err) {
debug(err);
throw err;
@@ -111,10 +131,12 @@ async function verifyAuth(repositoryUrl, branch) {
* Tag the commit head on the local repository.
*
* @param {String} tagName The name of the tag.
* @param {Object} [execaOpts] Options to pass to `execa`.
*
* @throws {Error} if the tag creation failed.
*/
async function tag(tagName) {
await execa('git', ['tag', tagName]);
async function tag(tagName, execaOpts) {
await execa('git', ['tag', tagName], execaOpts);
}
/**
@@ -122,21 +144,25 @@ async function tag(tagName) {
*
* @param {String} repositoryUrl The remote repository URL.
* @param {String} branch The branch to push.
* @param {Object} [execaOpts] Options to pass to `execa`.
*
* @throws {Error} if the push failed.
*/
async function push(repositoryUrl, branch) {
await execa('git', ['push', '--tags', repositoryUrl, `HEAD:${branch}`]);
async function push(repositoryUrl, branch, execaOpts) {
await execa('git', ['push', '--tags', repositoryUrl, `HEAD:${branch}`], execaOpts);
}
/**
* Verify a tag name is a valid Git reference.
*
* @param {string} tagName the tag name to verify.
* @param {Object} [execaOpts] Options to pass to `execa`.
*
* @return {boolean} `true` if valid, falsy otherwise.
*/
async function verifyTagName(tagName) {
async function verifyTagName(tagName, execaOpts) {
try {
return (await execa('git', ['check-ref-format', `refs/tags/${tagName}`])).code === 0;
return (await execa('git', ['check-ref-format', `refs/tags/${tagName}`], execaOpts)).code === 0;
} catch (err) {
debug(err);
}
@@ -146,13 +172,15 @@ async function verifyTagName(tagName) {
* Verify the local branch is up to date with the remote one.
*
* @param {String} branch The repository branch for which to verify status.
* @param {Object} [execaOpts] Options to pass to `execa`.
*
* @return {Boolean} `true` is the HEAD of the current local branch is the same as the HEAD of the remote branch, falsy otherwise.
*/
async function isBranchUpToDate(branch) {
async function isBranchUpToDate(branch, execaOpts) {
try {
return await isRefInHistory(
(await execa.stdout('git', ['ls-remote', '--heads', 'origin', branch])).match(/^(\w+)?/)[1]
(await execa.stdout('git', ['ls-remote', '--heads', 'origin', branch], execaOpts)).match(/^(\w+)?/)[1],
execaOpts
);
} catch (err) {
debug(err);