-
Notifications
You must be signed in to change notification settings - Fork 116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: add cron job to pick up hanging prs #1217
Changes from 3 commits
7881e54
c248993
6fc6505
f6a4842
4c6daff
0a15f1a
8a89d49
2440f97
8ff02f6
38d3d8f
82edf1c
2550522
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,7 +44,7 @@ interface WatchPR { | |
author: string; | ||
url: string; | ||
reactionId: number; | ||
installationId: number; | ||
installationId?: number; | ||
} | ||
|
||
interface Label { | ||
|
@@ -331,6 +331,98 @@ handler.checkPRMergeability = async function checkPRMergeability( | |
} | ||
}; | ||
|
||
/** | ||
* For a given repository, looks through all the PRs and checks to see if they have a MOG label | ||
* @param owner the owner of the repo | ||
* @param repo the repo name | ||
* @param context the context of the webhook payload | ||
* @returns void | ||
*/ | ||
handler.pickUpPR = async function pickUpPR( | ||
owner: string, | ||
repo: string, | ||
github: Context['github'] | ||
) { | ||
const prs = await github.paginate(await github.pulls.list, { | ||
owner, | ||
repo, | ||
state: 'open', | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can probably reduce the # of queries, by using the search API: https://docs.github.com/en/free-pro-team@latest/rest/reference/search#search-issues-and-pull-requests |
||
|
||
for (const pr of prs) { | ||
const labels = await github.paginate( | ||
await github.issues.listLabelsOnIssue, | ||
{ | ||
owner, | ||
repo, | ||
issue_number: pr.number, | ||
} | ||
); | ||
|
||
const labelFound = labels.find( | ||
(label: Label) => | ||
label.name === MERGE_ON_GREEN_LABEL || | ||
label.name === MERGE_ON_GREEN_LABEL_SECURE | ||
); | ||
|
||
if (labelFound) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should only do this if there's not already an entry in |
||
// check to see if the owner has branch protection rules | ||
let branchProtection: string[] | undefined; | ||
try { | ||
branchProtection = ( | ||
await github.repos.getBranchProtection({ | ||
owner, | ||
repo, | ||
branch: 'master', | ||
}) | ||
).data.required_status_checks.contexts; | ||
logger.info( | ||
`checking branch protection for ${owner}/${repo}: ${branchProtection}` | ||
); | ||
} catch (err) { | ||
err.message = `Error in getting branch protection\n\n${err.message}`; | ||
await github.issues.createComment({ | ||
owner, | ||
repo, | ||
issue_number: pr.number, | ||
body: | ||
"Your PR doesn't have any required checks. Please add required checks to your master branch and then re-add the label. Learn more about enabling these checks here: https://help.github.com/en/github/administering-a-repository/enabling-required-status-checks.", | ||
}); | ||
logger.error(err); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this logic share the same code as the webhook handling? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 I agree, I think the logic could be simplified if we:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure about faking an webhook - we could probably extract that common logic into a function to execute from both paths. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I simplified the logic here! |
||
} | ||
|
||
// if the owner has branch protection set up, add this PR to the Datastore table | ||
if (branchProtection) { | ||
// try to create reaction. Save this reaction in the Datastore table since I don't (think) | ||
// it is on the pull_request payload. | ||
const reactionId = ( | ||
await github.reactions.createForIssue({ | ||
owner, | ||
repo, | ||
issue_number: pr.number, | ||
content: 'eyes', | ||
}) | ||
).data.id; | ||
|
||
await handler.addPR( | ||
{ | ||
number: pr.number, | ||
owner, | ||
repo, | ||
state: 'continue', | ||
url: pr.html_url, | ||
branchProtection: branchProtection, | ||
label: labelFound.name, | ||
author: pr.user.login, | ||
reactionId, | ||
}, | ||
pr.html_url | ||
); | ||
} | ||
} | ||
} | ||
}; | ||
|
||
// TODO: refactor into multiple function exports, this will take some work in | ||
// gcf-utils. | ||
|
||
|
@@ -350,6 +442,22 @@ function handler(app: Application) { | |
await handler.cleanDatastoreTable(watchedPRs, app, context); | ||
return; | ||
} | ||
|
||
//because we're searching for the PRs, and not getting the installation ID, we have to use | ||
//the bot's installation ID to call the API. So, we need to make sure it matches the repo owner | ||
if (context.payload.cron_org) { | ||
logger.info('Entering job to pick up any hanging PRs'); | ||
const owner = context.payload.organization.login; | ||
const repo = context.payload.repository.name; | ||
|
||
if (context.payload.cron_org !== owner) { | ||
logger.info(`skipping run for ${context.payload.cron_org}`); | ||
return; | ||
} | ||
await handler.pickUpPR(owner, repo, context.github); | ||
return; | ||
} | ||
|
||
const start = Date.now(); | ||
await handler.checkPRMergeability(watchedPRs, app, context); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it worth trying to do these both async and awaiting them at the end? (it's going to complete all of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, I'm expecting this to run on a separate cron job - we won't try merging on the same run as we try picking up the PRs. |
||
logger.info(`mergeOnGreen check took ${Date.now() - start}ms`); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can we call this
scanForMissingPullRequests
or something like that?