-
Notifications
You must be signed in to change notification settings - Fork 77
/
Copy pathe-backport.js
115 lines (100 loc) · 3.67 KB
/
e-backport.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#!/usr/bin/env node
const { Octokit } = require('@octokit/rest');
const chalk = require('chalk').default;
const program = require('commander');
const inquirer = require('inquirer');
const path = require('path');
const evmConfig = require('./evm-config');
const { spawnSync } = require('./utils/depot-tools');
const { getGitHubAuthToken } = require('./utils/github-auth');
const { fatal } = require('./utils/logging');
program
.arguments('[pr]')
.description('Assists with manual backport processes')
.action(async (prNumberStr) => {
const prNumber = parseInt(prNumberStr, 10);
if (isNaN(prNumber) || `${prNumber}` !== prNumberStr) {
fatal(`backport requires a number, "${prNumberStr}" was provided`);
return;
}
const octokit = new Octokit({
auth: await getGitHubAuthToken(['repo']),
});
const { data: user } = await octokit.users.getAuthenticated();
const { data: pr } = await octokit.pulls.get({
owner: 'electron',
repo: 'electron',
pull_number: prNumber,
});
if (!pr.merge_commit_sha) {
fatal('No merge SHA available on PR');
return;
}
const targetBranches = pr.labels
.filter((label) => label.name.startsWith('needs-manual-bp/'))
.map((label) => label.name.substring(16));
if (targetBranches.length === 0) {
fatal('The given pull request is not needing any manual backports yet');
return;
}
const { branch: targetBranch } = await inquirer.prompt([
{
type: 'list',
name: 'branch',
message: 'Which branch do you want to backport this PR to?',
choices: targetBranches,
},
]);
const config = evmConfig.current();
const gitOpts = {
cwd: path.resolve(config.root, 'src', 'electron'),
stdio: 'pipe',
};
const result = spawnSync(config, 'git', ['status', '--porcelain'], gitOpts);
if (result.status !== 0 || result.stdout.toString().trim().length !== 0) {
fatal(
"Your current git working directory is not clean, we won't erase your local changes. Clean it up and try again",
);
return;
}
spawnSync(config, 'git', ['checkout', targetBranch], gitOpts, 'Failed to checkout base branch');
spawnSync(
config,
'git',
['pull', 'origin', targetBranch],
gitOpts,
'Failed to update base branch',
);
spawnSync(
config,
'git',
['fetch', 'origin', pr.base.ref],
gitOpts,
'Failed to fetch latest upstream',
);
const manualBpBranch = `manual-bp/${user.login}/pr/${prNumber}/branch/${targetBranch}`;
spawnSync(config, 'git', ['branch', '-D', manualBpBranch], gitOpts);
spawnSync(
config,
'git',
['checkout', '-b', manualBpBranch],
gitOpts,
`Failed to checkout new branch "${manualBpBranch}"`,
);
spawnSync(config, 'yarn', ['install'], gitOpts, `Failed to do "yarn install" on new branch`);
const cherryPickResult = spawnSync(config, 'git', ['cherry-pick', pr.merge_commit_sha], {
cwd: gitOpts.cwd,
});
const pushCommand = chalk.yellow(!!config.remotes.electron.fork ? 'git push fork' : 'git push');
const cherryPickCommand = chalk.yellow('git cherry-pick --continue');
const prCommand = chalk.yellow(`e pr --backport ${prNumber}`);
const followupMessage =
cherryPickResult.status !== 0
? `Cherry pick complete, fix conflicts locally and then run the following commands: "${cherryPickCommand}", "${pushCommand}"`
: `Cherry pick succeeded, run "${pushCommand}"`;
console.info(
'\n',
chalk.cyan(`${followupMessage} and finally "${prCommand}" to create your new pull request`),
);
});
program.parse(process.argv);