mirror of
https://github.com/MonsterDruide1/OdysseyDecomp
synced 2026-04-23 09:04:21 +00:00
workflow: Add status label to PRs (#778)
This commit is contained in:
parent
847b983680
commit
9d8c2c3759
169
.github/workflows/pr-status-label.yml
vendored
Normal file
169
.github/workflows/pr-status-label.yml
vendored
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
name: Add "status:"-label to PRs based on current state
|
||||
|
||||
on:
|
||||
pull_request_review:
|
||||
types: [submitted]
|
||||
pull_request:
|
||||
types: [opened]
|
||||
schedule:
|
||||
- cron: '0 * * * *' # every hour, on the hour
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
new_pr:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'pull_request' && github.event.action == 'opened'
|
||||
steps:
|
||||
- name: Label new PR as "status:waiting for review"
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.addLabels({
|
||||
...context.repo,
|
||||
issue_number: context.payload.pull_request.number,
|
||||
labels: ['status:waiting for review']
|
||||
})
|
||||
|
||||
review_update:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'pull_request_review' && github.event.action == 'submitted'
|
||||
steps:
|
||||
- name: Update status labels based on review
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const pr = context.payload.pull_request
|
||||
const review = context.payload.review
|
||||
const owner = context.repo.owner
|
||||
const repo = context.repo.repo
|
||||
|
||||
const R = review.user.login // reviewer
|
||||
const P = pr.user.login // PR author
|
||||
const O = owner // repo owner (by repo name)
|
||||
|
||||
// 1. Remove all "status:[...]" labels
|
||||
const { data: existingLabels } = await github.rest.issues.listLabelsOnIssue({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: pr.number
|
||||
})
|
||||
|
||||
const statusLabels = existingLabels.filter(l => l.name.startsWith('status:'))
|
||||
for (const label of statusLabels) {
|
||||
await github.rest.issues.removeLabel({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: pr.number,
|
||||
name: label.name
|
||||
}).catch(() => {}) // ignore if already removed
|
||||
}
|
||||
|
||||
// 2. Determine new label
|
||||
let newLabel = null
|
||||
|
||||
// https://github.com/Reviewable/Reviewable/issues/1163
|
||||
// other users cannot approve reviewers, requires permissions to actually say `review.state == 'approved'`
|
||||
const is_approved = review.state === 'approved' || review.body.includes("complete! all files reviewed, all discussions resolved")
|
||||
|
||||
if (is_approved && R === O) {
|
||||
newLabel = 'status:approved' // standard way of approval: owner appoves PR
|
||||
} else if (is_approved && P === O && R !== O) {
|
||||
newLabel = 'status:approved' // if owner is author, someone else must approve
|
||||
} else if (P === R) {
|
||||
newLabel = 'status:waiting for review'
|
||||
} else if (P !== R) {
|
||||
newLabel = 'status:waiting for author'
|
||||
} else {
|
||||
core.info('No matching condition for new label.')
|
||||
core.info(`Review state: ${review.state}, PR author: ${P}, Reviewer: ${R}, Repo owner: ${O}`)
|
||||
}
|
||||
|
||||
if (newLabel) {
|
||||
await github.rest.issues.addLabels({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: pr.number,
|
||||
labels: [newLabel]
|
||||
})
|
||||
core.info(`Added label: ${newLabel}`)
|
||||
} else {
|
||||
core.info('No new status label added.')
|
||||
}
|
||||
|
||||
promote_ready_to_merge:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'schedule'
|
||||
steps:
|
||||
- name: Promote approved PRs to "ready to merge"
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const owner = context.repo.owner
|
||||
const repo = context.repo.repo
|
||||
const now = new Date()
|
||||
|
||||
// 1. Search for open PRs with "status:approved"
|
||||
const searchQuery = `repo:${owner}/${repo} is:pr is:open label:"status:approved"`
|
||||
const { data: searchResults } = await github.rest.search.issuesAndPullRequests({ q: searchQuery })
|
||||
|
||||
for (const pr of searchResults.items) {
|
||||
const prNumber = pr.number
|
||||
|
||||
// Get full PR info (for timestamps)
|
||||
const { data: prData } = await github.rest.pulls.get({
|
||||
owner,
|
||||
repo,
|
||||
pull_number: prNumber
|
||||
})
|
||||
|
||||
const createdAt = new Date(prData.created_at)
|
||||
const hoursSinceCreation = (now - createdAt) / (1000 * 60 * 60)
|
||||
if (hoursSinceCreation < 24) {
|
||||
core.info(`Skipping #${prNumber} (created ${hoursSinceCreation.toFixed(1)}h ago)`)
|
||||
continue
|
||||
}
|
||||
|
||||
// Find the last "status:" label change (via timeline events)
|
||||
const { data: events } = await github.rest.issues.listEvents({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: prNumber,
|
||||
per_page: 100
|
||||
})
|
||||
|
||||
const lastStatusChange = events
|
||||
.filter(e => e.event === 'labeled' || e.event === 'unlabeled')
|
||||
.filter(e => e.label && e.label.name.startsWith('status:'))
|
||||
.sort((a, b) => new Date(b.created_at) - new Date(a.created_at))[0]
|
||||
|
||||
if (lastStatusChange) {
|
||||
const hoursSinceStatusChange = (now - new Date(lastStatusChange.created_at)) / (1000 * 60 * 60)
|
||||
if (hoursSinceStatusChange < 12) {
|
||||
core.info(`Skipping #${prNumber} (status changed ${hoursSinceStatusChange.toFixed(1)}h ago)`)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Conditions met → remove "status:approved", add "status:ready to merge"
|
||||
try {
|
||||
await github.rest.issues.removeLabel({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: prNumber,
|
||||
name: 'status:approved'
|
||||
}).catch(() => {})
|
||||
|
||||
await github.rest.issues.addLabels({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: prNumber,
|
||||
labels: ['status:ready to merge']
|
||||
})
|
||||
|
||||
core.info(`Promoted #${prNumber} to status:ready to merge`)
|
||||
} catch (err) {
|
||||
core.warning(`Failed to update #${prNumber}: ${err.message}`)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue