|
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 |