chore: implement a publish script

- checks whether branch is `master`
- checks whether the tree is clean
- checks whether HEAD doesn't match origin
- publishes using lerna
- updates root version based on --staging/--dev/--production flags
- tags tapo with name `${pkg.name}@${pkg.version}`
- pushes tag to origin

that creates and pushes a repo tag afterwards
This commit is contained in:
Sérgio Ramos 2017-05-26 02:14:51 +01:00
parent 9b3874ea56
commit 65a104f7d4
3 changed files with 158 additions and 16 deletions

View File

@ -4,18 +4,5 @@
"npmClient": "yarn", "npmClient": "yarn",
"packages": [ "packages": [
"packages/*" "packages/*"
], ]
"commands": {
"publish": {
"ignore": [
"babel-preset-joyent-portal",
"joyent-portal-cloudapi-gql",
"docker-compose-client",
"eslint-config-joyent-portal",
"joyent-portal-gql-cp-schema",
"joyent-portal-rdb-bootstrap",
"joyent-portal-ui-toolkit"
]
}
}
} }

View File

@ -19,7 +19,7 @@
"updt:packages": "lerna exec ncu -au", "updt:packages": "lerna exec ncu -au",
"updt:teardown": "run-s clean bootstrap", "updt:teardown": "run-s clean bootstrap",
"updt": "run-s updt:*", "updt": "run-s updt:*",
"publish": "lerna publish --conventional-commits --independent -m 'chore: publish'", "publish": "./scripts/publish",
"clean": "lerna clean --yes", "clean": "lerna clean --yes",
"bootstrap": "lerna bootstrap", "bootstrap": "lerna bootstrap",
"prepare": "run-s clean bootstrap", "prepare": "run-s clean bootstrap",
@ -59,11 +59,13 @@
"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.uniq": "^4.5.0", "lodash.uniq": "^4.5.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",
"semver": "^5.3.0",
"staged-git-files": "0.0.4", "staged-git-files": "0.0.4",
"yargs": "^8.0.1" "yargs": "^8.0.1"
}, },
@ -74,4 +76,4 @@
"control-tower" "control-tower"
] ]
} }
} }

153
scripts/publish Executable file
View File

@ -0,0 +1,153 @@
#!/usr/bin/env node
const pkg = require('../package.json');
const { writeFile } = require('mz/fs');
const execa = require('execa');
const Listr = require('listr');
const argv = require('yargs').argv;
const semver = require('semver');
const path = require('path');
const incs = {
major: argv.production,
minor: argv.staging,
patch: argv.dev
};
const exec = (...args) => {
const cp = execa(...args);
cp.stdout.pipe(process.stdout);
cp.stderr.pipe(process.stderr);
return cp;
};
const errors = [
'Not on `master` branch. Use --any-branch to publish anyway.',
'Unclean working tree. Commit or stash changes first. Use --force to publish anyway.',
'Remote history differs. Please pull changes.',
'Use --staging/--dev/--production'
];
if (!argv.staging && !argv.dev && !argv.production) {
throw new Error(errors[3]);
}
// based on https://github.com/sindresorhus/np/blob/df8bb7153ecb05cd4674846f488d012f3cd252e1/lib/git.js
const tasks = new Listr(
[
{
title: 'Check',
task: () =>
new Listr([
{
title: 'Check current branch',
task: async () => {
const branch = await execa.stdout('git', [
'symbolic-ref',
'--short',
'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) {
throw new Error(errors[1]);
}
}
},
{
title: 'Check remote history',
task: async () => {
const history = await execa.stdout('git', [
'rev-list',
'--count',
'--left-only',
'@{u}...HEAD'
]);
if (history !== '0') {
throw new Error(errors[3]);
}
}
}
])
},
{
title: 'Publish',
task: () =>
exec('lerna', [
'updated', // '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(
path.join(__dirname, '../package.json'),
JSON.stringify(pkg, null, 2),
'utf-8'
);
}
},
{
title: 'Tag',
task: async () => {
const lastTag = await execa.stdout('git', [
'describe',
'--tags',
'--abbrev=0'
]);
const lastCommits = await execa.stdout('git', [
'log',
`${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}@${pkg.version}`,
'-m',
msg
]);
}
},
{
title: 'Push',
task: () => exec('git', ['push', 'origin', `${pkg.name}@${pkg.version}`])
}
],
{
renderer: 'verbose'
}
);
tasks.run().catch(() => process.exit(1));