Skip to content

Create GitBook Sync PRs #1

Create GitBook Sync PRs

Create GitBook Sync PRs #1

# Commits 0 Open PRs 1 Open PR 2 Open PRs
# ------------------------------------------- ---------------------------------------------------- ------------------------------------------------------------------------------------------------------- ---------------------------------------------------------
# Neither ahead or behind Nothing Dismiss PRs Dismiss PRs
# `documentation-gitbook` is behind Open A PR from `main` into `documentation-gitbook` Determine the directionality, if wrong dismiss and open a PR from `main` into `documentation-gitbook` Dismiss the PR from `documentation-gitbook` into `main`
# `documentation-gitbook` is behind Open A PR from `documentation-gitbook` into `main` Determine the directionality, if wrong dismiss and open a PR from `documentation-gitbook` into `main` Dismiss the PR from `main` into `documentation-gitbook`
# `documentation-gitbook` is ahead & behind Open 2 PRs Determine the directionality of the missing one and open that Nothing
name: create-docs-pr
on:
workflow_dispatch:
schedule:
- cron: '1 10 * * 1-5'
jobs:
create-pr:
runs-on: ubuntu-latest
env:
DOCS_BRANCH: documentation-gitbook
PR_LABELS: 'documentation,high priority'
PR_ASSIGNEES: 'emprzy,jcblemai,pearsonca,saraloo,TimothyWillard'
PR_TITLE: 'Sync GitBook'
OWNER: 'HopkinsIDD'
REPO: 'flepiMoP'
steps:
- name: Checkout
uses: actions/checkout@v4
with:
lfs: true
fetch-depth: 0
- name: Determine Commits Ahead/Behind
run: |
git fetch --all
DOCS_AHEAD_MAIN=$( eval "git rev-list --count origin/main..origin/$DOCS_BRANCH -- documentation/" )
DOCS_BEHIND_MAIN=$( eval "git rev-list --count origin/$DOCS_BRANCH..origin/main -- documentation/" )
echo "DOCS_AHEAD_MAIN=$DOCS_AHEAD_MAIN" >> $GITHUB_ENV
echo "DOCS_BEHIND_MAIN=$DOCS_BEHIND_MAIN" >> $GITHUB_ENV
- name: Create PR If Needed
uses: actions/github-script@v7
id: create-pr
with:
result-encoding: string
retries: 5
script: |
const { DOCS_AHEAD_MAIN, DOCS_BEHIND_MAIN, DOCS_BRANCH, PR_LABELS, PR_ASSIGNEES, PR_TITLE, OWNER, REPO } = process.env
const prLabels = PR_LABELS.split(",")
const prAssignees = PR_ASSIGNEES.split(",")
const cc = prAssignees.map(x => "@" + x).join(", ")
const docsAheadMain = parseInt(DOCS_AHEAD_MAIN, 10)
const docsBehindMain = parseInt(DOCS_BEHIND_MAIN, 10)
if (isNaN(docsAheadMain) || isNaN(docsBehindMain)) {
throw new Error(`Cannot convert either "${DOCS_AHEAD_MAIN}" or "${DOCS_BEHIND_MAIN}" to integers.`)
}
const initialResults = await github.rest.search.issuesAndPullRequests({
q: `owner:${OWNER} repo:${REPO} is:open is:pr in:title '${PR_TITLE}'`
})
const count = initialResults.data.total_count
if (count > 2) {
throw new Error(`There are ${count} open PRs containing '${PR_TITLE}', but this action can only handle 0, 1, or 2 open PRs.`)
}
console.log(`${DOCS_BRANCH} is ${docsAheadMain} ahead, ${docsBehindMain} behind main. The open PR count is ${count}.`)
async function dismissAllPRs() {
initialResults.data.items.forEach((item) => {
github.rest.pulls.update({
owner: OWNER,
repo: REPO,
pull_number: item.number,
state: "closed"
})
})
}
async function createPR({ from, to, body }) {
let prBody = `cc: ${cc}.`
if (body !== null) {
prBody = `${body} ${prBody}`
}
const today = (new Date()).toLocaleDateString()
const pr = await github.rest.pulls.create({
owner: OWNER,
repo: REPO,
head: from,
base: to,
title: `${today} ${PR_TITLE} From ${from} Into ${to}`,
body: prBody
})
github.rest.issues.addLabels({
owner: OWNER,
repo: REPO,
issue_number: pr.data.number,
labels: prLabels
})
github.rest.issues.addAssignees({
owner: OWNER,
repo: REPO,
issue_number: pr.data.number,
assignees: prAssignees
})
return pr.data.number
}
async function handleSingleDirection({ from, to }) {
if (count === 0) {
// There isn't the 1 expected PR, open it
createPR({
from: from,
to: to,
body: null
})
} else if (count === 1) {
// There is a PR open, determine direction
let title = initialResults.data.items[0].title
if (!title.includes(`${PR_TITLE} From ${from} Into ${to}`)) {
// Wrong direction, close & recreate
dismissAllPRs()
createPR({
from: from,
to: to,
body: null
})
}
} else {
// There are two PRs open, close the wrong direction
initialResults.data.items.forEach((item) => {
if (!title.includes(`${PR_TITLE} From ${from} Into ${to}`)) {
github.rest.pulls.update({
owner: OWNER,
repo: REPO,
pull_number: item.number,
state: "closed"
})
}
})
}
}
if (docsAheadMain > 0 && docsBehindMain > 0) {
// Need PRs both ways
if (count === 0) {
// There are 0 PRs open, open both of them
const docsIntoMainPrNumber = await createPR({
from: DOCS_BRANCH,
to: "main",
body: null
})
createPR({
from: "main",
to: DOCS_BRANCH,
body: `Please merge GH-${docsIntoMainPrNumber} first.`
})
} else if (count === 1) {
// There is already a PR open in one direction, open the other direction
let title = initialResults.data.items[0].title
let number = initialResults.data.items[0].number
if (title.includes(`${PR_TITLE} From ${DOCS_BRANCH} Into main`)) {
// From docs into main already exists, create main into docs
createPR({
from: "main",
to: DOCS_BRANCH,
body: `Please merge GH-${number} first.`
})
} else {
// From main into docs already exists, create docs into main
const docsIntoMainPrNumber = await createPR({
from: DOCS_BRANCH,
to: "main",
body: null
})
github.rest.issues.createComment({
owner: OWNER,
repo: REPO,
issue_number: number,
body: `Please merge GH-${docsIntoMainPrNumber} first.`
})
}
}
} else if (docsAheadMain > 0) {
// Need a PR from docs to main
handleSingleDirection({
from: DOCS_BRANCH,
to: "main"
})
} else if (docsBehindMain > 0) {
// Need a PR from main to docs
handleSingleDirection({
from: "main",
to: DOCS_BRANCH
})
} else if (count > 0) {
// Ahead/behind commits is 0 but there are stale PRs to close
dismissAllPRs()
}