mirror of
https://github.com/yldio/copilot.git
synced 2024-11-30 23:20:06 +02:00
chore: improved publish script
- goes through the stages step by step - prompts the user to confirm some choices - smarter handling of tags and versions
This commit is contained in:
parent
b96e4321d4
commit
0dbd8a6b84
12
package.json
12
package.json
@ -35,9 +35,13 @@
|
|||||||
"apr-awaitify": "^1.0.4",
|
"apr-awaitify": "^1.0.4",
|
||||||
"apr-filter": "^1.0.5",
|
"apr-filter": "^1.0.5",
|
||||||
"apr-for-each": "^1.0.6",
|
"apr-for-each": "^1.0.6",
|
||||||
|
"apr-intercept": "^1.0.4",
|
||||||
"apr-main": "^1.0.7",
|
"apr-main": "^1.0.7",
|
||||||
"apr-map": "^1.0.5",
|
"apr-map": "^1.0.5",
|
||||||
|
"apr-reduce": "^1.0.5",
|
||||||
|
"apr-sort-by": "^1.0.5",
|
||||||
"babel-eslint": "^7.2.3",
|
"babel-eslint": "^7.2.3",
|
||||||
|
"chalk": "^1.1.3",
|
||||||
"conventional-changelog-angular": "^1.3.3",
|
"conventional-changelog-angular": "^1.3.3",
|
||||||
"conventional-changelog-cli": "^1.3.1",
|
"conventional-changelog-cli": "^1.3.1",
|
||||||
"conventional-changelog-lint": "^1.1.9",
|
"conventional-changelog-lint": "^1.1.9",
|
||||||
@ -54,17 +58,21 @@
|
|||||||
"eslint-plugin-react": "^7.0.1",
|
"eslint-plugin-react": "^7.0.1",
|
||||||
"eslint-tap": "^2.0.1",
|
"eslint-tap": "^2.0.1",
|
||||||
"execa": "^0.6.3",
|
"execa": "^0.6.3",
|
||||||
|
"figures": "^2.0.0",
|
||||||
"force-array": "^3.1.0",
|
"force-array": "^3.1.0",
|
||||||
"husky": "^0.13.3",
|
"husky": "^0.13.3",
|
||||||
|
"inquirer": "^3.0.6",
|
||||||
"lerna": "^2.0.0-rc.5",
|
"lerna": "^2.0.0-rc.5",
|
||||||
"lerna-wizard": "ramitos/lerna-wizard#7bcdc11",
|
"lerna-wizard": "ramitos/lerna-wizard#7bcdc11",
|
||||||
"license-to-fail": "^2.2.0",
|
"license-to-fail": "^2.2.0",
|
||||||
"listr": "^0.12.0",
|
"lodash.isplainobject": "^4.0.6",
|
||||||
"lodash.uniq": "^4.5.0",
|
"lodash.isstring": "^4.0.1",
|
||||||
|
"lodash.uniqby": "^4.7.0",
|
||||||
"npm-check-updates": "^2.11.2",
|
"npm-check-updates": "^2.11.2",
|
||||||
"npm-run-all": "^4.0.2",
|
"npm-run-all": "^4.0.2",
|
||||||
"prettier": "1.3.1",
|
"prettier": "1.3.1",
|
||||||
"quality-docs": "^3.3.0",
|
"quality-docs": "^3.3.0",
|
||||||
|
"read-pkg": "^2.0.0",
|
||||||
"semver": "^5.3.0",
|
"semver": "^5.3.0",
|
||||||
"staged-git-files": "0.0.4",
|
"staged-git-files": "0.0.4",
|
||||||
"yargs": "^8.0.1"
|
"yargs": "^8.0.1"
|
||||||
|
567
scripts/publish
567
scripts/publish
@ -1,159 +1,474 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
const { EOL } = require('os');
|
const { EOL } = require('os');
|
||||||
|
const inquirer = require('inquirer');
|
||||||
|
const isString = require('lodash.isstring');
|
||||||
|
const isPlainObject = require('lodash.isplainobject');
|
||||||
|
const uniqBy = require('lodash.uniqby');
|
||||||
|
const sortBy = require('apr-sort-by');
|
||||||
|
const map = require('apr-map');
|
||||||
const pkg = require('../package.json');
|
const pkg = require('../package.json');
|
||||||
const { writeFile } = require('mz/fs');
|
const { writeFile } = require('mz/fs');
|
||||||
|
const readPkg = require('read-pkg');
|
||||||
|
const reduce = require('apr-reduce');
|
||||||
|
const intercept = require('apr-intercept');
|
||||||
const execa = require('execa');
|
const execa = require('execa');
|
||||||
const Listr = require('listr');
|
|
||||||
const argv = require('yargs').argv;
|
const argv = require('yargs').argv;
|
||||||
const semver = require('semver');
|
const semver = require('semver');
|
||||||
|
const globby = require('globby');
|
||||||
|
const figures = require('figures');
|
||||||
|
const chalk = require('chalk');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
|
const ROOT = path.join(__dirname, '..');
|
||||||
|
|
||||||
|
const exec = (...args) =>
|
||||||
|
execa(...args, {
|
||||||
|
stdio: 'inherit'
|
||||||
|
});
|
||||||
|
|
||||||
|
const releaseTypes = {
|
||||||
|
dev: 'dev',
|
||||||
|
staging: 'staging',
|
||||||
|
production: 'production'
|
||||||
|
};
|
||||||
|
|
||||||
const incs = {
|
const incs = {
|
||||||
major: argv.production,
|
production: 'major',
|
||||||
minor: argv.staging,
|
staging: 'minor',
|
||||||
patch: argv.dev
|
dev: 'patch'
|
||||||
};
|
};
|
||||||
|
|
||||||
const type = ['production', 'staging', 'dev']
|
const tasks = [
|
||||||
.filter(k => argv[k])
|
{
|
||||||
.reduce((t, name) => name, '');
|
title: 'Git Check',
|
||||||
|
description: 'Checks whether the current git state is ideal for a publish',
|
||||||
|
task: [
|
||||||
|
{
|
||||||
|
title: 'Branch',
|
||||||
|
description: 'Checks if the current branch is `master`. To ignore use the `--any-branch` flag',
|
||||||
|
filter: () => !argv['any-branch'],
|
||||||
|
task: async () => {
|
||||||
|
const branch = await execa.stdout('git', [
|
||||||
|
'symbolic-ref',
|
||||||
|
'--short',
|
||||||
|
'HEAD'
|
||||||
|
]);
|
||||||
|
|
||||||
const exec = (...args) => {
|
if (branch !== 'master') {
|
||||||
const cp = execa(...args);
|
throw new Error(
|
||||||
|
'Not on `master` branch. Use --any-branch to publish anyway'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Working tree',
|
||||||
|
description: 'Checks if working tree is clean. To ignore use the `--force` flag',
|
||||||
|
filter: () => !argv.force,
|
||||||
|
task: async () => {
|
||||||
|
const status = await execa.stdout('git', ['status', '--porcelain']);
|
||||||
|
|
||||||
cp.stdout.pipe(process.stdout);
|
if (status !== '') {
|
||||||
cp.stderr.pipe(process.stderr);
|
throw new Error(
|
||||||
|
'Unclean working tree. Commit or stash changes first. Use --force to publish anyway'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Remote history',
|
||||||
|
description: 'Checks if remote history differs',
|
||||||
|
task: async () => {
|
||||||
|
const history = await execa.stdout('git', [
|
||||||
|
'rev-list',
|
||||||
|
'--count',
|
||||||
|
'--left-only',
|
||||||
|
'@{u}...HEAD'
|
||||||
|
]);
|
||||||
|
|
||||||
return cp;
|
if (history !== '0') {
|
||||||
};
|
throw new Error('Remote history differs. Please pull changes');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Lerna',
|
||||||
|
task: [
|
||||||
|
{
|
||||||
|
title: 'Updated',
|
||||||
|
description: 'Shows a list of updated packages',
|
||||||
|
task: () =>
|
||||||
|
exec('lerna', ['updated', '--conventional-commits', '--independent'])
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Publish',
|
||||||
|
description: 'Publish updated packages, based on the changes from last tag',
|
||||||
|
task: async ({ prefix }) => {
|
||||||
|
const { publish } = await inquirer.prompt([
|
||||||
|
{
|
||||||
|
name: 'publish',
|
||||||
|
type: 'confirm',
|
||||||
|
message: `${prefix}Want to publish packages?`
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
const errors = [
|
if (!publish) {
|
||||||
'Not on `master` branch. Use --any-branch to publish anyway.',
|
return {
|
||||||
'Unclean working tree. Commit or stash changes first. Use --force to publish anyway.',
|
published: false
|
||||||
'Remote history differs. Please pull changes.',
|
};
|
||||||
'Use --staging/--dev/--production'
|
}
|
||||||
];
|
|
||||||
|
|
||||||
if (!argv.staging && !argv.dev && !argv.production) {
|
const msg = 'chore: publish packages';
|
||||||
throw new Error(errors[3]);
|
const prevCommit = await execa.stdout('git', [
|
||||||
}
|
'log',
|
||||||
|
'-1',
|
||||||
|
"--format='%h'"
|
||||||
|
]);
|
||||||
|
|
||||||
// based on https://github.com/sindresorhus/np/blob/df8bb7153ecb05cd4674846f488d012f3cd252e1/lib/git.js
|
const [err] = await intercept(
|
||||||
const tasks = new Listr(
|
exec('lerna', [
|
||||||
[
|
'publish',
|
||||||
{
|
'--conventional-commits',
|
||||||
title: 'Check',
|
'--independent',
|
||||||
task: () =>
|
'-m',
|
||||||
new Listr([
|
`"${msg}"`
|
||||||
{
|
])
|
||||||
title: 'Check current branch',
|
);
|
||||||
task: async () => {
|
|
||||||
const branch = await execa.stdout('git', [
|
// check if user denied publish
|
||||||
'symbolic-ref',
|
if (/^Command\sfailed:/.test(err.message)) {
|
||||||
'--short',
|
return {
|
||||||
|
published: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if last commit is the publish
|
||||||
|
const lastCommit = await execa.stdout('git', [
|
||||||
|
'log',
|
||||||
|
'-1',
|
||||||
|
"--format=\"title:'%s' hash:'%h'\""
|
||||||
|
]);
|
||||||
|
|
||||||
|
const [_, title, hash] = lastCommit.match(
|
||||||
|
/title:'(.*?) hash:'(.*?)'/
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
published: title === msg && hash !== prevCommit
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Release',
|
||||||
|
description: 'Cut a release for Continuous Delivery',
|
||||||
|
task: [
|
||||||
|
{
|
||||||
|
filter: ({ published }) => !published,
|
||||||
|
task: async ({ published, prefix }) =>
|
||||||
|
inquirer.prompt([
|
||||||
|
{
|
||||||
|
name: 'release',
|
||||||
|
type: 'confirm',
|
||||||
|
default: false,
|
||||||
|
message: `${prefix}No lerna publish detected. Are you sure you want to release? \n ${prefix}${chalk.dim(`(${chalk.yellow(figures.warning)} this can have negative effects on future lerna publishes since it detects changes based on tags)`)}`
|
||||||
|
}
|
||||||
|
])
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Type',
|
||||||
|
filter: ({ release }) => release,
|
||||||
|
task: async ({ prefix }) =>
|
||||||
|
inquirer.prompt([
|
||||||
|
{
|
||||||
|
name: 'releaseType',
|
||||||
|
type: 'list',
|
||||||
|
message: `${prefix}What type of release?`,
|
||||||
|
choices: Object.keys(releaseTypes),
|
||||||
|
default: 'dev'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Version bump',
|
||||||
|
description: 'Bum version based on release type',
|
||||||
|
filter: ({ release }) => release,
|
||||||
|
task: async ({ releaseType }) => {
|
||||||
|
const version = Object.keys(incs)
|
||||||
|
.filter(k => releaseType === k)
|
||||||
|
.reduce((v, k) => semver.inc(v, incs[k]), pkg.version);
|
||||||
|
|
||||||
|
return {
|
||||||
|
version: String(version)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Tag',
|
||||||
|
description: 'Create new tag for release',
|
||||||
|
filter: ({ release }) => release,
|
||||||
|
task: async ({ version, releaseType, prefix }) => {
|
||||||
|
// from a tag hash, get the timestamp
|
||||||
|
const tagTimestamp = async ({ hash }) => {
|
||||||
|
if (!hash) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const show = await execa.stdout('git', [
|
||||||
|
'show',
|
||||||
|
'-s',
|
||||||
|
'--format=%ct',
|
||||||
|
hash
|
||||||
|
]);
|
||||||
|
|
||||||
|
return -Number(show.split(/\n/).pop());
|
||||||
|
};
|
||||||
|
|
||||||
|
// from a string of tags, get the name, hash, version and pkg
|
||||||
|
const parseTags = str =>
|
||||||
|
str.split(/\n/).map(line => {
|
||||||
|
const meta = line.match(/(.*?)\s*?refs\/tags\/(.*?)@(.*)/);
|
||||||
|
const hashname = line.match(/(.*?)\s*?refs\/tags\/(.*)/);
|
||||||
|
|
||||||
|
const [_, __, pkg, version] = meta || [];
|
||||||
|
const [___, hash, name] = hashname || [];
|
||||||
|
|
||||||
|
return {
|
||||||
|
hash,
|
||||||
|
name: (name || '').replace('^{}', ''),
|
||||||
|
pkg,
|
||||||
|
version: (version || '').replace('^{}', '')
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// get a tag parent tag
|
||||||
|
// this is needed to build a summary of changes
|
||||||
|
const getLastTag = async () => {
|
||||||
|
// get all remote tags
|
||||||
|
const remoteTags = await execa.stdout('git', [
|
||||||
|
'ls-remote',
|
||||||
|
'--tags'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// get all local tags
|
||||||
|
const localTags = await execa.stdout('git', [
|
||||||
|
'show-ref',
|
||||||
|
'--tags',
|
||||||
|
'-d'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// gather all tags, remote and local
|
||||||
|
const allTags = parseTags(remoteTags)
|
||||||
|
.concat(parseTags(localTags))
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
// from all tags, filter duplicates
|
||||||
|
const uniqueTags = uniqBy(allTags, ({ name }) => name);
|
||||||
|
// sort tags by timestamp, most recent to oldest
|
||||||
|
const tags = await sortBy(uniqueTags, tagTimestamp);
|
||||||
|
|
||||||
|
// check whether any of the tags matches the name
|
||||||
|
const type = releaseTypes[releaseType];
|
||||||
|
const projTags = tags.filter(
|
||||||
|
({ name }) => name.indexOf(`${pkg.name}-${type}`) >= 0
|
||||||
|
);
|
||||||
|
|
||||||
|
// if tags found, get the most recent
|
||||||
|
if (projTags.length) {
|
||||||
|
return projTags.shift().name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get all package folders
|
||||||
|
const pkgFolders = (await globby(['packages/*'], {
|
||||||
|
cwd: path.join(__dirname, '..')
|
||||||
|
})).map(folder => path.resolve(ROOT, folder));
|
||||||
|
|
||||||
|
// get package names
|
||||||
|
const pkgs = await map(
|
||||||
|
pkgFolders,
|
||||||
|
async folder => (await readPkg(folder)).name
|
||||||
|
);
|
||||||
|
|
||||||
|
// filter tags that are scoped to packages
|
||||||
|
const nonLernaTags = tags.filter(
|
||||||
|
tag => !pkgs.some(pkg => tag.pkg === pkg)
|
||||||
|
);
|
||||||
|
|
||||||
|
// if no remaining tag, get first repo commit
|
||||||
|
if (!nonLernaTags.length) {
|
||||||
|
return execa.stdout('git', [
|
||||||
|
'rev-list',
|
||||||
|
'--max-parents=0',
|
||||||
'HEAD'
|
'HEAD'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (branch !== 'master' && !argv['any-branch']) {
|
|
||||||
throw new Error(errors[0]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Check local working tree',
|
|
||||||
task: async () => {
|
|
||||||
const status = await execa.stdout('git', [
|
|
||||||
'status',
|
|
||||||
'--porcelain'
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (status !== '' && !argv.force) {
|
// from the remaining tags, pick one
|
||||||
throw new Error(errors[1]);
|
const { tag } = await inquirer.prompt([
|
||||||
|
{
|
||||||
|
name: 'tag',
|
||||||
|
type: 'list',
|
||||||
|
message: `${prefix}What tag to base your release on?`,
|
||||||
|
choices: nonLernaTags.map(({ name }) => name),
|
||||||
|
pageSize: nonLernaTags.length
|
||||||
}
|
}
|
||||||
}
|
]);
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Check remote history',
|
|
||||||
task: async () => {
|
|
||||||
const history = await execa.stdout('git', [
|
|
||||||
'rev-list',
|
|
||||||
'--count',
|
|
||||||
'--left-only',
|
|
||||||
'@{u}...HEAD'
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (history !== '0') {
|
return tag;
|
||||||
throw new Error(errors[3]);
|
};
|
||||||
}
|
|
||||||
|
const lastTag = await getLastTag();
|
||||||
|
const lastCommits = await execa.stdout('git', [
|
||||||
|
'log',
|
||||||
|
`${lastTag}..HEAD`,
|
||||||
|
'--no-merges',
|
||||||
|
'--format="%h %s (%aN)"'
|
||||||
|
]);
|
||||||
|
|
||||||
|
const tagName = `${pkg.name}-${releaseType}@${version}`;
|
||||||
|
const tagBody = `${EOL}${lastCommits}`;
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(
|
||||||
|
`${prefix}${chalk.yellow('Tag Name: ')}\n${prefix}${prefix}${chalk.dim(tagName)}`
|
||||||
|
);
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(`${prefix}${chalk.yellow('Tag Description: ')}`);
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(
|
||||||
|
`${chalk.dim(lastCommits
|
||||||
|
.split(/\n/)
|
||||||
|
.map(line => `${prefix}${prefix}${line}`)
|
||||||
|
.join('\n'))}`
|
||||||
|
);
|
||||||
|
|
||||||
|
const { createTag } = await inquirer.prompt([
|
||||||
|
{
|
||||||
|
name: 'createTag',
|
||||||
|
type: 'confirm',
|
||||||
|
message: `${prefix}Should above tag be created?`
|
||||||
}
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!createTag) {
|
||||||
|
return {
|
||||||
|
createTag
|
||||||
|
};
|
||||||
}
|
}
|
||||||
])
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Publish',
|
|
||||||
task: () =>
|
|
||||||
exec('lerna', [
|
|
||||||
'publish',
|
|
||||||
'--conventional-commits',
|
|
||||||
'--independent',
|
|
||||||
'-m',
|
|
||||||
'chore: publish'
|
|
||||||
])
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Version',
|
|
||||||
task: async () => {
|
|
||||||
pkg.version = Object.keys(incs)
|
|
||||||
.filter(k => incs[k])
|
|
||||||
.reduce((v, release) => semver.inc(v, release), pkg.version);
|
|
||||||
|
|
||||||
await writeFile(
|
await exec('git', ['tag', tagName, '-m', tagBody]);
|
||||||
path.join(__dirname, '../package.json'),
|
|
||||||
JSON.stringify(pkg, null, 2),
|
return {
|
||||||
'utf-8'
|
tagName,
|
||||||
|
tagBody,
|
||||||
|
lastCommits,
|
||||||
|
createTag
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Push',
|
||||||
|
description: 'Push just created tag to origin',
|
||||||
|
filter: ({ createTag }) => createTag,
|
||||||
|
task: async ({ tagName, prefix }) => {
|
||||||
|
const { pushTag } = await inquirer.prompt([
|
||||||
|
{
|
||||||
|
name: 'pushTag',
|
||||||
|
type: 'confirm',
|
||||||
|
message: `${prefix}Should ${chalk.yellow(tagName)} be pushed to origin?`
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!pushTag) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return exec('git', ['push', 'origin', tagName]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Version write',
|
||||||
|
filter: ({ createTag }) => createTag,
|
||||||
|
description: 'Write new version to `package.json`',
|
||||||
|
task: ({ version }) => {
|
||||||
|
pkg.version = version;
|
||||||
|
|
||||||
|
return writeFile(
|
||||||
|
path.join(__dirname, '../package.json'),
|
||||||
|
JSON.stringify(pkg, null, 2),
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const run = (tasks = [], ctx = {}, prefix = '') =>
|
||||||
|
reduce(
|
||||||
|
tasks,
|
||||||
|
async (ctx = {}, { title, description, filter, task }) => {
|
||||||
|
if (!task) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const context = Object.assign({}, ctx, {
|
||||||
|
prefix
|
||||||
|
});
|
||||||
|
|
||||||
|
const shouldRun = filter ? await filter(context) : true;
|
||||||
|
|
||||||
|
if (!shouldRun) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isString(title)) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(`${prefix}${chalk.green(figures.arrowRight)} ${title}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isString(description)) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(
|
||||||
|
`${chalk.dim(`${prefix}${figures.arrowRight} ${description}`)}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Tag',
|
|
||||||
task: async () => {
|
|
||||||
const lastTag = await execa.stdout('git', [
|
|
||||||
'describe',
|
|
||||||
'--tags',
|
|
||||||
'--abbrev=0'
|
|
||||||
]);
|
|
||||||
|
|
||||||
const lastCommits = await execa.stdout('git', [
|
if (Array.isArray(task)) {
|
||||||
'log',
|
return run(task, context, `${prefix} `);
|
||||||
`${lastTag}..HEAD`,
|
|
||||||
'--no-merges',
|
|
||||||
'--format="%h %s (%aN)"'
|
|
||||||
]);
|
|
||||||
|
|
||||||
const msg = lastCommits
|
|
||||||
.split(/\n/)
|
|
||||||
.map(commit => commit.replace(/^"/, '').replace(/"$/, ''))
|
|
||||||
.join('\n');
|
|
||||||
|
|
||||||
return exec('git', [
|
|
||||||
'tag',
|
|
||||||
'-a',
|
|
||||||
`${pkg.name}-${type}@${pkg.version}`,
|
|
||||||
'-m',
|
|
||||||
`${EOL}${pkg.name}@${pkg.version}${EOL}${msg}`
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Push',
|
|
||||||
task: () =>
|
|
||||||
exec('git', ['push', 'origin', `${pkg.name}-${type}@${pkg.version}`])
|
|
||||||
}
|
|
||||||
],
|
|
||||||
{
|
|
||||||
renderer: 'verbose'
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
tasks.run().catch(() => process.exit(1));
|
const [err, nCtx] = await intercept(task(context));
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(`${chalk.red(figures.cross)} ${chalk.dim(err.message)}`);
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(
|
||||||
|
`${chalk.dim(err.stack.replace(`Error: ${err.message}`, '').trim())}`
|
||||||
|
);
|
||||||
|
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.assign({}, context, isPlainObject(nCtx) ? nCtx : {});
|
||||||
|
},
|
||||||
|
ctx
|
||||||
|
);
|
||||||
|
|
||||||
|
const exit = err => {
|
||||||
|
process.exit(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
process.on('SIGTERM', exit);
|
||||||
|
process.on('SIGINT', exit);
|
||||||
|
process.on('SIGHUP', exit);
|
||||||
|
|
||||||
|
run(tasks).catch(exit);
|
||||||
|
Loading…
Reference in New Issue
Block a user