Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bin: custom git commands #106

Merged
merged 3 commits into from
Jan 17, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ CLI tools for Node.js Core collaborators.
- [Install](#install)
- [Setting up credentials](#setting-up-credentials)
- [`ncu-config`](#ncu-config)
- [`git-node`](#git-node)
- [Prerequistes](#prerequistes)
- [Demo & Usage](#demo--usage)
- [`get-metadata`](#get-metadata)
- [Git bash for Windows](#git-bash-for-windows)
- [Features](#features)
Expand Down Expand Up @@ -85,6 +88,48 @@ Options:
--global [boolean] [default: false]
```

## `git-node`

A custom Git command for landing pull requests. You can run it as
`git-node` or `git node`. To see the help text, run `git node help`.

### Prerequistes

1. It's a Git command, so make sure you have Git installed, of course.
2. Install [core-validate-commit](https://github.com/nodejs/core-validate-commit)

```
$ npm install -g core-validate-commit
```
3. Configure your upstream remote and branch name. By default it assumes your
remote pointing to https://github.com/nodejs/node is called `upstream`, and
the branch that you are trying to land PRs on is `master`. If that's not the
case:

```
$ cd path/to/node/project
$ ncu-config upstream your-remote-name
$ ncu-config branch your-branch-name
```

### Demo & Usage

1. Landing multiple commits: https://asciinema.org/a/148627
2. Landing one commit: https://asciinema.org/a/157445

```
$ cd path/to/node/project
$ git node land --abort # Abort a landing session, just in case
$ git node land $PRID # Start a new landing session

$ git rebase -i upstream/master # Put `edit` on every commit that's gonna stay

$ git node land --amend # Regenerate commit messages in HEAD
$ git rebase --continue # Repeat until the rebase is done

$ git node land --final # Verify all the commit messages
```

## `get-metadata`

This tool is inspired by Evan Lucas's [node-review](https://github.com/evanlucas/node-review),
Expand Down
21 changes: 21 additions & 0 deletions bin/git-node
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env node
'use strict';

const CMD = process.argv[2];
const path = require('path');
const { runAsync } = require('../lib/run');
const fs = require('fs');

if (!CMD) {
console.log('Run `git node help` to see how to use this');
process.exit(1);
}

const script = path.join(
__dirname, '..', 'components', 'git', `git-node-${CMD}`);
if (!fs.existsSync(script)) {
console.error(`No such command: git node ${CMD}`);
process.exit(1);
}

runAsync(script, process.argv.slice(3));
17 changes: 17 additions & 0 deletions components/git/git-node-help
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env node

console.log(`
Steps to land a pull request:
==============================================================================
$ cd path/to/node/project
$ git node land --abort # Abort a landing session, just in case
$ git node land $PRID # Start a new landing session

$ git rebase -i upstream/master # Put "edit" on every commit that's gonna stay

$ git node land --amend # Regenerate commit messages in HEAD
$ git rebase --continue # Repeat until the rebase is done

$ git node land --final # Verify all the commit messages
==============================================================================
Watch https://asciinema.org/a/148627 for a complete demo`);
85 changes: 85 additions & 0 deletions components/git/git-node-land
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/usr/bin/env node

const getMetadata = require('../metadata');
const CLI = require('../../lib/cli');
const Request = require('../../lib/request');
const {
runPromise
} = require('../../lib/run');
const LandingSession = require('../../lib/landing_session');

const START = 'START';
const APPLY = 'APPLY';
const AMEND = 'AMEND';
const FINAL = 'FINAL';
const CONTINUE = 'CONTINUE';
const ABORT = 'ABORT';

const states = [
[START, (args) => !isNaN(parseInt(args[0]))],
[CONTINUE, (args) => args[0] === '--continue'],
[APPLY, (args) => args[0] === '--apply'],
[AMEND, (args) => args[0] === '--amend'],
[FINAL, (args) => args[0] === '--final'],
[ABORT, (args) => args[0] === '--abort']
];

const cli = new CLI(process.stderr);
const req = new Request();
const dir = process.cwd();
const args = process.argv.slice(2);

const result = states.filter(([state, pred]) => pred(args));
if (result.length) {
const state = result[0][0];
runPromise(main(state, args).catch((err) => {
if (cli.spinner.enabled) {
cli.spinner.fail();
}
throw err;
}));
} else {
cli.error('Usage: `git node land <PRID>`');
process.exit(1);
}

async function main(state, args) {
let session = new LandingSession(cli, req, dir);

try {
session.restore();
} catch (err) { // JSON error?
if (state === ABORT) {
await session.abort();
return;
}
cli.warn(
'Failed to detect previous session. ' +
'please run `git node land --abort`');
return;
}

if (state === START) {
if (session.hasStarted()) {
cli.warn(
'Previous `git node land` session for ' +
`${session.pullName} in progress.`);
cli.log('run `git node land --abort` before starting a new session');
return;
}
session = new LandingSession(cli, req, dir, parseInt(args[0]));
const { repo, owner, prid } = session;
const metadata = await getMetadata({ repo, owner, prid }, cli);
return session.start(metadata);
} else if (state === APPLY) {
return session.apply();
} else if (state === AMEND) {
return session.amend();
} else if (state === FINAL) {
return session.final();
} else if (state === ABORT) {
return session.abort();
} else if (state === CONTINUE) {
return session.continue();
}
}
23 changes: 23 additions & 0 deletions lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const ora = require('ora');
const { EOL } = require('os');
const chalk = require('chalk');
const read = require('read');

const { warning, error, info, success } = require('./figures');

Expand All @@ -25,6 +26,28 @@ class CLI {
this.SPINNER_STATUS = SPINNER_STATUS;
}

prompt(question, defaultAnswer = true) {
const option =
`[${(defaultAnswer ? 'Y' : 'y')}/${(defaultAnswer ? 'n' : 'N')}]`;
return new Promise((resolve, reject) => {
read({prompt: `${question} ${option} `}, (err, answer) => {
if (err) {
reject(err);
}
if (answer === undefined || answer === null) {
reject(new Error('__ignore__'));
}
const trimmed = answer.toLowerCase().trim();
if (!trimmed) {
resolve(defaultAnswer);
} else if (trimmed === 'y') {
resolve(true);
}
resolve(false);
});
});
}

startSpinner(text) {
this.spinner.text = text;
this.spinner.start();
Expand Down
Loading