create-pull-request/src/github-helper.ts

180 lines
5 KiB
TypeScript
Raw Normal View History

2020-07-16 08:57:13 +00:00
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
}
2020-09-17 01:41:24 +00:00
interface Pull {
number: number
html_url: string
created: boolean
2020-09-17 01:41:24 +00:00
}
2020-07-16 08:57:13 +00:00
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'
2020-07-16 08:57:13 +00:00
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
2020-09-17 01:41:24 +00:00
): Promise<Pull> {
2020-07-16 08:57:13 +00:00
// Try to create the pull request
try {
2021-05-14 04:47:55 +00:00
core.info(`Attempting creation of pull request`)
2021-04-01 02:56:16 +00:00
const {data: pull} = await this.octokit.rest.pulls.create({
2020-07-16 08:57:13 +00:00
...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})`
)
2020-09-17 01:41:24 +00:00
return {
number: pull.number,
html_url: pull.html_url,
created: true
2020-09-17 01:41:24 +00:00
}
2021-09-02 04:59:30 +00:00
} catch (e: any) {
2020-07-16 08:57:13 +00:00
if (
e.message &&
e.message.includes(`A pull request already exists for ${headBranch}`)
2020-07-16 08:57:13 +00:00
) {
core.info(`A pull request already exists for ${headBranch}`)
} else {
2020-07-16 08:57:13 +00:00
throw e
}
}
// Update the pull request that exists for this branch and base
2021-05-14 04:47:55 +00:00
core.info(`Fetching existing pull request`)
2021-04-01 02:56:16 +00:00
const {data: pulls} = await this.octokit.rest.pulls.list({
2020-07-16 08:57:13 +00:00
...this.parseRepository(baseRepository),
state: 'open',
head: headBranch,
base: inputs.base
})
2021-05-14 04:47:55 +00:00
core.info(`Attempting update of pull request`)
2021-04-01 02:56:16 +00:00
const {data: pull} = await this.octokit.rest.pulls.update({
2020-07-16 08:57:13 +00:00
...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})`
)
2020-09-17 01:41:24 +00:00
return {
number: pull.number,
html_url: pull.html_url,
created: false
2020-09-17 01:41:24 +00:00
}
2020-07-16 08:57:13 +00:00
}
async getRepositoryParent(headRepository: string): Promise<string> {
2021-04-01 02:56:16 +00:00
const {data: headRepo} = await this.octokit.rest.repos.get({
2020-07-16 08:57:13 +00:00
...this.parseRepository(headRepository)
})
if (!headRepo.parent) {
2020-07-16 08:57:13 +00:00
throw new Error(
`Repository '${headRepository}' is not a fork. Unable to continue.`
2020-07-16 08:57:13 +00:00
)
}
return headRepo.parent.full_name
}
2020-07-16 08:57:13 +00:00
async createOrUpdatePullRequest(
inputs: Inputs,
baseRepository: string,
headRepository: string
): Promise<Pull> {
const [headOwner] = headRepository.split('/')
const headBranch = `${headOwner}:${inputs.branch}`
2020-07-16 08:57:13 +00:00
// Create or update the pull request
2020-09-17 01:41:24 +00:00
const pull = await this.createOrUpdate(inputs, baseRepository, headBranch)
2020-07-16 08:57:13 +00:00
// Apply milestone
2020-07-16 08:57:13 +00:00
if (inputs.milestone) {
core.info(`Applying milestone '${inputs.milestone}'`)
2021-04-01 02:56:16 +00:00
await this.octokit.rest.issues.update({
...this.parseRepository(baseRepository),
issue_number: pull.number,
milestone: inputs.milestone
})
2020-07-16 08:57:13 +00:00
}
// Apply labels
2020-07-16 08:57:13 +00:00
if (inputs.labels.length > 0) {
core.info(`Applying labels '${inputs.labels}'`)
2021-04-01 02:56:16 +00:00
await this.octokit.rest.issues.addLabels({
...this.parseRepository(baseRepository),
issue_number: pull.number,
labels: inputs.labels
})
2020-07-16 08:57:13 +00:00
}
// Apply assignees
2020-07-16 08:57:13 +00:00
if (inputs.assignees.length > 0) {
core.info(`Applying assignees '${inputs.assignees}'`)
2021-04-01 02:56:16 +00:00
await this.octokit.rest.issues.addAssignees({
2020-07-16 08:57:13 +00:00
...this.parseRepository(baseRepository),
2020-09-17 01:41:24 +00:00
issue_number: pull.number,
assignees: inputs.assignees
2020-07-16 08:57:13 +00:00
})
}
// 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 {
2021-04-01 02:56:16 +00:00
await this.octokit.rest.pulls.requestReviewers({
2020-07-16 08:57:13 +00:00
...this.parseRepository(baseRepository),
2020-09-17 01:41:24 +00:00
pull_number: pull.number,
2020-07-16 08:57:13 +00:00
...requestReviewersParams
})
2021-09-02 04:59:30 +00:00
} catch (e: any) {
2020-07-16 08:57:13 +00:00
if (e.message && e.message.includes(ERROR_PR_REVIEW_FROM_AUTHOR)) {
core.warning(ERROR_PR_REVIEW_FROM_AUTHOR)
} else {
throw e
}
}
}
return pull
2020-07-16 08:57:13 +00:00
}
}