Skip to content

Commit f99e6f4

Browse files
committed
git: abstract landing session over session
1 parent 86a55aa commit f99e6f4

File tree

3 files changed

+424
-405
lines changed

3 files changed

+424
-405
lines changed

components/git/git-node-land

Lines changed: 21 additions & 247 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,11 @@
22

33
const getMetadata = require('../metadata');
44
const CLI = require('../../lib/cli');
5-
const cli = new CLI(process.stderr);
65
const Request = require('../../lib/request');
7-
const req = new Request();
86
const {
9-
runPromise, runAsync, runSync, forceRunAsync
7+
runPromise
108
} = require('../../lib/run');
11-
const Session = require('../../lib/landing_session');
12-
const dir = process.cwd();
13-
const args = process.argv.slice(2);
9+
const LandingSession = require('../../lib/landing_session');
1410

1511
const START = 'START';
1612
const APPLY = 'APPLY';
@@ -28,9 +24,15 @@ const states = [
2824
[ABORT, (args) => args[0] === '--abort']
2925
];
3026

27+
const cli = new CLI(process.stderr);
28+
const req = new Request();
29+
const dir = process.cwd();
30+
const args = process.argv.slice(2);
31+
3132
const result = states.filter(([state, pred]) => pred(args));
3233
if (result.length) {
33-
runPromise(main(result[0][0], args).catch((err) => {
34+
const state = result[0][0];
35+
runPromise(main(state, args).catch((err) => {
3436
if (cli.spinner.enabled) {
3537
cli.spinner.fail();
3638
}
@@ -42,14 +44,13 @@ if (result.length) {
4244
}
4345

4446
async function main(state, args) {
45-
let session;
47+
let session = new LandingSession(cli, req, dir);
4648

4749
try {
48-
session = Session.restore(dir);
50+
session.restore();
4951
} catch (err) { // JSON error?
5052
if (state === ABORT) {
51-
session = new Session(dir);
52-
await abort(session);
53+
await session.abort();
5354
return;
5455
}
5556
cli.warn(
@@ -66,246 +67,19 @@ async function main(state, args) {
6667
cli.log('run `git node land --abort` before starting a new session');
6768
return;
6869
}
69-
session = new Session(dir, parseInt(args[0]));
70-
await start(session);
70+
session = new LandingSession(cli, req, dir, parseInt(args[0]));
71+
const { repo, owner, prid } = session;
72+
const metadata = await getMetadata({ repo, owner, prid }, cli);
73+
return session.start(metadata);
7174
} else if (state === APPLY) {
72-
await apply(session);
75+
return session.apply();
7376
} else if (state === AMEND) {
74-
await amend(session);
77+
return session.amend();
7578
} else if (state === FINAL) {
76-
await final(session);
79+
return session.final();
7780
} else if (state === ABORT) {
78-
await abort(session);
81+
return session.abort();
7982
} else if (state === CONTINUE) {
80-
await continueSession(session);
81-
}
82-
}
83-
84-
async function start(session) {
85-
session.start();
86-
const { repo, owner, prid } = session;
87-
const result = await getMetadata({ repo, owner, prid }, cli);
88-
89-
const status = result.status ? 'should be ready' : 'is not ready';
90-
const response = await cli.prompt(
91-
`This PR ${status} to land, do you want to continue?`);
92-
if (response) {
93-
session.saveMetadata(result);
94-
session.startApplying();
95-
return apply(session);
96-
} else {
97-
await abort(session);
98-
process.exit();
99-
}
100-
}
101-
102-
function getNotYetPushedCommits(session, verbose) {
103-
const upstream = session.upstream;
104-
const branch = session.branch;
105-
var revs;
106-
if (verbose) {
107-
revs = runSync('git',
108-
['log', '--oneline', `${upstream}/${branch}...HEAD`]);
109-
} else {
110-
revs = runSync('git', ['rev-list', `${upstream}/${branch}...HEAD`]);
111-
}
112-
113-
if (!revs.trim()) {
114-
return [];
115-
}
116-
return revs.trim().split('\n');
117-
}
118-
119-
async function tryAbortAm(session, cli) {
120-
if (session.amInProgress()) {
121-
const shouldAbortAm = await cli.prompt(
122-
'Abort previous git am sessions?');
123-
if (shouldAbortAm) {
124-
await forceRunAsync('git', ['am', '--abort']);
125-
cli.ok('Aborted previous git am sessions');
126-
}
127-
} else {
128-
cli.ok('No git am in progress');
129-
}
130-
}
131-
132-
async function tryAbortRebase(session, cli) {
133-
if (session.rebaseInProgress()) {
134-
const shouldAbortRebase = await cli.prompt(
135-
'Abort previous git rebase sessions?');
136-
if (shouldAbortRebase) {
137-
await forceRunAsync('git', ['rebase', '--abort']);
138-
cli.ok('Aborted previous git rebase sessions');
139-
}
140-
} else {
141-
cli.ok('No git rebase in progress');
142-
}
143-
}
144-
145-
async function tryResetHead(session, cli) {
146-
const branch = `${session.upstream}/${session.branch}`;
147-
cli.startSpinner(`Bringing ${branch} up to date`);
148-
await runAsync('git',
149-
['fetch', session.upstream, session.branch]);
150-
cli.stopSpinner(`${branch} is now up-to-date`);
151-
const notYetPushed = getNotYetPushedCommits(session, true);
152-
if (notYetPushed.length) {
153-
const branch = `${session.upstream}/${session.branch}`;
154-
cli.log(`Found strayed commits in ${branch}:\n` +
155-
` - ${notYetPushed.join('\n - ')}`);
156-
const shouldReset = await cli.prompt(`Reset to ${branch}?`);
157-
if (shouldReset) {
158-
await runAsync('git', ['reset', '--hard', branch]);
159-
cli.ok(`Reset to ${branch}`);
160-
}
161-
}
162-
}
163-
164-
async function tryResetBranch(session, cli) {
165-
await tryAbortAm(session, cli);
166-
await tryAbortRebase(session, cli);
167-
168-
const branch = `${session.upstream}/${session.branch}`;
169-
const shouldResetHead = await cli.prompt(
170-
`Do you want to try reset the branch to ${branch}?`);
171-
if (shouldResetHead) {
172-
await tryResetHead(session, cli);
173-
}
174-
}
175-
176-
async function abort(session) {
177-
session.abort();
178-
await tryResetBranch(session, cli);
179-
cli.log(`Aborted \`git node land\` session in ${session.ncuDir}`);
180-
}
181-
182-
async function apply(session) {
183-
if (!session.readyToApply()) {
184-
cli.warn('This session can not proceed to apply patches, ' +
185-
'run `git node land --abort`');
186-
return;
187-
}
188-
189-
await tryResetBranch(session, cli);
190-
191-
const { repo, owner, prid } = session;
192-
// TODO: restore previously downloaded patches
193-
cli.startSpinner(`Downloading patch for ${prid}`);
194-
const patch = await req.promise({
195-
url: `https://github.com/${owner}/${repo}/pull/${prid}.patch`
196-
});
197-
session.savePatch(patch);
198-
cli.stopSpinner(`Downloaded patch to ${session.patchPath}`);
199-
200-
// TODO: check that patches downloaded match metadata.commits
201-
await runAsync('git', ['am', '--whitespace=fix', session.patchPath]);
202-
cli.ok('Patches applied');
203-
204-
session.startAmending();
205-
if (/Subject: \[PATCH\]/.test(patch)) {
206-
const shouldAmend = await cli.prompt(
207-
'There is only one commit in this PR.\n' +
208-
'do you want to amend the commit message?');
209-
if (shouldAmend) {
210-
const canFinal = await amend(session);
211-
if (canFinal) {
212-
return final(session);
213-
}
214-
}
215-
} else {
216-
const re = /Subject: \[PATCH 1\/(\d+)\]/;
217-
const match = patch.match(re);
218-
if (!match) {
219-
cli.warn('Cannot get number of commits in the patch. ' +
220-
'It seems to be malformed');
221-
return;
222-
}
223-
const upstream = session.upstream;
224-
const branch = session.branch;
225-
cli.log(
226-
`There are ${match[1]} commits in the PR.\n` +
227-
`Please run \`git rebase ${upstream}/${branch} -i\` ` +
228-
'and use `git node land --amend` to amend the commit messages');
229-
// TODO: do git rebase automatically?
230-
}
231-
}
232-
233-
async function amend(session) {
234-
if (!session.readyToAmend()) {
235-
cli.warn('Not yet ready to amend, run `git node land --abort`');
236-
return;
237-
}
238-
239-
const rev = runSync('git', ['rev-parse', 'HEAD']);
240-
const original = runSync('git', ['show', 'HEAD', '-s', '--format=%B']).trim();
241-
const metadata = session.metadata.trim().split('\n');
242-
const amended = original.split('\n');
243-
if (amended[amended.length - 1] !== '') {
244-
amended.push('');
245-
}
246-
247-
for (const line of metadata) {
248-
if (original.includes(line)) {
249-
if (line) {
250-
cli.warn(`Found ${line}, skipping..`);
251-
}
252-
} else {
253-
amended.push(line);
254-
}
255-
}
256-
257-
const message = amended.join('\n') + '\n';
258-
const messageFile = session.saveMessage(rev, message);
259-
cli.separator('New Message');
260-
cli.log(message.trim());
261-
cli.separator();
262-
const takeMessage = await cli.prompt('Use this message?');
263-
if (takeMessage) {
264-
await runAsync('git', ['commit', '--amend', '-F', messageFile]);
265-
// session.markAsAmended(rev);
266-
return true;
267-
}
268-
269-
cli.log(`Please manually edit ${messageFile}, then run\n` +
270-
`\`git commit --amend -F ${messageFile}\` to finish amending the message`);
271-
return false;
272-
};
273-
274-
async function final(session) {
275-
if (!session.readyToFinal()) { // check git rebase/am has been done
276-
cli.warn('Not yet ready to final');
277-
return;
278-
}
279-
const upstream = session.upstream;
280-
const branch = session.branch;
281-
const notYetPushed = getNotYetPushedCommits(session);
282-
const notYetPushedVerbose = getNotYetPushedCommits(session, true);
283-
await runAsync('core-validate-commit', notYetPushed);
284-
cli.separator();
285-
cli.log('The following commits are ready to be pushed to ' +
286-
`${upstream}/${branch}`);
287-
cli.log(`- ${notYetPushedVerbose.join('\n- ')}`);
288-
cli.separator();
289-
cli.log(`run \`git push ${upstream} ${branch}\` to finish landing`);
290-
const shouldClean = await cli.prompt('Clean up generated temporary files?');
291-
if (shouldClean) {
292-
session.cleanFiles();
293-
}
294-
}
295-
296-
async function continueSession(session) {
297-
if (session.readyToFinal()) {
298-
return final(session);
299-
}
300-
if (session.readyToAmend()) {
301-
return amend(session);
302-
}
303-
if (session.readyToApply()) {
304-
return apply(session);
305-
}
306-
if (session.hasStarted()) {
307-
return apply(session);
83+
return session.continue();
30884
}
309-
cli.log(
310-
'Please run `git node land <PRID> to start a landing session`');
31185
}

0 commit comments

Comments
 (0)