Skip to content

Close invalid PR writer #1265

Close invalid PR writer

Close invalid PR writer #1265

name: Close invalid PR writer
on:
workflow_run:
workflows: [Close issue/PR on adding invalid label]
types: [completed]
# pull_request does not run for conflicted PRs, so reconcile from the trusted default branch.
schedule:
- cron: '*/5 * * * *'
workflow_dispatch:
permissions: {}
jobs:
close-invalid-pr-from-workflow-run:
if: >
github.repository == 'github/copilot-cli' &&
github.event_name == 'workflow_run' &&
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.repository.full_name == github.repository
runs-on: ubuntu-latest
permissions:
actions: read
pull-requests: write
concurrency:
group: close-invalid-pr-${{ github.event.workflow_run.pull_requests[0].number || github.run_id }}
cancel-in-progress: false
steps:
- name: Close invalid PR
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
WORKFLOW_RUN_ID: ${{ github.event.workflow_run.id }}
run: |
set -euo pipefail
trusted_workflow_id="$(gh api "repos/$GH_REPO/actions/workflows/close-invalid.yml" --jq .id)"
workflow_run="$(gh api "repos/$GH_REPO/actions/runs/$WORKFLOW_RUN_ID")"
if [ "$(jq -r .workflow_id <<<"$workflow_run")" != "$trusted_workflow_id" ] ||
[ "$(jq -r .event <<<"$workflow_run")" != "pull_request" ] ||
[ "$(jq -r .repository.full_name <<<"$workflow_run")" != "$GH_REPO" ]; then
echo "Workflow run is not a trusted pull_request run from $GH_REPO; skipping."
exit 0
fi
run_head_sha="$(jq -r .head_sha <<<"$workflow_run")"
run_head_repo="$(jq -r '.head_repository.full_name // empty' <<<"$workflow_run")"
run_head_branch="$(jq -r '.head_branch // empty' <<<"$workflow_run")"
if [ -z "$run_head_repo" ] ||
[ -z "$run_head_branch" ] ||
[[ ! "$run_head_sha" =~ ^[0-9a-f]{40}$ ]] ||
[ "${run_head_repo#*/}" = "$run_head_repo" ] ||
[ -z "${run_head_repo%%/*}" ] ||
[ -z "${run_head_repo#*/}" ]; then
echo "Workflow run is missing valid head repository, branch, or SHA metadata; skipping."
exit 0
fi
pull_request_count="$(jq '.pull_requests | length' <<<"$workflow_run")"
if [ "$pull_request_count" -eq 1 ]; then
pr_number="$(jq -r .pull_requests[0].number <<<"$workflow_run")"
elif [ "$pull_request_count" -eq 0 ]; then
run_head_owner="${run_head_repo%%/*}"
matching_prs="$(
gh api --method GET --paginate "repos/$GH_REPO/pulls" \
-f state=open \
-f head="$run_head_owner:$run_head_branch" \
-f per_page=100 |
jq -cs \
--arg repo "$GH_REPO" \
--arg head_repo "$run_head_repo" \
--arg head_branch "$run_head_branch" \
--arg head_sha "$run_head_sha" \
'add | [
.[] |
select(
.state == "open" and
.base.repo.full_name == $repo and
.head.repo.full_name == $head_repo and
.head.ref == $head_branch and
.head.sha == $head_sha
)
]'
)"
if [ "$(jq 'length' <<<"$matching_prs")" -ne 1 ]; then
echo "Workflow run could not be uniquely associated with an open PR; skipping."
exit 0
fi
pr_number="$(jq -r '.[0].number' <<<"$matching_prs")"
else
echo "Workflow run is associated with multiple PRs; skipping."
exit 0
fi
if [[ ! "$pr_number" =~ ^[1-9][0-9]*$ ]]; then
echo "Workflow run produced an invalid PR number; skipping."
exit 0
fi
pr="$(gh api "repos/$GH_REPO/pulls/$pr_number")"
if [ "$(jq -r .base.repo.full_name <<<"$pr")" != "$GH_REPO" ] ||
[ "$(jq -r '.head.repo.full_name // empty' <<<"$pr")" != "$run_head_repo" ] ||
[ "$(jq -r .head.ref <<<"$pr")" != "$run_head_branch" ] ||
[ "$(jq -r .head.sha <<<"$pr")" != "$run_head_sha" ]; then
echo "PR #$pr_number no longer matches the workflow run head; skipping."
exit 0
fi
if [ "$(jq -r .state <<<"$pr")" != "open" ] ||
! jq -e 'any(.labels[]?; .name == "invalid")' >/dev/null <<<"$pr"; then
echo "PR #$pr_number is not open with the invalid label; skipping."
exit 0
fi
gh api -X PATCH "repos/$GH_REPO/pulls/$pr_number" -f state=closed
reconcile-invalid-prs:
if: >
github.repository == 'github/copilot-cli' &&
(github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
runs-on: ubuntu-latest
permissions:
pull-requests: write
concurrency:
group: close-invalid-pr-reconciliation
cancel-in-progress: false
steps:
- name: Close open PRs with the invalid label
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
run: |
set -euo pipefail
gh api --paginate "repos/$GH_REPO/pulls?state=open&per_page=100" \
--jq '.[] | select(any(.labels[]?; .name == "invalid")) | .number' |
while read -r pr_number; do
pr="$(gh api "repos/$GH_REPO/pulls/$pr_number")"
if [ "$(jq -r .state <<<"$pr")" = "open" ] &&
jq -e 'any(.labels[]?; .name == "invalid")' >/dev/null <<<"$pr"; then
gh api -X PATCH "repos/$GH_REPO/pulls/$pr_number" -f state=closed
fi
done