/
github-helper.ts
179 lines (165 loc) · 5.04 KB
/
github-helper.ts
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
import * as core from '@actions/core'
import {Inputs} from './create-pull-request'
import {Octokit, OctokitOptions} from './octokit-client'
const ERROR_PR_REVIEW_FROM_AUTHOR =
'Review cannot be requested from pull request author'
interface Repository {
owner: string
repo: string
}
interface Pull {
number: number
html_url: string
created: boolean
}
export class GitHubHelper {
private octokit: InstanceType<typeof Octokit>
constructor(token: string) {
const options: OctokitOptions = {}
if (token) {
options.auth = `${token}`
}
options.baseUrl = process.env['GITHUB_API_URL'] || 'https://api.github.com'
this.octokit = new Octokit(options)
}
private parseRepository(repository: string): Repository {
const [owner, repo] = repository.split('/')
return {
owner: owner,
repo: repo
}
}
private async createOrUpdate(
inputs: Inputs,
baseRepository: string,
headBranch: string
): Promise<Pull> {
// Try to create the pull request
try {
core.info(`Attempting creation of pull request`)
const {data: pull} = await this.octokit.rest.pulls.create({
...this.parseRepository(baseRepository),
title: inputs.title,
head: headBranch,
base: inputs.base,
body: inputs.body,
draft: inputs.draft
})
core.info(
`Created pull request #${pull.number} (${headBranch} => ${inputs.base})`
)
return {
number: pull.number,
html_url: pull.html_url,
created: true
}
} catch (e: any) {
if (
e.message &&
e.message.includes(`A pull request already exists for ${headBranch}`)
) {
core.info(`A pull request already exists for ${headBranch}`)
} else {
throw e
}
}
// Update the pull request that exists for this branch and base
core.info(`Fetching existing pull request`)
const {data: pulls} = await this.octokit.rest.pulls.list({
...this.parseRepository(baseRepository),
state: 'open',
head: headBranch,
base: inputs.base
})
core.info(`Attempting update of pull request`)
const {data: pull} = await this.octokit.rest.pulls.update({
...this.parseRepository(baseRepository),
pull_number: pulls[0].number,
title: inputs.title,
body: inputs.body,
draft: inputs.draft
})
core.info(
`Updated pull request #${pull.number} (${headBranch} => ${inputs.base})`
)
return {
number: pull.number,
html_url: pull.html_url,
created: false
}
}
async getRepositoryParent(headRepository: string): Promise<string> {
const {data: headRepo} = await this.octokit.rest.repos.get({
...this.parseRepository(headRepository)
})
if (!headRepo.parent) {
throw new Error(
`Repository '${headRepository}' is not a fork. Unable to continue.`
)
}
return headRepo.parent.full_name
}
async createOrUpdatePullRequest(
inputs: Inputs,
baseRepository: string,
headRepository: string
): Promise<Pull> {
const [headOwner] = headRepository.split('/')
const headBranch = `${headOwner}:${inputs.branch}`
// Create or update the pull request
const pull = await this.createOrUpdate(inputs, baseRepository, headBranch)
// Apply milestone
if (inputs.milestone) {
core.info(`Applying milestone '${inputs.milestone}'`)
await this.octokit.rest.issues.update({
...this.parseRepository(baseRepository),
issue_number: pull.number,
milestone: inputs.milestone
})
}
// Apply labels
if (inputs.labels.length > 0) {
core.info(`Applying labels '${inputs.labels}'`)
await this.octokit.rest.issues.addLabels({
...this.parseRepository(baseRepository),
issue_number: pull.number,
labels: inputs.labels
})
}
// Apply assignees
if (inputs.assignees.length > 0) {
core.info(`Applying assignees '${inputs.assignees}'`)
await this.octokit.rest.issues.addAssignees({
...this.parseRepository(baseRepository),
issue_number: pull.number,
assignees: inputs.assignees
})
}
// Request reviewers and team reviewers
const requestReviewersParams = {}
if (inputs.reviewers.length > 0) {
requestReviewersParams['reviewers'] = inputs.reviewers
core.info(`Requesting reviewers '${inputs.reviewers}'`)
}
if (inputs.teamReviewers.length > 0) {
requestReviewersParams['team_reviewers'] = inputs.teamReviewers
core.info(`Requesting team reviewers '${inputs.teamReviewers}'`)
}
if (Object.keys(requestReviewersParams).length > 0) {
try {
await this.octokit.rest.pulls.requestReviewers({
...this.parseRepository(baseRepository),
pull_number: pull.number,
...requestReviewersParams
})
} catch (e: any) {
if (e.message && e.message.includes(ERROR_PR_REVIEW_FROM_AUTHOR)) {
core.warning(ERROR_PR_REVIEW_FROM_AUTHOR)
} else {
throw e
}
}
}
return pull
}
}