OdysseyDecomp/.github/workflows/pr-status-label-review.yml
renovate[bot] 8f46da6630
workflow: Update actions/github-script to v9 (#1016)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-17 17:34:53 +02:00

120 lines
4.5 KiB
YAML

name: Add "status:"-label to PRs based on current state
on:
workflow_run:
workflows:
- PR-Review submitted
types: [completed]
permissions:
pull-requests: write
issues: write
jobs:
review_update:
runs-on: ubuntu-latest
steps:
- name: 'Download artifact'
uses: actions/github-script@v9
with:
script: |
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => {
return artifact.name == "review-event"
})[0];
let download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
const fs = require('fs');
const path = require('path');
const temp = '${{ runner.temp }}/artifacts';
if (!fs.existsSync(temp)){
fs.mkdirSync(temp);
}
fs.writeFileSync(path.join(temp, 'review-event.zip'), Buffer.from(download.data));
- name: 'Unzip artifact'
run: unzip "${{ runner.temp }}/artifacts/review-event.zip" -d "${{ runner.temp }}/artifacts"
- name: Update status labels based on review
uses: actions/github-script@v9
with:
script: |
const fs = require('fs');
const data = JSON.parse(fs.readFileSync('${{ runner.temp }}/artifacts/event.json', 'utf8'));
const owner = data.repository.owner;
const repo = data.repository.name;
const prNumber = data.pull_request.number;
const reviewState = data.review.state;
const reviewBody = data.review.body;
const changeLabel = async (currentLabels, newLabel) => {
// Remove all "status:[...]" labels
for (const label of currentLabels) {
await github.rest.issues.removeLabel({
owner,
repo,
issue_number: prNumber,
name: label.name
}).catch(() => {}) // ignore if already removed
}
// Add new label
await github.rest.issues.addLabels({
owner,
repo,
issue_number: prNumber,
labels: [newLabel]
})
core.info(`Added label: ${newLabel}`)
}
const { data: existingLabels } = await github.rest.issues.listLabelsOnIssue({
owner,
repo,
issue_number: prNumber
})
const statusLabels = existingLabels.filter(l => l.name.startsWith('status:'))
const is_approved = statusLabels.some(l => l.name === 'status:approved' || l.name === 'status:ready to merge')
// https://github.com/Reviewable/Reviewable/issues/1163
// other users cannot approve reviewers, requires permissions to actually say `reviewState == 'approved'`
const approve = reviewState === 'approved' || reviewBody.includes("complete! all files reviewed, all discussions resolved")
const R = data.review.reviewer; // reviewer
const P = data.pull_request.author; // PR author
const O = owner; // repo owner (by repo name)
let new_label = null;
if (is_approved && approve) {
core.info('PR is already approved and review is another approval. No label change needed.')
return;
}
if (approve && R === O) {
newLabel = 'status:approved' // standard way of approval: owner appoves PR
} else if (approve && 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 && !approve) {
newLabel = 'status:waiting for author'
} else {
core.info('No matching condition for new label.')
core.info(`Review state: ${reviewState}, PR author: ${P}, Reviewer: ${R}, Repo owner: ${O}`)
}
if (newLabel) {
await changeLabel(statusLabels, newLabel)
}