-
Notifications
You must be signed in to change notification settings - Fork 0
/
cherry-pick.js
69 lines (62 loc) · 2.64 KB
/
cherry-pick.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
const path = require('path')
const tmp = require('os').tmpdir()
const fs = require('fs-extra')
const execFile = require('util').promisify(require('child_process').execFile)
function createGit (dir, context) {
function exec (file, args = [], options) {
context.log.debug(file, ...args)
return execFile(file, args, {cwd: dir, ...options})
}
function git (args, options) { return exec('/usr/bin/git', args, options) }
function child (subdir) { return createGit(path.join(dir, subdir), context) }
exec.git = git
exec.child = child
exec.exec = exec
exec.path = dir
return exec
}
async function getWorktree (slug, context, token) {
const dir = path.join(tmp, 'backport', slug)
const worktree = createGit(dir, context)
try {
await fs.stat(path.join(worktree.path, '.git'))
await worktree.git(['remote', 'set-url', 'origin', `https://x-access-token:${token}@github.com/${slug}.git`])
} catch (err) {
if (err.code !== 'ENOENT') throw err
await fs.mkdir(worktree.path, {recursive: true})
await worktree.git(['clone', '--bare', `https://x-access-token:${token}@github.com/${slug}.git`, '.git'])
await worktree.git(['update-ref', '--no-deref', 'HEAD', 'HEAD^{commit}'])
await fs.appendFile(path.join(worktree.path, '.git/config'), ' fetch = +refs/heads/*:refs/remotes/origin/*')
// Setup config
await worktree.git(['config', '--local', 'user.email', '[email protected]'])
await worktree.git(['config', '--local', 'user.name', 'Machine User'])
await worktree.git(['config', '--local', 'commit.gpgsign', 'false'])
}
return worktree
}
module.exports = async function (context, pr, targetBase, token, forcePush = false) {
const slug = `${context.repo().owner}/${context.repo().repo}`
const worktree = await getWorktree(slug, context, token)
const targetBranch = 'backport/' + pr.number + '/' + targetBase
const targetDir = `${Date.now()}-${targetBranch}`
const branch = worktree.child(targetDir)
try {
// Fetch and create branch
await worktree.git(['fetch', 'origin', targetBase, pr.head.sha, pr.base.ref])
await worktree.git(['branch', targetDir, pr.head.sha])
await worktree.git(['worktree', 'add', targetDir, targetDir])
// Rebase the branch onto the new base and push
await branch.git(['rebase', '--onto', `origin/${targetBase}`, pr.base.sha])
const pushCommand = ['push', 'origin', `${targetDir}:${targetBranch}`]
if (forcePush) pushCommand.push('--force')
await branch.git(pushCommand)
return targetBranch
} catch (err) {
err.pr = pr
throw err
} finally {
try {
await worktree.git(['worktree', 'remove', '--force', targetDir])
} catch {}
}
}