potiuk commented on code in PR #74822: URL: https://github.com/apache/airflow/pull/74822#discussion_r4304446705
########## .github/workflows/fork-ci-monitor.yml: ########## @@ -0,0 +1,71 @@ +# 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. +# +--- +# Drives pull requests whose CI runs in contributor forks (AIP-120): labels, draft state, the +# state comment, the `Fork CI / Tests (AMD)` commit status and closing. It is the only writer for +# those pull requests and never checks out or runs pull request code. See +# dev/breeze/doc/ci/08_fork_ci_for_external_contributors.md. +name: "Fork CI monitor" +on: # yamllint disable-line rule:truthy + schedule: + - cron: '*/15 * * * *' + workflow_dispatch: + inputs: + dry-run: + description: "Compute the changes without applying them to pull requests" + type: boolean + default: false +permissions: Review Comment: It doesn't: every scope a `permissions` block leaves out is `none`, so the runs and jobs listings would fail. Added `actions: read` with a comment, and the design doc lists it. Fixed in 9c0975d413. --- Drafted-by: Claude Code (Opus 5); reviewed by @potiuk before posting ########## .github/workflows/fork-ci-monitor.yml: ########## @@ -0,0 +1,71 @@ +# 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. +# +--- +# Drives pull requests whose CI runs in contributor forks (AIP-120): labels, draft state, the +# state comment, the `Fork CI / Tests (AMD)` commit status and closing. It is the only writer for +# those pull requests and never checks out or runs pull request code. See +# dev/breeze/doc/ci/08_fork_ci_for_external_contributors.md. +name: "Fork CI monitor" +on: # yamllint disable-line rule:truthy + schedule: + - cron: '*/15 * * * *' + workflow_dispatch: + inputs: + dry-run: + description: "Compute the changes without applying them to pull requests" + type: boolean + default: false +permissions: + contents: read + # Labels, draft state, comments and closing of gated pull requests. + pull-requests: write + # The `Fork CI / Tests (AMD)` commit status on pull request head commits. + statuses: write +concurrency: + group: fork-ci-monitor + cancel-in-progress: false + +jobs: + reconcile: + name: "Reconcile pull requests gated to fork CI" + if: github.repository == 'apache/airflow' + # The breeze action frees disk space with sudo and docker, which ubuntu-slim does not provide. + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - name: "Checkout main" + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: main + persist-credentials: false + - name: "Install Breeze" + uses: ./.github/actions/breeze + - name: "Reconcile" + id: reconcile + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DRY_RUN: ${{ inputs.dry-run && 'true' || 'false' }} Review Comment: Fixed in 9c0975d413. The Slack step now also requires `!inputs.dry-run`, since a dry run's alerts describe changes it didn't make. --- Drafted-by: Claude Code (Opus 5); reviewed by @potiuk before posting ########## .github/workflows/fork-ci-monitor.yml: ########## @@ -0,0 +1,71 @@ +# 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. +# +--- +# Drives pull requests whose CI runs in contributor forks (AIP-120): labels, draft state, the +# state comment, the `Fork CI / Tests (AMD)` commit status and closing. It is the only writer for +# those pull requests and never checks out or runs pull request code. See +# dev/breeze/doc/ci/08_fork_ci_for_external_contributors.md. +name: "Fork CI monitor" +on: # yamllint disable-line rule:truthy + schedule: + - cron: '*/15 * * * *' + workflow_dispatch: + inputs: + dry-run: + description: "Compute the changes without applying them to pull requests" + type: boolean + default: false +permissions: + contents: read + # Labels, draft state, comments and closing of gated pull requests. + pull-requests: write + # The `Fork CI / Tests (AMD)` commit status on pull request head commits. + statuses: write +concurrency: + group: fork-ci-monitor + cancel-in-progress: false + +jobs: + reconcile: + name: "Reconcile pull requests gated to fork CI" + if: github.repository == 'apache/airflow' + # The breeze action frees disk space with sudo and docker, which ubuntu-slim does not provide. + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - name: "Checkout main" + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: main + persist-credentials: false + - name: "Install Breeze" + uses: ./.github/actions/breeze + - name: "Reconcile" + id: reconcile + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DRY_RUN: ${{ inputs.dry-run && 'true' || 'false' }} + RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + run: breeze ci fork-ci-reconcile --output-file slack-message.json + - name: "Post to Slack" + if: steps.reconcile.outputs.has-alerts == 'true' Review Comment: Added a second Slack step with `if: failure() && !inputs.dry-run` that posts a link to the failed run. 9c0975d413. --- Drafted-by: Claude Code (Opus 5); reviewed by @potiuk before posting ########## dev/breeze/src/airflow_breeze/utils/fork_ci_github.py: ########## @@ -0,0 +1,170 @@ +# 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. +"""GitHub access for the fork CI reconciler (AIP-120); the only module of it that calls ``gh``.""" + +from __future__ import annotations + +import json +import subprocess +import time +from collections import Counter +from collections.abc import Sequence +from typing import Any +from urllib.parse import quote + +from airflow_breeze.utils.console import console_print +from airflow_breeze.utils.fork_ci_messages import STATUS_CONTEXT + +RATE_LIMIT_MARKERS = ("rate limit", "secondary rate", "abuse detection") +MAX_ATTEMPTS = 4 + + +class GitHubError(RuntimeError): + """A GitHub API call failed for a reason other than a rate limit.""" + + +class GitHubClient: + def __init__(self, repo: str = "apache/airflow", *, dry_run: bool = False): + self.repo = repo + self.dry_run = dry_run + self.calls: Counter[str] = Counter() + + def _gh(self, args: Sequence[str], body: dict[str, Any] | None, kind: str) -> Any: + payload = json.dumps(body) if body is not None else None + for attempt in range(MAX_ATTEMPTS): + self.calls[kind] += 1 + result = subprocess.run( + ["gh", *args, *(["--input", "-"] if payload is not None else [])], + input=payload, + capture_output=True, + text=True, + check=False, + ) + if result.returncode == 0: + return json.loads(result.stdout) if result.stdout.strip() else None + if any(marker in result.stderr.lower() for marker in RATE_LIMIT_MARKERS): + wait = 30 * 2**attempt Review Comment: Both fixed in 9c0975d413. The last attempt no longer sleeps before raising, and every `gh` call has `timeout=120`, with a timeout raised as `GitHubError` so the run reports it. Tests for both. --- Drafted-by: Claude Code (Opus 5); reviewed by @potiuk before posting -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
