1
0
mirror of synced 2026-01-06 06:02:35 -05:00

Simple merge queue (#22992)

This commit is contained in:
Rachael Sewell
2021-11-18 20:41:08 -08:00
committed by GitHub
parent 33c5ce2d36
commit ca614134cb
3 changed files with 140 additions and 16 deletions

View File

@@ -0,0 +1,124 @@
#!/usr/bin/env node
import { getOctokit } from '@actions/github'
const token = process.env.GITHUB_TOKEN
const github = getOctokit(token)
// Mergeable status documentation here:
// https://docs.github.com/en/graphql/reference/enums#mergestatestatus
// https://docs.github.com/en/graphql/reference/enums#mergeablestate
/*
This script gets a list of automerge-enabled PRs and sorts them
by priority. The PRs with the skip-to-front-of-merge-queue label
are prioritized first. The rest of the PRs are sorted by the date
they were updated. This is basically a FIFO queue, while allowing
writers the ability to skip the line when high-priority ships are
needed but a freeze isn't necessary.
*/
main()
async function main() {
// Get a list of open PRs and order them from oldest to newest
const query = `query ($first: Int, $after: String, $firstLabels: Int) {
organization(login: "github") {
repository(name: "docs-internal") {
pullRequests(first: $first, after: $after, states: OPEN, orderBy: {field: UPDATED_AT, direction: ASC}) {
edges{
node {
number
url
updatedAt
mergeable
mergeStateStatus
autoMergeRequest {
enabledBy {
login
}
enabledAt
}
labels (first:$firstLabels){
nodes {
name
}
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
}`
const queryVariables = {
first: 100,
after: null, // when pagination in null it will get first page
firstLabels: 100,
headers: {
// required for the mergeStateStatus enum
accept: 'application/vnd.github.merge-info-preview+json',
},
}
let hasNextPage = true
const autoMergeEnabledPRs = []
// we need to get all the paginated results in the case that
// there are more than 100 PRs
while (hasNextPage) {
const graph = await github.graphql(query, queryVariables)
const dataRoot = graph.organization.repository.pullRequests
const pullRequests = dataRoot.edges
// update pagination variables
hasNextPage = dataRoot.pageInfo.hasNextPage
// the endCursor is the start cursor for the next page
queryVariables.after = dataRoot.pageInfo.endCursor
const filteredPrs = pullRequests
// this simplifies the format received from the graphql query to
// remove the unnecessary nested objects
.map((pr) => {
// make the labels object just an array of the label names
const labelArray = pr.node.labels.nodes.map((label) => label.name)
pr.node.labels = labelArray
// return the pr object and ✂️ the node property
return pr.node
})
.filter((pr) => pr.autoMergeRequest !== null)
.filter((pr) => pr.mergeable === 'MERGEABLE')
// filter out prs that don't have a calculated mergeable state yet
.filter((pr) => pr.mergeStateStatus !== 'UNKNOWN')
// filter out prs that still need a review, have merge conflicts,
// or have failing ci tests
.filter((pr) => pr.mergeStateStatus !== 'BLOCKED')
// **NOTE**: In the future we may want to send slack message to initiators
// of PRs with the following merge states because these can happen after
// a PR is green and the automerge is enabled
.filter((pr) => pr.mergeStateStatus !== 'DIRTY')
.filter((pr) => pr.mergeStateStatus !== 'UNSTABLE')
autoMergeEnabledPRs.push(...filteredPrs)
}
// Get the list of prs with the skip label so they can
// be put at the beginning of the list
const prioritizedPrList = autoMergeEnabledPRs
.filter((pr) => pr.labels.includes('skip-to-front-of-merge-queue'))
.concat(autoMergeEnabledPRs.filter((pr) => !pr.labels.includes('skip-to-front-of-merge-queue')))
const nextInQueue = prioritizedPrList.shift()
// Update the branch for the next PR in the merge queue
github.rest.pulls.updateBranch({
owner: 'github',
repo: 'docs-internal',
pull_number: parseInt(nextInQueue.number),
})
console.log(`⏱ Total PRs in the merge queue: ${prioritizedPrList.length + 1}`)
console.log(`🚂 Updated branch for PR #${JSON.stringify(nextInQueue, null, 2)}`)
console.log(`🚏 Next up in the queue: `)
console.log(JSON.stringify(prioritizedPrList, null, 2))
}

View File

@@ -17,7 +17,6 @@ export default [
'cschleiden/actions-linter@caffd707beda4fc6083926a3dff48444bc7c24aa', // uses github-actions-parser v0.23.0
'dawidd6/action-delete-branch@47743101a121ad657031e6704086271ca81b1911', // v3.0.2
'dawidd6/action-download-artifact@af92a8455a59214b7b932932f2662fdefbd78126', // v2.15.0
'docker://chinthakagodawita/autoupdate-action:v1',
'dorny/paths-filter@eb75a1edc117d3756a18ef89958ee59f9500ba58',
'trilom/file-changes-action@a6ca26c14274c33b15e6499323aac178af06ad4b', // v1.2.4
'github/codeql-action/analyze@v1',

View File

@@ -1,20 +1,22 @@
name: Autoupdate branch
# **What it does**: Any pull requests with automerge will get main branch updates.
# **Why we have it**: So we don't have to watch pull requests and click update branch 100x.
# **What it does**: The next pull request in the merge queue will get its
# branch updated with main. Only updating one branch ensures that pull requests
# in the queue are merged sequentially.
# **Why we have it**: So we don't have to watch pull requests and click
# update branch 1000x.
# **Who does it impact**: Our health.
#
# This workflow checks all open PRs targeting `main` as their base branch and
# will attempt to update them if they have automerge.
# It is triggered when a `push` event occurs ON the `main` branch (e.g. a PR
# was merged or a force-push was done).
# The merge queue consists of any pull requests with automerge enabled and
# are mergeable. There is a label that can be used to skip to the front of
# the queue (`skip-to-front-of-merge-queue`).
#
# It should work on all PRs created from source branches within the repo itself
# but is unlikely to work for PRs created from forked repos.
# This workflow is triggered when a `push` event occurs ON the `main` branch
# (e.g. a PR was merged or a force-push was done).
#
# It is still worthwhile to leave it enabled for the `docs` open source repo as
# it should at least be running on `repo-sync` branch PRs.
# This workflow runs on all PRs created from source branches within the
# public and private docs repos but is won't work for PRs created from
# forked repos.
#
on:
@@ -28,8 +30,7 @@ jobs:
name: autoupdate
runs-on: ubuntu-latest
steps:
- uses: docker://chinthakagodawita/autoupdate-action:v1
- name: Update next PR in queue
env:
GITHUB_TOKEN: ${{ secrets.OCTOMERGER_PAT_WITH_REPO_AND_WORKFLOW_SCOPE }}
PR_FILTER: auto_merge
MERGE_MSG: 'Autoupdate branch'
GITHUB_TOKEN: ${{ secrets.DOCUBOT_REPO_PAT }}
run: node .github/actions-scripts/update-merge-queue-branch.js