jerryshao commented on code in PR #13049:
URL: https://github.com/apache/gravitino/pull/13049#discussion_r4056802300


##########
.github/workflows/fork-ci-status-update.yml:
##########
@@ -0,0 +1,111 @@
+# 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.
+
+name: Update Fork CI Status
+
+on:
+  schedule:
+    - cron: '*/15 * * * *'
+
+permissions:
+  actions: read
+  checks: write
+  pull-requests: read
+
+jobs:
+  update:
+    name: Update fork CI checks
+    if: github.repository == 'apache/gravitino'
+    runs-on: ubuntu-slim
+    steps:
+      - name: Synchronize fork CI checks
+        uses: actions/github-script@v7
+        with:
+          github-token: ${{ secrets.GITHUB_TOKEN }}
+          script: |
+            const prs = await github.paginate(
+              'GET /repos/{owner}/{repo}/pulls',
+              { owner: context.repo.owner, repo: context.repo.repo, state: 
'open', per_page: 100 });
+
+            for (const pr of prs) {
+              if (!pr.head.repo) continue;
+              const owner = pr.head.repo.owner.login;
+              const repo = pr.head.repo.name;
+              let runs;
+              try {
+                runs = await github.paginate(

Review Comment:
   This loop runs every 15 minutes over all open PRs and, per PR, does two 
unfiltered `github.paginate` calls: the fork's entire workflow-run history for 
that branch, and all check-runs on the upstream commit.
   
   `apache/gravitino` currently has ~263 open PRs, so that is at least ~526 
requests per cycle and ~2000+/hour, against a `GITHUB_TOKEN` quota of 1000 
requests per hour per repository. Once the quota is exhausted, the check-runs 
`paginate` on line 59 throws a 403 — it is outside the `try/catch` that wraps 
the workflow-runs call — and the whole loop aborts, so every PR after that 
point never gets its "Fork CI" check updated.
   
   On top of that this job runs on `ubuntu-slim`, which has a 15-minute hard 
limit; 263 PRs with pagination is unlikely to finish inside it.
   
   Suggestions: use the `head_sha` query parameter on the workflow-runs 
endpoint (drops the pagination entirely), wrap the check-runs call in 
`try/catch` too, and consider only processing PRs updated since the last cycle.



##########
.github/workflows/fork-ci.yml:
##########
@@ -0,0 +1,235 @@
+# 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.
+
+# Run the complete CI entry point from branch pushes in the contributor's 
repository.
+name: Fork CI
+
+on:
+  push:
+    branches: ['**']
+
+concurrency:
+  group: fork-ci-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  eligibility:
+    name: Resolve fork CI eligibility
+    # Downstream mirrors can set this repository variable to keep the
+    # inherited workflow completely dormant.
+    if: vars.DISABLE_FORK_CI != 'true'
+    runs-on: ubuntu-slim

Review Comment:
   **Blocking:** `ubuntu-slim` is an ASF org-level runner, not a GitHub-hosted 
label. The ASF infrastructure site documents it under "Use lightweight runners" 
(1 vCPU, 5GB RAM, no Docker engine, 15-minute hard limit), and it is only 
schedulable for repositories in the `apache` org.
   
   In a contributor's personal fork there is no runner with that label, so this 
job sits in "Waiting for a runner to pick up this job" until the 24h queue 
timeout. Since all 16 suites are `needs: eligibility`, Fork CI never executes 
in a fork at all, and the mirrored upstream "Fork CI" check stays 
`queued`/`action_required` forever — which defeats the purpose of the PR.
   
   Suggest `runs-on: ubuntu-latest` here. (`fork-ci-status.yml` and 
`fork-ci-status-update.yml` can keep `ubuntu-slim`, since both are guarded by 
`if: github.repository == 'apache/gravitino'` — though see the separate note 
about the 15-minute cap on the cron job.)



##########
.github/workflows/fork-ci-status.yml:
##########
@@ -0,0 +1,90 @@
+# 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.
+
+name: Fork CI Status
+
+on:
+  pull_request_target:
+    types: [opened, synchronize, reopened]
+
+permissions:
+  actions: read
+  checks: write
+
+jobs:
+  notify:
+    name: Notify fork CI
+    if: github.repository == 'apache/gravitino'
+    runs-on: ubuntu-slim
+    steps:
+      - name: Create fork CI check
+        uses: actions/github-script@v7
+        with:
+          github-token: ${{ secrets.GITHUB_TOKEN }}
+          script: |
+            const pr = context.payload.pull_request;
+            const owner = pr.head.repo.owner.login;
+            const repo = pr.head.repo.name;
+            const branch = pr.head.ref;
+            const headSha = pr.head.sha;
+            const workflow = 'fork-ci.yml';
+
+            let run;
+            for (let attempt = 0; attempt < 3 && !run; attempt++) {
+              if (attempt > 0) {
+                await new Promise(resolve => setTimeout(resolve, 3000));
+              }
+              try {
+                const runs = await github.paginate(
+                  'GET 
/repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs',
+                  { owner, repo, workflow_id: workflow, branch, per_page: 100 
});
+                run = runs.find(candidate => candidate.head_sha === headSha);
+              } catch (error) {
+                core.warning(`Unable to read fork Actions: ${error.message}`);
+              }
+            }
+
+            const detailsUrl = run
+              ? `https://github.com/${owner}/${repo}/actions/runs/${run.id}`
+              : 
`https://github.com/${owner}/${repo}/actions/workflows/${workflow}`;
+            const status = !run || run.status === 'completed' ? 'completed' : 
'queued';
+            const conclusion = run && run.status === 'completed'
+              ? run.conclusion
+              : (run ? undefined : 'action_required');

Review Comment:
   Worth documenting rather than changing: this mirrors `run.conclusion` from 
the fork straight into a check named "Fork CI", but `fork-ci.yml` is a file the 
contributor fully controls on their own branch.
   
   A contributor can replace it with a single `runs-on: ubuntu-latest` / `exit 
0` job and the upstream required check turns green with zero tests executed. 
The Spark model has the same property, but it relies on committers knowing it — 
so it would be good to say plainly in the PR description (and ideally in a 
contributor doc) that "Fork CI" is a self-attested result and that reviewers 
must open the linked fork run to confirm the suites actually ran.



##########
.github/workflows/build.yml:
##########
@@ -2,20 +2,10 @@ name: build
 
 # Controls when the workflow will run
 on:
-  # Triggers the workflow on push or pull request events but only for the 
"main" branch
-  push:
-    branches: [ "main", "branch-*" ]
-    paths-ignore:
-      - 'docs/assets/**'
-      - 'web-v2/**'
-  pull_request:
-    branches: [ "main", "branch-*" ]
-    paths-ignore:
-      - 'docs/assets/**'
-      - 'web-v2/**'
+  workflow_call:

Review Comment:
   All the suite workflows lose their `pull_request` / `push` triggers in this 
PR. The required status checks currently configured in `apache/gravitino`'s 
branch protection (`build / build`, `Backend Integration Test / ...`, etc.) 
will therefore never report again, and every open PR will sit at "Expected — 
Waiting for status to be reported" and be unmergeable until INFRA switches 
branch protection over to requiring only "Fork CI".
   
   That's a coordinated cutover rather than a code issue, but it isn't 
mentioned in the PR description — could you spell out the before/after 
branch-protection steps there (and in the linked issue), so whoever merges this 
knows what has to happen at the same time?



##########
.github/workflows/build.yml:
##########
@@ -216,36 +214,30 @@ jobs:
           ./gradlew "${gradle_args[@]}"
 
       - name: Fetch base branch for coverage diff
-        if: github.event_name == 'pull_request'
-        run: git fetch origin ${{ github.base_ref }} --depth=1
+        if: steps.build-checkout.outputs.synced == 'true'
+        run: git fetch origin ${{ steps.build-checkout.outputs.base-ref }} 
--depth=1
 
       - name: Generate Coverage Report
         id: coverage
-        if: github.event_name == 'pull_request'
+        if: steps.build-checkout.outputs.synced == 'true'
         run: |
           python3 dev/ci/jacoco_report.py \
-            --base-ref "${{ github.base_ref }}" \
-            --head-sha "${{ github.event.pull_request.head.sha }}" \
-            --repo-url "${{ github.event.pull_request.head.repo.html_url }}" \
+            --base-ref "${{ steps.build-checkout.outputs.base-ref }}" \
+            --head-sha "${{ github.sha }}" \
+            --repo-url "${{ github.server_url }}/${{ github.repository }}" \
             --min-overall 40 \
             --min-changed 60 \
             --output coverage-report.md
 
-      - name: Save PR number
-        if: github.event_name == 'pull_request' && 
steps.coverage.outputs.has_reports == 'true'
-        run: echo "${{ github.event.pull_request.number }}" > pr-number.txt
-
       - name: Upload Coverage Report
-        if: github.event_name == 'pull_request' && 
steps.coverage.outputs.has_reports == 'true'
+        if: steps.build-checkout.outputs.synced == 'true' && 
steps.coverage.outputs.has_reports == 'true'
         uses: actions/upload-artifact@v7
         with:
           name: coverage-report
-          path: |
-            coverage-report.md
-            pr-number.txt
+          path: coverage-report.md

Review Comment:
   **Blocking:** `pr-number.txt` is dropped from the artifact here, but 
`.github/workflows/coverage-comment.yml` is not touched by this PR and still 
does `fs.readFileSync('pr-number.txt', 'utf8')`.
   
   More fundamentally, that workflow triggers on `workflow_run: workflows: 
["build"]`. With `build.yml` reduced to `workflow_call` only, it runs as a set 
of jobs inside the caller's run and never produces its own workflow run, so the 
`workflow_run` event can never fire again — the coverage comment feature goes 
away silently.
   
   And even if the trigger were fixed, the artifact is now produced in the 
contributor's fork run, which upstream `actions/download-artifact` cannot reach.
   
   Either adapt `coverage-comment.yml` (pull the artifact from the fork run, 
recover the PR number from the check/API) or state explicitly in the PR 
description that coverage comments are being retired.



##########
.github/workflows/asf-allowlist-check.yml:
##########
@@ -40,6 +33,7 @@ jobs:
       - uses: actions/checkout@v4
         with:
           persist-credentials: false
+      - uses: ./.github/actions/checkout-and-sync

Review Comment:
   The `persist-credentials: false` two lines above is deliberate, but this 
composite runs another `actions/checkout@v4` internally 
(`.github/actions/checkout-and-sync/action.yml`) without that option, so the 
token gets written back into `.git/config` as an `http.extraheader`.
   
   That means `apache/infrastructure-actions/allowlist-check@main` then runs 
against a workspace carrying credentials — exactly what the original step was 
avoiding. Either set `persist-credentials: false` on the composite's checkout, 
or add a pass-through input for it.



##########
.github/workflows/fork-ci-status.yml:
##########
@@ -0,0 +1,90 @@
+# 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.
+
+name: Fork CI Status
+
+on:
+  pull_request_target:
+    types: [opened, synchronize, reopened]
+
+permissions:
+  actions: read
+  checks: write
+
+jobs:
+  notify:
+    name: Notify fork CI
+    if: github.repository == 'apache/gravitino'
+    runs-on: ubuntu-slim
+    steps:
+      - name: Create fork CI check
+        uses: actions/github-script@v7
+        with:
+          github-token: ${{ secrets.GITHUB_TOKEN }}
+          script: |
+            const pr = context.payload.pull_request;
+            const owner = pr.head.repo.owner.login;

Review Comment:
   `pr.head.repo` can be `null` when the head fork has been deleted. 
`fork-ci-status-update.yml:45` guards this with `if (!pr.head.repo) continue;`, 
but here it is dereferenced directly.
   
   On a `reopened` event for a PR whose fork is gone, github-script throws 
`TypeError: Cannot read properties of null`, the job fails with a red X 
unrelated to the contributor's code, and no "Fork CI" check is created at all.



##########
.github/workflows/asf-allowlist-check.yml:
##########
@@ -20,15 +20,8 @@
 name: "ASF Allowlist Check"
 
 on:
+  workflow_call:

Review Comment:
   Dropping `pull_request` (and `push` to `main`) means the INFRA 
action-allowlist gate no longer runs in `apache/gravitino` at all — only inside 
a contributor's fork via Fork CI, or manually via `workflow_dispatch`.
   
   Combined with the self-attestation point on `fork-ci-status.yml`, a PR that 
introduces an unpinned or non-allowlisted third-party action could land without 
the upstream check ever having run.
   
   This workflow is very cheap (a glob scan, no build), so it doesn't really 
belong to the load that needs to move off ASF runners. Suggest keeping the 
upstream `pull_request` trigger for this one.



##########
.github/workflows/fork-ci.yml:
##########
@@ -0,0 +1,235 @@
+# 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.
+
+# Run the complete CI entry point from branch pushes in the contributor's 
repository.
+name: Fork CI
+
+on:
+  push:
+    branches: ['**']
+
+concurrency:
+  group: fork-ci-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  eligibility:
+    name: Resolve fork CI eligibility
+    # Downstream mirrors can set this repository variable to keep the
+    # inherited workflow completely dormant.
+    if: vars.DISABLE_FORK_CI != 'true'
+    runs-on: ubuntu-slim
+    outputs:
+      applicable: ${{ steps.resolve.outputs.applicable }}
+      valid: ${{ steps.resolve.outputs.valid }}
+    steps:
+      - name: Resolve repository and pull request
+        id: resolve
+        env:
+          GH_TOKEN: ${{ github.token }}
+          HEAD_BRANCH: ${{ github.ref_name }}
+          HEAD_OWNER: ${{ github.repository_owner }}
+          HEAD_REPOSITORY: ${{ github.repository }}
+          HEAD_SHA: ${{ github.sha }}
+        run: |
+          set -euo pipefail
+
+          echo "applicable=false" >> "${GITHUB_OUTPUT}"
+          echo "valid=false" >> "${GITHUB_OUTPUT}"
+
+          if [[ "${HEAD_REPOSITORY}" == "apache/gravitino" && \
+            ("${GITHUB_REF}" == "refs/heads/main" || "${GITHUB_REF}" == 
refs/heads/branch-*) ]]; then
+            echo "applicable=true" >> "${GITHUB_OUTPUT}"
+            echo "base_ref=${GITHUB_REF_NAME}" >> "${GITHUB_OUTPUT}"
+            echo "valid=true" >> "${GITHUB_OUTPUT}"
+            exit 0
+          fi
+
+          repository_response="$(curl --fail-with-body --silent --show-error \
+            --header "Accept: application/vnd.github+json" \
+            --header "Authorization: Bearer ${GH_TOKEN}" \
+            --header "X-GitHub-Api-Version: 2022-11-28" \
+            "${GITHUB_API_URL}/repos/${HEAD_REPOSITORY}")"
+          source_repository="$(jq -r '.source.full_name // empty' <<< 
"${repository_response}")"
+
+          if [[ "${HEAD_REPOSITORY}" != "apache/gravitino" && \
+            "${source_repository}" != "apache/gravitino" ]]; then
+            echo "This repository is not in the apache/gravitino fork network; 
Fork CI is dormant."
+            exit 0
+          fi
+
+          echo "applicable=true" >> "${GITHUB_OUTPUT}"
+          matches="[]"
+          match_count=0
+          for attempt in 1 2 3; do
+            response="$(curl --fail-with-body --silent --show-error \
+              --header "Accept: application/vnd.github+json" \
+              --header "Authorization: Bearer ${GH_TOKEN}" \
+              --header "X-GitHub-Api-Version: 2022-11-28" \
+              --get \
+              --data-urlencode "state=open" \
+              --data-urlencode "head=${HEAD_OWNER}:${HEAD_BRANCH}" \
+              --data-urlencode "per_page=10" \
+              "https://api.github.com/repos/apache/gravitino/pulls";)"
+            matches="$(jq -r \
+              --arg head_sha "${HEAD_SHA}" \
+              --arg head_repository "${HEAD_REPOSITORY}" \
+              '[.[] | select(.head.sha == $head_sha and .head.repo.full_name 
== $head_repository)]' \
+              <<< "${response}")"
+            match_count="$(jq -r 'length' <<< "${matches}")"
+            if [[ "${match_count}" == "1" ]]; then
+              break
+            fi
+            if [[ "${attempt}" != "3" ]]; then
+              sleep 3
+            fi
+          done
+
+          if [[ "${match_count}" != "1" ]]; then
+            echo "::error::Expected one open apache/gravitino pull request for 
${HEAD_REPOSITORY}:${HEAD_BRANCH} at ${HEAD_SHA}, found ${match_count}."
+            exit 0
+          fi
+
+          echo "base_ref=$(jq -r '.[0].base.ref' <<< "${matches}")" >> 
"${GITHUB_OUTPUT}"
+          echo "valid=true" >> "${GITHUB_OUTPUT}"
+
+      - name: Reject an unmatched Apache fork branch

