Skip to content

Commit

Permalink
added github workflow
Browse files Browse the repository at this point in the history
Signed-off-by: Vamshi Reddy <[email protected]>
  • Loading branch information
VamshiReddy02 committed Feb 14, 2024
1 parent a5404c7 commit 9f52f6d
Show file tree
Hide file tree
Showing 28 changed files with 2,473 additions and 0 deletions.
22 changes: 22 additions & 0 deletions action.yml
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'
61 changes: 61 additions & 0 deletions src/cronJobs/handleCronJob.ts
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
}
143 changes: 143 additions & 0 deletions src/cronJobs/lgtm.ts
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}`)
}
}
}
Loading

0 comments on commit 9f52f6d

Please sign in to comment.