-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Vamshi Reddy <[email protected]>
- Loading branch information
1 parent
a5404c7
commit 9f52f6d
Showing
28 changed files
with
2,473 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
name: 'prow-github-actions' | ||
description: 'Prow inspired github CI/CD actions' | ||
author: 'Vamshi Reddy' | ||
inputs: | ||
github-token: | ||
description: "Token used by prow actions to accomplish jobs and tasks. May be a bot user access token or the limited scope Github token" | ||
required: true | ||
prow-commands: | ||
description: "Comment keywords/commands to look for. Space delimited. Expect commands on own line." | ||
required: false | ||
jobs: | ||
description: "The jobs to automatically run on event. Space delimited. Expect commands on own line." | ||
required: false | ||
merge-method: | ||
description: "Strategy for Prow-github-actions to take when merging a pull request using the lgtm cron-job. Can be 'squash', 'rebase', or 'merge'. Defaults to 'merge'" | ||
required: false | ||
branding: | ||
color: blue | ||
icon: anchor | ||
runs: | ||
using: 'node12' | ||
main: 'dist/index.js' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import * as github from '@actions/github' | ||
|
||
import * as core from '@actions/core' | ||
|
||
import {Context} from '@actions/github/lib/context' | ||
|
||
import {cronLabelPr} from './prLabeler' | ||
import {cronLgtm} from './lgtm' | ||
|
||
/** | ||
* This Method handles any cron job events. | ||
* A user should define which of the jobs they want to run in their workflow yaml | ||
* | ||
* @param context - the github context of the current action event | ||
*/ | ||
export const handleCronJobs = async ( | ||
context: Context = github.context | ||
): Promise<void> => { | ||
const runConfig = core.getInput('jobs', {required: false}).split(' ') | ||
|
||
await Promise.all( | ||
runConfig.map(async command => { | ||
switch (command) { | ||
case 'pr-labeler': | ||
core.debug('running cronLabelPr job') | ||
return await cronLabelPr(1, context).catch(async e => { | ||
return e | ||
}) | ||
|
||
case 'lgtm': | ||
core.debug('running cronLgtm job') | ||
return await cronLgtm(1, context).catch(async e => { | ||
return e | ||
}) | ||
|
||
case '': | ||
return new Error( | ||
`please provide a list of space delimited commands / jobs to run. None found` | ||
) | ||
|
||
default: | ||
return new Error( | ||
`could not execute ${command}. May not be supported - please refer to docs` | ||
) | ||
} | ||
}) | ||
) | ||
.then(results => { | ||
// Check to see if any of the promises failed | ||
for (const result of results) { | ||
if (result instanceof Error) { | ||
throw new Error(`error handling issue comment: ${result}`) | ||
} | ||
} | ||
}) | ||
.catch(e => { | ||
core.setFailed(`${e}`) | ||
}) | ||
|
||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
import * as github from '@actions/github' | ||
import {Octokit} from '@octokit/rest' | ||
|
||
import {Context} from '@actions/github/lib/context' | ||
import * as core from '@actions/core' | ||
|
||
let jobsDone = 0 | ||
|
||
/** | ||
* Inspired by https://github.com/actions/stale | ||
* this will recurse through the pages of PRs for a repo | ||
* and attempt to merge them if they have the "lgtm" label | ||
* | ||
* @param currentPage - the page to return from the github api | ||
* @param context - The github actions event context | ||
*/ | ||
export const cronLgtm = async ( | ||
currentPage: number, | ||
context: Context | ||
): Promise<number> => { | ||
core.info(`starting lgtm merger page: ${currentPage}`) | ||
const token = core.getInput('github-token', {required: true}) | ||
const octokit = new github.GitHub(token) | ||
|
||
// Get next batch | ||
let prs: Octokit.PullsListResponseItem[] | ||
try { | ||
prs = await getOpenPrs(octokit, context, currentPage) | ||
} catch (e) { | ||
throw new Error(`could not get PRs: ${e}`) | ||
} | ||
|
||
if (prs.length <= 0) { | ||
// All done! | ||
return jobsDone | ||
} | ||
|
||
await Promise.all( | ||
prs.map(async pr => { | ||
core.info(`processing pr: ${pr.number}`) | ||
if (pr.state === 'closed') { | ||
return | ||
} | ||
|
||
if (pr.state === 'locked') { | ||
return | ||
} | ||
|
||
return await tryMergePr(pr, octokit, context) | ||
.then(() => { | ||
jobsDone++ | ||
}) | ||
.catch(async e => { | ||
return e | ||
}) | ||
}) | ||
).then(results => { | ||
for (const result of results) { | ||
if (result instanceof Error) { | ||
throw new Error(`error processing pr: ${result}`) | ||
} | ||
} | ||
}) | ||
|
||
// Recurse, continue to next page | ||
return await cronLgtm(currentPage + 1, context) | ||
} | ||
|
||
/** | ||
* grabs pulls from github in baches of 100 | ||
* | ||
* @param octokit - a hydrated github client | ||
* @param context - the github actions workflow context | ||
* @param page - the page number to get from the api | ||
*/ | ||
const getOpenPrs = async ( | ||
octokit: github.GitHub, | ||
context: Context = github.context, | ||
page: number | ||
): Promise<Octokit.PullsListResponse> => { | ||
core.debug(`getting prs page ${page}...`) | ||
|
||
const prResults = await octokit.pulls.list({ | ||
...context.repo, | ||
state: 'open', | ||
page | ||
}) | ||
|
||
core.debug(`got: ${prResults.data}`) | ||
|
||
return prResults.data | ||
} | ||
|
||
/** | ||
* Attempts to merge a PR if it is mergable and has the lgtm label | ||
* | ||
* @param pr - the PR to try and merge | ||
* @param octokit - a hydrated github api client | ||
* @param context - the github actions event context | ||
*/ | ||
const tryMergePr = async ( | ||
pr: Octokit.PullsListResponseItem, | ||
octokit: github.GitHub, | ||
context: Context = github.context | ||
): Promise<void> => { | ||
const method = core.getInput('merge-method', {required: false}) | ||
|
||
// if pr has label 'lgtm', attempt to merge | ||
// but not if it has the 'hold' label | ||
if ( | ||
pr.labels.map(e => e.name).includes('lgtm') && | ||
!pr.labels.map(e => e.name).includes('hold') | ||
) { | ||
try { | ||
switch (method) { | ||
case 'squash': | ||
await octokit.pulls.merge({ | ||
...context.repo, | ||
pull_number: pr.number, | ||
merge_method: 'squash' | ||
}) | ||
break | ||
|
||
case 'rebase': | ||
await octokit.pulls.merge({ | ||
...context.repo, | ||
pull_number: pr.number, | ||
merge_method: 'rebase' | ||
}) | ||
break | ||
|
||
default: | ||
await octokit.pulls.merge({ | ||
...context.repo, | ||
pull_number: pr.number, | ||
merge_method: 'merge' | ||
}) | ||
} | ||
} catch (e) { | ||
core.debug(`could not merge pr ${pr.number}: ${e}`) | ||
} | ||
} | ||
} |
Oops, something went wrong.