semantic-release-github-notifier
Version:
semantic-release-github plugin that notifies GitHub issues and pull requests of a related package release.
96 lines (81 loc) • 3.44 kB
JavaScript
;
const _ = require(`lodash`);
const Bluebird = require(`bluebird`);
const debug = require(`debug`)(`semantic-release-github-notifier`);
const getPkgRepo = require(`get-pkg-repo`);
const ghGot = require(`gh-got`);
const parser = require(`conventional-commits-parser`);
const semver = require(`semver`);
const streamify = require(`stream-array`);
const through = require(`through2`);
module.exports = notifier;
function notifier(config) {
return new Bluebird((resolve, reject) => {
if (!_.has(config, `pkg`)) {
return reject(new Error('This plugin, `semantic-release-github-notifier`, was not ' +
'passed the contents of your package\'s `package.json` file. Please contact the user of ' +
'this plugin and request that they pass the contents of `package.json` to the plugin.'));
}
let repoUrl;
try {
repoUrl = getPkgRepo(config.pkg);
debug(`parsed repository URL using the 'get-pkg-repo' package - %O`, repoUrl);
} catch (err) {
return reject(err);
}
if (typeof config.options.scmToken !== `string` || config.options.scmToken.length === 0) {
debug(`no SCM token provided for GitHub`);
return reject(new Error(`No SCM token provided for GitHub.`));
}
let semverVersion = config.data.version;
if (config.options.monoRepo) {
// Default to Lerna standard of using `@` if no tagSplitter provided
const tagSplitter = config.options.tagSplitter || '@';
semverVersion = _.get(config, 'data.version', `${tagSplitter}`).split(tagSplitter)[1];
}
if (semver.valid(semverVersion) === null) {
debug(`invalid version provided to 'semantic-release-github-notifier'`);
return reject(new Error(`Invalid version provided to 'semantic-release-github-notifier'.`));
}
const url = `${config.options.insecureApi ? `http` : `https`}://${repoUrl.domain}`;
const endpoint = `${config.options.insecureApi ? `http` : `https`}://api.${repoUrl.domain}/`;
debug(`url - ${url}`);
debug(`endpoint - ${endpoint}`);
// Placed after all other code so that sanity checking has had a chance to run.
if (config.options.dryRun) {
return resolve(false);
}
const issueIds = new Set();
streamify(config.data.commits)
.pipe(parser())
.pipe(through.obj((commit, enc, cb) => {
_.forEach(_.map(commit.references, `issue`), issueIds.add.bind(issueIds));
cb();
}))
.on(`finish`, () => {
const commentPromises = generateIssueComments(
endpoint,
url,
config.options.scmToken,
config.data.version,
`${repoUrl.user}/${repoUrl.project}`,
issueIds
);
Bluebird.all(commentPromises)
.then(_.ary(_.partial(resolve, true)))
.catch(() => reject(new Error(`Failed to post comment(s) to GitHub.`)));
});
});
}
// eslint-disable-next-line max-params
function generateIssueComments(endpoint, url, token, version, projectID, issueIds) {
debug(`posting notifications to the following issues - %o`, Array.from(issueIds));
return _.map(Array.from(issueIds), function (id) {
debug(`posting notification to issue ${id}`);
return ghGot.post(`repos/${projectID}/issues/${id}/comments`, {
body: {
body: `Version [${version}](${url}/${projectID}/releases/tag/${version}) has been released.`,
}, endpoint, token,
});
});
}