143 lines
4.1 KiB
JavaScript
Executable File
143 lines
4.1 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
import fs from 'fs'
|
|
import github from '@actions/github'
|
|
|
|
const OPTIONS = Object.fromEntries(
|
|
['BASE', 'BODY_FILE', 'GITHUB_TOKEN', 'HEAD', 'LANGUAGE', 'TITLE', 'GITHUB_REPOSITORY'].map(
|
|
(envVarName) => {
|
|
const envVarValue = process.env[envVarName]
|
|
if (!envVarValue) {
|
|
throw new Error(`You must supply a ${envVarName} environment variable`)
|
|
}
|
|
return [envVarName, envVarValue]
|
|
}
|
|
)
|
|
)
|
|
|
|
if (!process.env.GITHUB_REPOSITORY) {
|
|
throw new Error('GITHUB_REPOSITORY environment variable not set')
|
|
}
|
|
|
|
const RETRY_STATUSES = [
|
|
422, // Retry the operation if the PR already exists
|
|
502, // Retry the operation if the API responds with a `502 Bad Gateway` error.
|
|
]
|
|
const RETRY_ATTEMPTS = 3
|
|
const {
|
|
// One of the default environment variables provided by Actions.
|
|
GITHUB_REPOSITORY,
|
|
|
|
// These are passed in from the step in the workflow file.
|
|
TITLE,
|
|
BASE,
|
|
HEAD,
|
|
LANGUAGE,
|
|
BODY_FILE,
|
|
GITHUB_TOKEN,
|
|
} = OPTIONS
|
|
const [OWNER, REPO] = GITHUB_REPOSITORY.split('/')
|
|
|
|
const octokit = github.getOctokit(GITHUB_TOKEN)
|
|
|
|
/**
|
|
* @param {object} config Configuration options for finding the PR.
|
|
* @returns {Promise<number | undefined>} The PR number.
|
|
*/
|
|
async function findPullRequestNumber(config) {
|
|
// Get a list of PRs and see if one already exists.
|
|
const { data: listOfPullRequests } = await octokit.rest.pulls.list({
|
|
owner: config.owner,
|
|
repo: config.repo,
|
|
head: `${config.owner}:${config.head}`,
|
|
})
|
|
|
|
return listOfPullRequests[0]?.number
|
|
}
|
|
|
|
/**
|
|
* When this file was first created, we only introduced support for creating a pull request for some translation batch.
|
|
* However, some of our first workflow runs failed during the pull request creation due to a timeout error.
|
|
* There have been cases where, despite the timeout error, the pull request gets created _anyway_.
|
|
* To accommodate this reality, we created this function to look for an existing pull request before a new one is created.
|
|
* Although the "find" check is redundant in the first "cycle", it's designed this way to recursively call the function again via its retry mechanism should that be necessary.
|
|
*
|
|
* @param {object} config Configuration options for creating the pull request.
|
|
* @returns {Promise<number>} The PR number.
|
|
*/
|
|
async function findOrCreatePullRequest(config) {
|
|
const found = await findPullRequestNumber(config)
|
|
|
|
if (found) {
|
|
return found
|
|
}
|
|
|
|
try {
|
|
const { data: pullRequest } = await octokit.rest.pulls.create({
|
|
owner: config.owner,
|
|
repo: config.repo,
|
|
base: config.base,
|
|
head: config.head,
|
|
title: config.title,
|
|
body: config.body,
|
|
draft: false,
|
|
})
|
|
|
|
return pullRequest.number
|
|
} catch (error) {
|
|
if (!error.response || !config.retryCount) {
|
|
throw error
|
|
}
|
|
|
|
if (!config.retryStatuses.includes(error.response.status)) {
|
|
throw error
|
|
}
|
|
|
|
console.error(`Error creating pull request: ${error.message}`)
|
|
console.warn(`Retrying in 5 seconds...`)
|
|
await new Promise((resolve) => setTimeout(resolve, 5000))
|
|
|
|
config.retryCount -= 1
|
|
|
|
return findOrCreatePullRequest(config)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {object} config Configuration options for labeling the PR
|
|
* @returns {Promise<undefined>}
|
|
*/
|
|
async function labelPullRequest(config) {
|
|
await octokit.rest.issues.update({
|
|
owner: config.owner,
|
|
repo: config.repo,
|
|
issue_number: config.issue_number,
|
|
labels: config.labels,
|
|
})
|
|
}
|
|
|
|
async function main() {
|
|
const options = {
|
|
title: TITLE,
|
|
base: BASE,
|
|
head: HEAD,
|
|
body: fs.readFileSync(BODY_FILE, 'utf8'),
|
|
labels: ['translation-batch', `translation-batch-${LANGUAGE}`],
|
|
owner: OWNER,
|
|
repo: REPO,
|
|
retryStatuses: RETRY_STATUSES,
|
|
retryCount: RETRY_ATTEMPTS,
|
|
}
|
|
|
|
options.issue_number = await findOrCreatePullRequest(options)
|
|
const pr = `${GITHUB_REPOSITORY}#${options.issue_number}`
|
|
console.log(`Created PR ${pr}`)
|
|
|
|
// metadata parameters aren't currently available in `github.rest.pulls.create`,
|
|
// but they are in `github.rest.issues.update`.
|
|
await labelPullRequest(options)
|
|
console.log(`Updated ${pr} with these labels: ${options.labels.join(', ')}`)
|
|
}
|
|
|
|
main()
|