Skip to content

Commit 5f8cf80

Browse files
authored
git-node: suggest -x and --autosquash for git rebase (#237)
- Suggest to add `-x "git node land --amend"` which will put `exec git node land --amend` on every picked commit. - Suggest to add `--autosquash` if `fixup!` or `squash!` appears in the commit messages, which will add fixup or squash actions to corresponding commits if they match the autosquash rules.
1 parent 969987b commit 5f8cf80

2 files changed

Lines changed: 67 additions & 31 deletions

File tree

lib/landing_session.js

Lines changed: 60 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
const path = require('path');
44

55
const {
6-
runAsync, runSync, forceRunAsync, exit
6+
runAsync, runSync, forceRunAsync
77
} = require('./run');
88
const Session = require('./session');
99

@@ -46,17 +46,10 @@ class LandingSession extends Session {
4646
cli.ok(`Aborted \`git node land\` session in ${this.ncuDir}`);
4747
}
4848

49-
async apply() {
49+
async downloadAndPatch() {
5050
const { cli, req, repo, owner, prid } = this;
5151

52-
if (!this.readyToApply()) {
53-
cli.warn('This session can not proceed to apply patches, ' +
54-
'run `git node land --abort`');
55-
return;
56-
}
57-
await this.tryResetBranch();
58-
59-
// TODO: restore previously downloaded patches
52+
// TODO(joyeecheung): restore previously downloaded patches
6053
cli.startSpinner(`Downloading patch for ${prid}`);
6154
const patch = await req.text(
6255
`https://github.com/${owner}/${repo}/pull/${prid}.patch`);
@@ -81,13 +74,42 @@ class LandingSession extends Session {
8174
]);
8275
} else {
8376
cli.error('Failed to apply patches');
84-
exit();
77+
process.exit(1);
8578
}
8679
}
8780
cli.ok('Patches applied');
81+
return patch;
82+
}
8883

89-
this.startAmending();
90-
if (/Subject: \[PATCH\]/.test(patch)) {
84+
getRebaseSuggestion(subjects) {
85+
const { upstream, branch } = this;
86+
let command = `git rebase ${upstream}/${branch} -i`;
87+
command += ' -x "git node land --amend"';
88+
89+
const squashes = subjects.filter(
90+
line => line.includes('fixup!') || line.includes('squash!'));
91+
92+
if (squashes.length !== 0) {
93+
command += ' --autosquash';
94+
}
95+
96+
return command;
97+
}
98+
99+
async suggestAfterPatch(patch) {
100+
const { cli } = this;
101+
const subjects = patch.match(/Subject: \[PATCH.*?\].*/g);
102+
if (!subjects) {
103+
cli.warn('Cannot get number of commits in the patch. ' +
104+
'It seems to be malformed');
105+
return;
106+
}
107+
108+
// XXX(joyeecheung) we cannot guarantee that no one will put a subject
109+
// line in the commit message but that seems unlikely (some deps update
110+
// might do that).
111+
if (subjects.length === 1) {
112+
// assert(subjects[0].startsWith('Subject: [PATCH]'))
91113
const shouldAmend = await cli.prompt(
92114
'There is only one commit in this PR.\n' +
93115
'do you want to amend the commit message?');
@@ -101,20 +123,25 @@ class LandingSession extends Session {
101123
return this.final();
102124
}
103125

104-
const re = /Subject: \[PATCH 1\/(\d+)\]/;
105-
const match = patch.match(re);
106-
if (!match) {
107-
cli.warn('Cannot get number of commits in the patch. ' +
108-
'It seems to be malformed');
126+
const suggestion = this.getRebaseSuggestion(subjects);
127+
128+
cli.log(`There are ${subjects.length} commits in the PR`);
129+
cli.log('Please run the following command to complete landing\n\n' +
130+
`$ ${suggestion} # put "edit" on every commit that will stay`);
131+
}
132+
133+
async apply() {
134+
const { cli } = this;
135+
if (!this.readyToApply()) {
136+
cli.warn('This session can not proceed to apply patches, ' +
137+
'run `git node land --abort`');
109138
return;
110139
}
111-
const { upstream, branch } = this;
112-
cli.log(
113-
`There are ${match[1]} commits in the PR.\n` +
114-
`Please run \`git rebase ${upstream}/${branch} -i\`, put "edit" on ` +
115-
'every commit that\'s gonna stay and use `git node land --amend` to ' +
116-
'amend the commit messages');
117-
// TODO: do git rebase automatically?
140+
await this.tryResetBranch();
141+
142+
const patch = await this.downloadAndPatch();
143+
this.startAmending();
144+
await this.suggestAfterPatch(patch);
118145
}
119146

120147
getCurrentRev() {
@@ -166,17 +193,17 @@ class LandingSession extends Session {
166193
cli.log(`Please manually edit ${messageFile}, then run\n` +
167194
`\`git commit --amend -F ${messageFile}\` ` +
168195
'to finish amending the message');
169-
return false;
196+
process.exit(1); // make it work with git rebase -x
170197
}
171198

172199
async final() {
173-
const { cli } = this;
200+
const { cli, owner, repo, upstream, branch, prid } = this;
201+
174202
if (!this.readyToFinal()) { // check git rebase/am has been done
175203
cli.warn('Not yet ready to final');
176204
return;
177-
}
178-
const upstream = this.upstream;
179-
const branch = this.branch;
205+
};
206+
180207
const notYetPushed = this.getNotYetPushedCommits();
181208
const notYetPushedVerbose = this.getNotYetPushedCommits(true);
182209
const validateCommand = path.join(
@@ -196,9 +223,11 @@ class LandingSession extends Session {
196223
const head = this.getUpstreamHead().slice(0, 7);
197224
willBeLanded = `${head}...${willBeLanded}`;
198225
}
226+
199227
cli.log('To finish landing:');
200228
cli.log(`1. Run \`git push ${upstream} ${branch}\``);
201-
cli.log(`2. Post in the PR: \`Landed in ${willBeLanded}\``);
229+
const url = `https://github.com/${owner}/${repo}/pull/${prid}`;
230+
cli.log(`2. Post in ${url}: \`Landed in ${willBeLanded}\``);
202231

203232
const shouldClean = await cli.prompt('Clean up generated temporary files?');
204233
if (shouldClean) {

lib/session.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@ class Session {
7979
});
8080
}
8181

82+
// TODO(joyeecheung): more states
83+
// - STARTED (fetching metadata)
84+
// - DOWNLOADING (downloading the patch)
85+
// - PATCHING (git am)
86+
// - AMENDING (git rebase or just amending messages)
87+
// - DONE
88+
8289
startApplying() {
8390
this.updateSession({
8491
state: APPLYING

0 commit comments

Comments
 (0)