Files
airflow/.github/workflows/mark-workflow-runs-approved.yml
Jarek Potiuk ee62251fc2 Show why external contributors' workflow runs wait for approval (#75832)
* Show why external contributors' workflow runs wait for approval

Contributors whose runs the auto-approve workflow leaves for a maintainer
only saw a label, with no reason, and a comment for each would notify
every subscriber. A pending "Workflow approval" commit status shows the
reason in the PR's checks without notifying anyone.

GitHub has no event for approving runs, but a waiting run never starts,
so a run that starts is the signal to clear the status and the label,
also for runs a maintainer approves by hand, without listing every
waiting run.

Generated-by: Claude Opus 5

* Keep the approval status in sync with runs approved during a tick

Generated-by: Claude Opus 5

* Re-check approved runs after the failure path writes the approval state

Generated-by: Claude Opus 5
2026-10-28 06:27:26 +02:00

86 lines
4.3 KiB
YAML

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
---
# When the "Tests (AMD)" run of an external contributor's PR starts, turns the pending "Workflow
# approval" status that auto-approve-workflow-runs.yml set on its commit green and removes the
# "need workflow approval" label. GitHub has no event for approving runs, but a run waiting for
# approval never starts, so a started run was approved, by a maintainer or automatically.
#
# workflow_run runs with this repository's token whatever the PR, so this workflow checks out
# nothing and only calls the GitHub API. The head branch is chosen by the contributor and reaches
# the script only through the environment.
name: Mark workflow runs approved
on: # yamllint disable-line rule:truthy
workflow_run: # zizmor: ignore[dangerous-triggers]
workflows: ["Tests (AMD)"]
types: [in_progress]
permissions:
# Removing the "need workflow approval" label.
pull-requests: write
# Turning the "Workflow approval" status green.
statuses: write
concurrency:
group: mark-workflow-runs-approved-${{ github.event.workflow_run.head_sha }}
cancel-in-progress: false
jobs:
mark-workflow-runs-approved:
name: "Mark workflow runs approved"
runs-on: ["ubuntu-slim"]
if: >-
github.repository == 'apache/airflow' &&
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.head_repository.full_name != github.repository
timeout-minutes: 5
steps:
- name: "Mark workflow runs approved"
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
HEAD_REPOSITORY: ${{ github.event.workflow_run.head_repository.full_name }}
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
STATUS_URL: "https://github.com/apache/airflow/blob/main/contributing-docs/\
05_pull_requests.rst#ci-workflow-runs-of-external-contributors"
run: |
# Keep in sync with APPROVAL_STATUS_CONTEXT and NEED_WORKFLOW_APPROVAL_LABEL in
# dev/breeze/src/airflow_breeze/utils/workflow_run_approval.py.
context="Workflow approval"
label="need workflow approval"
# The sha is put into jq filters below.
[[ "${HEAD_SHA}" =~ ^[0-9a-f]{40}$ ]] || { echo "Unexpected head sha: ${HEAD_SHA}"; exit 1; }
# Paginated: the fork CI reconciler posts a status per job, so a commit can have many contexts.
state=$(gh api --paginate "repos/${REPO}/commits/${HEAD_SHA}/status?per_page=100" \
--jq ".statuses[] | select(.context == \"${context}\") | .state")
if [[ "${state}" == "pending" ]]; then
gh api -X POST "repos/${REPO}/statuses/${HEAD_SHA}" \
-f state=success -f context="${context}" -f description="Workflow runs approved" \
-f target_url="${STATUS_URL}" \
--silent
echo "${HEAD_SHA}: status turned green"
fi
# -f with GET encodes the branch into the query string. A PR pushed again after the run
# started has newer runs, which may wait, so it keeps its label.
prs=$(gh api -X GET --paginate "repos/${REPO}/pulls" \
-f state=open -f per_page=100 -f head="${HEAD_REPOSITORY%%/*}:${HEAD_BRANCH}" \
--jq ".[] | select(.head.sha == \"${HEAD_SHA}\")
| select(any(.labels[]; .name == \"${label}\")) | .number")
for number in ${prs}; do
gh api -X DELETE "repos/${REPO}/issues/${number}/labels/${label// /%20}" --silent
echo "#${number}: label removed"
done