Skip to content

Commit 82b7fbd

Browse files
committedJan 22, 2018
landing: prompt for 3-way merge, log landing text
1 parent 5805ced commit 82b7fbd

File tree

2 files changed

+59
-12
lines changed

2 files changed

+59
-12
lines changed
 

‎lib/landing_session.js

+41-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict';
22

33
const {
4-
runAsync, runSync, forceRunAsync
4+
runAsync, runSync, forceRunAsync, exit
55
} = require('./run');
66
const Session = require('./session');
77

@@ -31,7 +31,7 @@ class LandingSession extends Session {
3131
const { cli } = this;
3232
this.cleanFiles();
3333
await this.tryResetBranch();
34-
cli.log(`Aborted \`git node land\` session in ${this.ncuDir}`);
34+
cli.ok(`Aborted \`git node land\` session in ${this.ncuDir}`);
3535
}
3636

3737
async apply() {
@@ -51,9 +51,28 @@ class LandingSession extends Session {
5151
});
5252
this.savePatch(patch);
5353
cli.stopSpinner(`Downloaded patch to ${this.patchPath}`);
54-
54+
cli.separator();
5555
// TODO: check that patches downloaded match metadata.commits
56-
await runAsync('git', ['am', '--whitespace=fix', this.patchPath]);
56+
try {
57+
await forceRunAsync('git', ['am', '--whitespace=fix', this.patchPath], {
58+
ignoreFailure: false
59+
});
60+
} catch (ex) {
61+
const should3Way = await cli.prompt(
62+
'The normal `git am` failed. Do you want to retry with 3-way merge?');
63+
if (should3Way) {
64+
await forceRunAsync('git', ['am', '--abort']);
65+
await runAsync('git', [
66+
'am',
67+
'-3',
68+
'--whitespace=fix',
69+
this.patchPath
70+
]);
71+
} else {
72+
cli.error('Failed to apply patches');
73+
exit();
74+
}
75+
}
5776
cli.ok('Patches applied');
5877

5978
this.startAmending();
@@ -117,7 +136,6 @@ class LandingSession extends Session {
117136
const messageFile = this.saveMessage(rev, message);
118137
cli.separator('New Message');
119138
cli.log(message.trim());
120-
cli.separator();
121139
const takeMessage = await cli.prompt('Use this message?');
122140
if (takeMessage) {
123141
await runAsync('git', ['commit', '--amend', '-F', messageFile]);
@@ -142,12 +160,22 @@ class LandingSession extends Session {
142160
const notYetPushed = this.getNotYetPushedCommits();
143161
const notYetPushedVerbose = this.getNotYetPushedCommits(true);
144162
await runAsync('core-validate-commit', notYetPushed);
163+
145164
cli.separator();
146165
cli.log('The following commits are ready to be pushed to ' +
147166
`${upstream}/${branch}`);
148167
cli.log(`- ${notYetPushedVerbose.join('\n- ')}`);
149168
cli.separator();
150-
cli.log(`run \`git push ${upstream} ${branch}\` to finish landing`);
169+
170+
let willBeLanded = notYetPushed[notYetPushed.length - 1].slice(0, 7);
171+
if (notYetPushed.length > 1) {
172+
const head = this.getUpstreamHead().slice(0, 7);
173+
willBeLanded = `${head}...${willBeLanded}`;
174+
}
175+
cli.log('To finish landing:');
176+
cli.log(`1. Run \`git push ${upstream} ${branch}\``);
177+
cli.log(`2. Post in the PR: \`Landed in ${willBeLanded}\``);
178+
151179
const shouldClean = await cli.prompt('Clean up generated temporary files?');
152180
if (shouldClean) {
153181
this.cleanFiles();
@@ -183,11 +211,17 @@ class LandingSession extends Session {
183211
getNotYetPushedCommits(verbose) {
184212
const { upstream, branch } = this;
185213
const ref = `${upstream}/${branch}...HEAD`;
186-
const gitCmd = verbose ? ['log', '--oneline', ref] : ['rev-list', ref];
214+
const gitCmd = verbose
215+
? ['log', '--oneline', '--reverse', ref] : ['rev-list', '--reverse', ref];
187216
const revs = runSync('git', gitCmd).trim();
188217
return revs ? revs.split('\n') : [];
189218
}
190219

220+
getUpstreamHead(verbose) {
221+
const { upstream, branch } = this;
222+
return runSync('git', ['rev-parse', `${upstream}/${branch}^1`]).trim();
223+
}
224+
191225
async tryAbortAm() {
192226
const { cli } = this;
193227
if (!this.amInProgress()) {

‎lib/run.js

+18-5
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,22 @@ const { spawn, spawnSync } = require('child_process');
44

55
const IGNORE = '__ignore__';
66

7-
function runAsyncBase(cmd, args, options) {
7+
function runAsyncBase(cmd, args, options = {}) {
88
return new Promise((resolve, reject) => {
99
const child = spawn(cmd, args, Object.assign({
1010
cwd: process.cwd(),
1111
stdio: 'inherit'
12-
}, options));
12+
}, options.spawnArgs));
1313
child.on('close', (code) => {
1414
if (code !== 0) {
15-
return reject(new Error(IGNORE));
15+
const { ignoreFailure = true } = options;
16+
if (ignoreFailure) {
17+
return reject(new Error(IGNORE));
18+
}
19+
const err = new Error(`${cmd} failed: ${code}`);
20+
err.code = code;
21+
err.messageOnly = true;
22+
return reject(err);
1623
}
1724
return resolve();
1825
});
@@ -22,7 +29,9 @@ function runAsyncBase(cmd, args, options) {
2229
exports.forceRunAsync = function(cmd, args, options) {
2330
return runAsyncBase(cmd, args, options).catch((error) => {
2431
if (error.message !== IGNORE) {
25-
console.error(error);
32+
if (!error.messageOnly) {
33+
console.error(error);
34+
}
2635
throw error;
2736
}
2837
});
@@ -33,7 +42,7 @@ exports.runPromise = function runAsync(promise) {
3342
if (error.message !== IGNORE) {
3443
console.error(error);
3544
}
36-
process.exit(1);
45+
exports.exit();
3746
});
3847
};
3948

@@ -53,3 +62,7 @@ exports.runSync = function(cmd, args, options) {
5362
return child.stdout.toString();
5463
}
5564
};
65+
66+
exports.exit = function() {
67+
process.exit(1);
68+
};

0 commit comments

Comments
 (0)
Please sign in to comment.