Skip to content

Commit

Permalink
add animated task list output (#42)
Browse files Browse the repository at this point in the history
fixes #30
  • Loading branch information
SamVerschueren authored and sindresorhus committed Jul 6, 2016
1 parent 021ebb1 commit e578a95
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 55 deletions.
15 changes: 8 additions & 7 deletions cli.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#!/usr/bin/env node
'use strict';
const meow = require('meow');
const logSymbols = require('log-symbols');
const updateNotifier = require('update-notifier');
const np = require('./');

Expand All @@ -22,9 +21,11 @@ const cli = meow(`

updateNotifier({pkg: cli.pkg}).notify();

try {
np(cli.input[0], cli.flags);
} catch (err) {
console.error(` ${logSymbols.error} ${err.message}`);
process.exit(1);
}
np(cli.input[0], cli.flags)
.then(pkg => {
console.log(`\n ${pkg.name} ${pkg.version} published`);
})
.catch(err => {
console.error(`\n${err.message}`);
process.exit(1);
});
133 changes: 91 additions & 42 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,65 @@
'use strict';
const fs = require('fs');
const semver = require('semver');
const execa = require('execa');
const del = require('del');
const chalk = require('chalk');

const pify = require('pify');
const Listr = require('listr');
const split = require('split');
require('any-observable/register/rxjs-all');
const Observable = require('any-observable');
const streamToObservable = require('stream-to-observable');

const fsP = pify(fs);
const VERSIONS = ['major', 'minor', 'patch', 'premajor', 'preminor', 'prepatch', 'prerelease'];

const log = str => console.log(chalk.bold(`\n${chalk.cyan('›')} ${str}\n`));

const exec = (cmd, args) => {
// TODO Switch to `{stdio: 'inherit'}` instead of manual logging when a new execa version is released
const result = execa.sync(cmd, args);
// Use `Observable` support if merged https://github.com/sindresorhus/execa/pull/26
const cp = execa(cmd, args);

if (result.stdout) {
console.log(result.stdout);
}
return Observable.merge(
streamToObservable(cp.stdout.pipe(split()), {await: cp}),
streamToObservable(cp.stderr.pipe(split()), {await: cp})
).filter(Boolean);
};

if (result.stderr) {
console.error(result.stderr);
const gitTasks = opts => {
const tasks = [
{
title: 'Check current branch',
task: () => execa.stdout('git', ['symbolic-ref', '--short', 'HEAD']).then(branch => {
if (branch !== 'master') {
throw new Error('Not on `master` branch. Use --any-branch to publish anyway.');
}
})
},
{
title: 'Check local working tree',
task: () => execa.stdout('git', ['status', '--porcelain']).then(status => {
if (status !== '') {
throw new Error('Unclean working tree. Commit or stash changes first.');
}
})
},
{
title: 'Fetch remote changes',
task: () => execa('git', ['fetch'])
},
{
title: 'Check remote history',
task: () => execa.stdout('git', ['rev-list', '--count', '--left-only', '@{u}...HEAD']).then(result => {
if (result !== '0') {
throw new Error('Remote history differ. Please pull changes.');
}
})
}
];

if (opts.anyBranch) {
tasks.shift();
}

if (result.status !== 0) {
throw new Error(`Exited with status ${result.status}.`);
}
return new Listr(tasks);
};

module.exports = (input, opts) => {
Expand All @@ -33,44 +70,56 @@ module.exports = (input, opts) => {
const runCleanup = !opts.skipCleanup && !opts.yolo;

if (VERSIONS.indexOf(input) === -1 && !semver.valid(input)) {
throw new Error(`Version should be either ${VERSIONS.join(', ')}, or a valid semver version.`);
return Promise.reject(new Error(`Version should be either ${VERSIONS.join(', ')}, or a valid semver version.`));
}

if (semver.gte(process.version, '6.0.0')) {
throw new Error('You should not publish when running Node.js 6. Please downgrade and publish again. https://github.com/npm/npm/issues/5082');
}

if (!opts.anyBranch && execa.sync('git', ['symbolic-ref', '--short', 'HEAD']).stdout !== 'master') {
throw new Error('Not on `master` branch. Use --any-branch to publish anyway.');
}

if (execa.sync('git', ['status', '--porcelain']).stdout !== '') {
throw new Error('Unclean working tree. Commit or stash changes first.');
return Promise.reject(new Error('You should not publish when running Node.js 6. Please downgrade and publish again. https://github.com/npm/npm/issues/5082'));
}

log('Fetching remote git changes...');

execa.sync('git', ['fetch']);

if (execa.sync('git', ['rev-list', '--count', '--left-only', '@{u}...HEAD']).stdout !== '0') {
throw new Error('Remote history differ. Please pull changes.');
}
const tasks = new Listr([
{
title: 'Git',
task: () => gitTasks(opts)
}
]);

if (runCleanup) {
log('Reinstalling node modules. This might take a while...');
del.sync('node_modules');
exec('npm', ['install']);
tasks.add([
{
title: 'Cleanup',
task: () => del('node_modules')
},
{
title: 'Installing dependencies',
task: () => exec('npm', ['install'])
}
]);
}

if (runTests) {
log('Running tests...');
exec('npm', ['test']);
tasks.add({
title: 'Running tests',
task: () => exec('npm', ['test'])
});
}

log('Publishing new version...');
exec('npm', ['version', input]);
exec('npm', ['publish']);
log('Pushing git commit and tag...');
exec('git', ['push', '--follow-tags']);
log('Done! 🎉');
tasks.add([
{
title: 'Bumping version',
task: () => exec('npm', ['version', input])
},
{
title: 'Publishing package',
task: () => exec('npm', ['publish'])
},
{
title: 'Pushing tags',
task: () => exec('git', ['push', '--follow-tags'])
}
]);

return tasks.run()
.then(() => fsP.readFile('package.json', 'utf8'))
.then(JSON.parse);
};
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,16 @@
"commit"
],
"dependencies": {
"chalk": "^1.1.3",
"any-observable": "^0.2.0",
"del": "^2.2.0",
"execa": "^0.4.0",
"log-symbols": "^1.0.2",
"listr": "^0.4.3",
"meow": "^3.7.0",
"pify": "^2.3.0",
"rxjs": "^5.0.0-beta.9",
"semver": "^5.1.0",
"split": "^1.0.0",
"stream-to-observable": "^0.2.0",
"update-notifier": "^1.0.1"
},
"devDependencies": {
Expand Down
6 changes: 2 additions & 4 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import test from 'ava';
import m from './';

const np = input => m.bind(m, input);

test('wrong input', t => {
t.throws(np('foo'), 'Version should be either major, minor, patch, premajor, preminor, prepatch, prerelease, or a valid semver version.');
t.throws(np('4.x.3'), 'Version should be either major, minor, patch, premajor, preminor, prepatch, prerelease, or a valid semver version.');
t.throws(m('foo'), 'Version should be either major, minor, patch, premajor, preminor, prepatch, prerelease, or a valid semver version.');
t.throws(m('4.x.3'), 'Version should be either major, minor, patch, premajor, preminor, prepatch, prerelease, or a valid semver version.');
});

0 comments on commit e578a95

Please sign in to comment.