Review Comment:
   **Blocking:** when no single matching open PR is found, the resolve step 
writes `applicable=true, valid=false` and `exit 0`, and this step then fails 
the whole run.
   
   That makes the ordinary contributor flow fail by construction:
   
   - The normal sequence is *push branch to fork*, **then** *open the PR*. At 
push time there is no open PR upstream, so `match_count=0` → red X plus a 
failure email. Opening the PR does not emit a new `push` event, so Fork CI 
never re-runs — `fork-ci-status.yml` mirrors that failed run to the upstream 
check, and the contributor has to push an empty commit to recover.
   - A contributor syncing their fork's `main` from upstream pushes to 
`fork/main`, which has no PR → red X on every fork sync.
   - Upstream is affected too: `cherry-pick-branch.yml:93` does `git push 
origin cherry-pick-...` and only creates the PR in a later step, so every 
automated cherry-pick produces a failing Fork CI run on `apache/gravitino`.
   
   Could this be a no-op instead (exit success, suites skipped) when no PR is 
found, so only genuinely broken states are reported as failures?



##########
.github/actions/checkout-and-sync/action.yml:
##########
@@ -0,0 +1,150 @@
+# 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.
+
+name: Checkout and sync
+description: Check out the upstream base branch and merge the contributor 
branch for fork CI.
+
+outputs:
+  base-ref:
+    description: Upstream branch used as the comparison base.
+    value: ${{ steps.base.outputs.base_ref }}
+  base-sha:
+    description: Upstream commit checked out before merging contributor 
changes.
+    value: ${{ steps.upstream.outputs.base_sha }}
+  head-sha:
+    description: Commit tested after contributor changes are merged.
+    value: ${{ steps.head.outputs.head_sha }}
+  synced:
+    description: Whether contributor changes were merged onto the upstream 
base.
+    value: ${{ steps.base.outputs.should_sync }}
+
+runs:
+  using: composite
+  steps:
+    - name: Resolve pull request base branch
+      id: base
+      shell: bash
+      env:
+        EVENT_BASE_REF: ${{ github.base_ref }}
+        GH_TOKEN: ${{ github.token }}
+        HEAD_OWNER: ${{ github.repository_owner }}
+        HEAD_BRANCH: ${{ github.ref_name }}
+        HEAD_REPOSITORY: ${{ github.repository }}
+        HEAD_SHA: ${{ github.sha }}
+      run: |
+        set -euo pipefail
+
+        if [[ "${GITHUB_REPOSITORY}" == "apache/gravitino" && \
+          ("${GITHUB_REF}" == "refs/heads/main" || "${GITHUB_REF}" == 
refs/heads/branch-*) ]]; then
+          echo "base_ref=${GITHUB_REF_NAME}" >> "${GITHUB_OUTPUT}"
+          echo "should_sync=false" >> "${GITHUB_OUTPUT}"
+          exit 0
+        fi
+
+        repository_response="$(curl --fail-with-body --silent --show-error \
+          --header "Accept: application/vnd.github+json" \
+          --header "Authorization: Bearer ${GH_TOKEN}" \
+          --header "X-GitHub-Api-Version: 2022-11-28" \
+          "${GITHUB_API_URL}/repos/${HEAD_REPOSITORY}")"
+        source_repository="$(jq -r '.source.full_name // empty' <<< 
"${repository_response}")"
+
+        if [[ "${HEAD_REPOSITORY}" != "apache/gravitino" && \
+          "${source_repository}" != "apache/gravitino" ]]; then
+          echo "base_ref=${EVENT_BASE_REF:-${GITHUB_REF_NAME}}" >> 
"${GITHUB_OUTPUT}"
+          echo "should_sync=false" >> "${GITHUB_OUTPUT}"
+          exit 0
+        fi
+
+        response="[]"
+        match_count=0
+        for attempt in 1 2 3; do
+          response="$(curl --fail-with-body --silent --show-error \
+            --header "Accept: application/vnd.github+json" \
+            --header "Authorization: Bearer ${GH_TOKEN}" \
+            --header "X-GitHub-Api-Version: 2022-11-28" \
+            --get \
+            --data-urlencode "state=open" \
+            --data-urlencode "head=${HEAD_OWNER}:${HEAD_BRANCH}" \
+            --data-urlencode "per_page=10" \
+            "https://api.github.com/repos/apache/gravitino/pulls";)"
+          match_count="$(jq -r \
+            --arg head_sha "${HEAD_SHA}" \
+            --arg head_repository "${HEAD_REPOSITORY}" \
+            '[.[] | select(.head.sha == $head_sha and .head.repo.full_name == 
$head_repository)]
+             | length' \
+            <<< "${response}")"
+          if [[ "${match_count}" == "1" ]]; then
+            break
+          fi
+          if [[ "${attempt}" != "3" ]]; then
+            sleep 3
+          fi
+        done
+
+        if [[ "${match_count}" != "1" ]]; then

Review Comment:
   This composite is added to roughly 60 jobs once the backend/spark/flink 
matrices expand, and each one independently re-queries GitHub for "exactly one 
open PR matching this head SHA", failing with `exit 1` if it doesn't find it.
   
   Two consequences:
   
   - A full Fork CI run takes tens of minutes to hours. If the PR is closed or 
merged in the meantime, jobs scheduled after that point fail with `Expected one 
open apache/gravitino pull request ... found 0`, and Required CI goes red for a 
reason unrelated to the code.
   - Each job merges the contributor branch onto whatever the base branch tip 
is *at that moment*, so different suites in the same run can be testing 
different trees when the base branch moves.
   
   Would it work to resolve `base_ref` / `base_sha` once in the `eligibility` 
job and pass them to each suite through `workflow_call` inputs, leaving the 
composite responsible only for checkout + merge? That also cuts the API traffic 
by ~60x.



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

Reply via email to