This is an automated email from the ASF dual-hosted git repository.
Yicong-Huang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/texera.git
The following commit(s) were added to refs/heads/main by this push:
new 7d3b55bd3b refactor(ci): consolidate Build matrix into a single
reusable workflow (#4624)
7d3b55bd3b is described below
commit 7d3b55bd3b02a4420f428b8b275664911c15d073
Author: Yicong Huang <[email protected]>
AuthorDate: Fri May 1 16:14:42 2026 -0700
refactor(ci): consolidate Build matrix into a single reusable workflow
(#4624)
### What changes were proposed in this PR?
The Build matrix jobs (`frontend`, `scala`, `python`, `agent-service`)
were duplicated between `github-action-build.yml` and
`reusable-build.yml`, and the two had drifted — `reusable-build.yml` was
missing the recent license-check additions (npm bundle check,
pip-licenses manifest, bundled-jar diff against LICENSE-binary,
agent-service license manifest). Net change: **+238 / −416** lines.
- Rename `reusable-build.yml` → `build.yml` (workflow name `Build`). It
is now the single source of truth for the matrix steps, with the
license-check additions ported in.
- Rename `github-action-build.yml` → `required-checks.yml` (workflow
name `Required Checks`). Replace the four inline matrix jobs with a
single `build:` caller that `uses: ./.github/workflows/build.yml`. The
`backport:` caller is unchanged; the `Required Checks` aggregator job's
`needs:` shrinks from `[precheck, frontend, scala, python,
agent-service, backport]` to `[precheck, build, backport]`.
- Update `direct-backport-push.yml`'s `workflow_id` reference to the new
filename.
`.asf.yaml` continues to require only `Required Checks`, so the
display-name change (matrix children gain a `build /` prefix) does not
affect branch protection.
### Any related issues, documentation, discussions?
Closes #4623
### How was this PR tested?
YAML parses locally for all three modified workflow files. Step parity
between the new `build.yml` and the previous inline
`github-action-build.yml` matrix jobs verified by side-by-side diff. The
job will be exercised on this PR itself; matrix children appear under
`Required Checks / build / …` and the `backport:` matrix continues to
appear under `Required Checks / backport (...) / …`.
### Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Opus 4.7)
---------
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
---
.../workflows/{reusable-build.yml => build.yml} | 63 +++-
.github/workflows/direct-backport-push.yml | 2 +-
.github/workflows/github-action-build.yml | 411 ---------------------
.github/workflows/required-checks.yml | 178 +++++++++
4 files changed, 238 insertions(+), 416 deletions(-)
diff --git a/.github/workflows/reusable-build.yml b/.github/workflows/build.yml
similarity index 75%
rename from .github/workflows/reusable-build.yml
rename to .github/workflows/build.yml
index 3e34206f90..4e1b431169 100644
--- a/.github/workflows/reusable-build.yml
+++ b/.github/workflows/build.yml
@@ -15,7 +15,7 @@
# specific language governing permissions and limitations
# under the License.
-name: Reusable Build
+name: Build
on:
workflow_call:
@@ -105,10 +105,13 @@ jobs:
run: yarn --cwd frontend install --immutable --inline-builds
--network-timeout=100000
- name: Lint with Prettier & ESLint
run: yarn --cwd frontend format:ci
- - name: Run frontend unit tests
- run: yarn --cwd frontend run test:ci
- name: Prod build
run: yarn --cwd frontend run build:ci
+ - name: Check bundled npm packages against LICENSE-binary
+ if: matrix.os == 'ubuntu-latest'
+ run: ./bin/licensing/check_binary_deps.py npm
frontend/dist/3rdpartylicenses.json
+ - name: Run frontend unit tests
+ run: yarn --cwd frontend run test:ci
scala:
if: ${{ inputs.run_scala }}
@@ -173,6 +176,41 @@ jobs:
psql -h localhost -U postgres -f sql/texera_lakefs.sql
env:
PGPASSWORD: postgres
+ - name: Build distributable bundles for license check
+ # Build every dist-producing module so the union of bundled jars can
+ # be diffed against LICENSE-binary.
+ run: sbt 'clean; ConfigService/dist; AccessControlService/dist;
FileService/dist; ComputingUnitManagingService/dist;
WorkflowCompilingService/dist; WorkflowExecutionService/dist'
+ - name: Unzip JVM distributable bundles
+ run: |
+ mkdir -p /tmp/dists
+ for zip in \
+ config-service/target/universal/config-service-*.zip \
+
access-control-service/target/universal/access-control-service-*.zip \
+ file-service/target/universal/file-service-*.zip \
+
computing-unit-managing-service/target/universal/computing-unit-managing-service-*.zip
\
+
workflow-compiling-service/target/universal/workflow-compiling-service-*.zip \
+ amber/target/universal/amber-*.zip; do
+ unzip -q "$zip" -d /tmp/dists/
+ done
+ - name: Check bundled jars against LICENSE-binary
+ run: |
+ ./bin/licensing/check_binary_deps.py jar \
+ /tmp/dists/config-service-*/lib \
+ /tmp/dists/access-control-service-*/lib \
+ /tmp/dists/file-service-*/lib \
+ /tmp/dists/computing-unit-managing-service-*/lib \
+ /tmp/dists/workflow-compiling-service-*/lib \
+ /tmp/dists/amber-*/lib
+ - name: Audit per-dep license preservation (advisory)
+ if: always()
+ run: |
+ ./bin/licensing/audit_jar_licenses.py \
+ /tmp/dists/config-service-*/lib \
+ /tmp/dists/access-control-service-*/lib \
+ /tmp/dists/file-service-*/lib \
+ /tmp/dists/computing-unit-managing-service-*/lib \
+ /tmp/dists/workflow-compiling-service-*/lib \
+ /tmp/dists/amber-*/lib
- name: Create texera_db_for_test_cases
run: psql -h localhost -U postgres -v DB_NAME=texera_db_for_test_cases
-f sql/texera_ddl.sql
env:
@@ -214,6 +252,13 @@ jobs:
python -m pip install --upgrade pip
if [ -f amber/requirements.txt ]; then pip install -r
amber/requirements.txt; fi
if [ -f amber/operator-requirements.txt ]; then pip install -r
amber/operator-requirements.txt; fi
+ if [ "${{ matrix.python-version }}" = "3.12" ]; then pip install
pip-licenses; fi
+ - name: Generate pip-licenses manifest
+ if: matrix.python-version == '3.12'
+ run: pip-licenses --format=csv --ignore-packages pip-licenses
prettytable wcwidth > /tmp/pip-licenses.csv
+ - name: Check installed Python packages against LICENSE-binary
+ if: matrix.python-version == '3.12'
+ run: ./bin/licensing/check_binary_deps.py python /tmp/pip-licenses.csv
- name: Install PostgreSQL
run: sudo apt-get update && sudo apt-get install -y postgresql
- name: Start PostgreSQL Service
@@ -254,7 +299,17 @@ jobs:
run: |
curl -fsSL https://bun.sh/install | bash -s -- bun-v${{
matrix.bun-version }}
echo "$HOME/.bun/bin" >> $GITHUB_PATH
- - name: Install dependencies
+ - name: Install production dependencies
+ run: bun install --production --frozen-lockfile
+ - name: Generate agent-service license manifest
+ if: matrix.os == 'ubuntu-latest'
+ run: |
+ mkdir -p dist
+ bun run bin/collect-licenses.ts > dist/3rdpartylicenses.json
+ - name: Check bundled agent-service packages against LICENSE-binary
+ if: matrix.os == 'ubuntu-latest'
+ run: ../bin/licensing/check_binary_deps.py agent-npm
dist/3rdpartylicenses.json
+ - name: Install development dependencies
run: bun install --frozen-lockfile
- name: Lint with Prettier
run: bun run format:check
diff --git a/.github/workflows/direct-backport-push.yml
b/.github/workflows/direct-backport-push.yml
index 37fbe04ce4..c291fc1887 100644
--- a/.github/workflows/direct-backport-push.yml
+++ b/.github/workflows/direct-backport-push.yml
@@ -129,7 +129,7 @@ jobs:
{
owner,
repo,
- workflow_id: "github-action-build.yml",
+ workflow_id: "required-checks.yml",
head_sha: pullRequest.head.sha,
per_page: 100,
}
diff --git a/.github/workflows/github-action-build.yml
b/.github/workflows/github-action-build.yml
deleted file mode 100644
index 5d5bacfe01..0000000000
--- a/.github/workflows/github-action-build.yml
+++ /dev/null
@@ -1,411 +0,0 @@
-# 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: Build
-
-env:
- NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
-
-on:
- push:
- branches:
- - 'ci-enable/**'
- - 'main'
- - 'release/**'
- pull_request:
- types:
- - opened
- - reopened
- - synchronize
- - labeled
- - unlabeled
- workflow_dispatch:
-
-permissions:
- checks: write
- contents: read
- pull-requests: read
-
-concurrency:
- group: ${{ github.workflow }}-${{ github.ref }}
- cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
-
-jobs:
- # Precheck decides which downstream jobs run for this event:
- # - run_frontend / run_scala / run_python / run_agent_service: gate the
- # main build stacks. All true today; placeholder for future path- or
- # label-based selection.
- # - backport_targets: JSON array of release/* labels currently on the PR.
- # Drives the backport matrix; empty array means no backport runs.
- precheck:
- name: Precheck
- runs-on: ubuntu-latest
- outputs:
- run_frontend: ${{ steps.decide.outputs.run_frontend }}
- run_scala: ${{ steps.decide.outputs.run_scala }}
- run_python: ${{ steps.decide.outputs.run_python }}
- run_agent_service: ${{ steps.decide.outputs.run_agent_service }}
- backport_targets: ${{ steps.decide.outputs.backport_targets }}
- steps:
- - name: Decide which jobs to run
- id: decide
- uses: actions/github-script@v8
- with:
- script: |
- const eventName = context.eventName;
-
- // Main build stacks: always run.
- const stacks = ["run_frontend", "run_scala", "run_python",
"run_agent_service"];
- for (const key of stacks) {
- core.setOutput(key, "true");
- }
-
- // Backport targets: all current release/* labels on the PR.
- let targets = [];
- if (eventName === "pull_request") {
- const labels = context.payload.pull_request.labels.map((l) =>
l.name);
- targets = [...new Set(labels.filter((n) =>
/^release\/.+$/.test(n)))].sort();
- }
-
- if (targets.length === 0) {
- core.info(`No backport targets on PR.`);
- } else {
- core.info(`Backport targets: ${targets.join(", ")}`);
- }
- core.setOutput("backport_targets", JSON.stringify(targets));
-
- cleanup-stale-backport:
- if: ${{ github.event_name == 'pull_request' && github.event.action ==
'unlabeled' && startsWith(github.event.label.name, 'release/') }}
- runs-on: ubuntu-latest
- steps:
- - name: Cancel obsolete backport check_runs for the removed target
- uses: actions/github-script@v8
- with:
- script: |
- const { owner, repo } = context.repo;
- const target = context.payload.label.name;
- const headSha = context.payload.pull_request.head.sha;
- const prefix = `backport (${target}) `;
-
- const checks = await github.paginate(
- github.rest.checks.listForRef,
- { owner, repo, ref: headSha, per_page: 100 }
- );
-
- for (const check of checks) {
- if (!check.name.startsWith(prefix)) continue;
- if (check.status === "completed" && check.conclusion ===
"cancelled") continue;
- try {
- await github.rest.checks.update({
- owner,
- repo,
- check_run_id: check.id,
- status: "completed",
- conclusion: "cancelled",
- });
- core.info(`Cancelled check ${check.name}`);
- } catch (e) {
- core.warning(`Failed to update check ${check.id}
(${check.name}): ${e.message}`);
- }
- }
-
- frontend:
- needs: precheck
- if: ${{ needs.precheck.outputs.run_frontend == 'true' }}
- name: frontend (${{ matrix.os }}, 18)
- runs-on: ${{ matrix.os }}
- strategy:
- matrix:
- os: [ubuntu-latest, windows-latest, macos-latest]
- include:
- - os: macos-latest
- arch: arm64
- - os: ubuntu-latest
- arch: x64
- - os: windows-latest
- arch: x64
- node-version:
- - 20.19.0
- steps:
- - name: Checkout Texera
- uses: actions/checkout@v5
- - name: Setup node
- uses: actions/setup-node@v5
- with:
- node-version: ${{ matrix.node-version }}
- architecture: ${{ matrix.arch }}
- - uses: actions/cache@v4
- with:
- path: frontend/.yarn/cache
- key: ${{ runner.os }}-${{ matrix.arch }}-${{ matrix.node-version
}}-yarn-cache-v4-${{ hashFiles('**/yarn.lock') }}
- restore-keys: |
- ${{ runner.os }}-${{ matrix.arch }}-${{ matrix.node-version
}}-yarn-cache-v4-
- - name: Prepare Yarn 4.14.1
- run: corepack enable && corepack prepare [email protected] --activate
- - name: Setup Python
- uses: actions/setup-python@v6
- with:
- python-version: '3.12'
- - name: Install dependency
- timeout-minutes: 20
- run: yarn --cwd frontend install --immutable --inline-builds
--network-timeout=100000
- - name: Lint with Prettier & ESLint
- run: yarn --cwd frontend format:ci
- - name: Prod build
- run: yarn --cwd frontend run build:ci
- - name: Check bundled npm packages against LICENSE-binary
- if: matrix.os == 'ubuntu-latest'
- run: ./bin/licensing/check_binary_deps.py npm
frontend/dist/3rdpartylicenses.json
- - name: Run frontend unit tests
- run: yarn --cwd frontend run test:ci
-
- scala:
- needs: precheck
- if: ${{ needs.precheck.outputs.run_scala == 'true' }}
- strategy:
- matrix:
- os: [ ubuntu-22.04 ]
- java-version: [ 11 ]
- runs-on: ${{ matrix.os }}
- env:
- JAVA_OPTS: -Xms2048M -Xmx2048M -Xss6M -XX:ReservedCodeCacheSize=256M
-Dfile.encoding=UTF-8
- JVM_OPTS: -Xms2048M -Xmx2048M -Xss6M -XX:ReservedCodeCacheSize=256M
-Dfile.encoding=UTF-8
-
- services:
- postgres:
- image: postgres
- env:
- POSTGRES_PASSWORD: postgres
- ports:
- - 5432:5432
- # Add a health check so steps wait until Postgres is ready
- options: >-
- --health-cmd="pg_isready -U postgres"
- --health-interval=10s
- --health-timeout=5s
- --health-retries=5
- steps:
- - name: Checkout
- uses: actions/checkout@v5
- - name: Setup JDK
- uses: actions/setup-java@v5
- with:
- distribution: 'temurin'
- java-version: 11
- - name: Setup Python for Scala tests
- uses: actions/setup-python@v6
- with:
- python-version: '3.11'
- - name: Show Python
- run: python --version || python3 --version
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- if [ -f amber/requirements.txt ]; then pip install -r
amber/requirements.txt; fi
- if [ -f amber/operator-requirements.txt ]; then pip install -r
amber/operator-requirements.txt; fi
- - name: Setup sbt launcher
- uses: sbt/setup-sbt@508b753e53cb6095967669e0911487d2b9bc9f41 # v1.1.22
- - uses: coursier/cache-action@90c37294538be80a558fd665531fcdc2b467b475 #
v8.1.0
- with:
- extraSbtFiles: '["*.sbt", "project/**.{scala,sbt}",
"project/build.properties" ]'
- - name: Lint with scalafmt
- run: sbt scalafmtCheckAll
- - name: Create Databases
- run: |
- psql -h localhost -U postgres -f sql/texera_ddl.sql
- psql -h localhost -U postgres -f sql/iceberg_postgres_catalog.sql
- psql -h localhost -U postgres -f sql/texera_lakefs.sql
- env:
- PGPASSWORD: postgres
- - name: Build distributable bundles for license check
- # Build every dist-producing module so the union of bundled jars can
- # be diffed against LICENSE-binary.
- run: sbt 'clean; ConfigService/dist; AccessControlService/dist;
FileService/dist; ComputingUnitManagingService/dist;
WorkflowCompilingService/dist; WorkflowExecutionService/dist'
- - name: Unzip JVM distributable bundles
- run: |
- mkdir -p /tmp/dists
- for zip in \
- config-service/target/universal/config-service-*.zip \
-
access-control-service/target/universal/access-control-service-*.zip \
- file-service/target/universal/file-service-*.zip \
-
computing-unit-managing-service/target/universal/computing-unit-managing-service-*.zip
\
-
workflow-compiling-service/target/universal/workflow-compiling-service-*.zip \
- amber/target/universal/amber-*.zip; do
- unzip -q "$zip" -d /tmp/dists/
- done
- - name: Check bundled jars against LICENSE-binary
- run: |
- ./bin/licensing/check_binary_deps.py jar \
- /tmp/dists/config-service-*/lib \
- /tmp/dists/access-control-service-*/lib \
- /tmp/dists/file-service-*/lib \
- /tmp/dists/computing-unit-managing-service-*/lib \
- /tmp/dists/workflow-compiling-service-*/lib \
- /tmp/dists/amber-*/lib
- - name: Audit per-dep license preservation (advisory)
- if: always()
- run: |
- ./bin/licensing/audit_jar_licenses.py \
- /tmp/dists/config-service-*/lib \
- /tmp/dists/access-control-service-*/lib \
- /tmp/dists/file-service-*/lib \
- /tmp/dists/computing-unit-managing-service-*/lib \
- /tmp/dists/workflow-compiling-service-*/lib \
- /tmp/dists/amber-*/lib
- - name: Create texera_db_for_test_cases
- run: psql -h localhost -U postgres -v DB_NAME=texera_db_for_test_cases
-f sql/texera_ddl.sql
- env:
- PGPASSWORD: postgres
- - name: Compile with sbt
- run: sbt clean package
- - name: Lint with scalafix
- run: sbt "scalafixAll --check"
- - name: Set docker-java API version
- run: |
- echo "api.version=1.52" >> ~/.docker-java.properties
- cat ~/.docker-java.properties
- - name: Run backend tests
- run: sbt test
-
- python:
- needs: precheck
- if: ${{ needs.precheck.outputs.run_python == 'true' }}
- strategy:
- matrix:
- os: [ ubuntu-latest ]
- python-version: [ '3.10', '3.11', '3.12', '3.13' ]
- runs-on: ${{ matrix.os }}
- steps:
- - name: Checkout Texera
- uses: actions/checkout@v5
- - name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v6
- with:
- python-version: ${{ matrix.python-version }}
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- if [ -f amber/requirements.txt ]; then pip install -r
amber/requirements.txt; fi
- if [ -f amber/operator-requirements.txt ]; then pip install -r
amber/operator-requirements.txt; fi
- if [ "${{ matrix.python-version }}" = "3.12" ]; then pip install
pip-licenses; fi
- - name: Generate pip-licenses manifest
- if: matrix.python-version == '3.12'
- run: pip-licenses --format=csv --ignore-packages pip-licenses
prettytable wcwidth > /tmp/pip-licenses.csv
- - name: Check installed Python packages against LICENSE-binary
- if: matrix.python-version == '3.12'
- run: ./bin/licensing/check_binary_deps.py python /tmp/pip-licenses.csv
- - name: Install PostgreSQL
- run: sudo apt-get update && sudo apt-get install -y postgresql
- - name: Start PostgreSQL Service
- run: sudo systemctl start postgresql
- - name: Create Database and User
- run: |
- cd sql && sudo -u postgres psql -f iceberg_postgres_catalog.sql
- - name: Lint with Ruff
- run: |
- cd amber/src/main/python && ruff check . && ruff format --check .
- - name: Test with pytest
- run: |
- cd amber/src/main/python && pytest -sv
-
- agent-service:
- needs: precheck
- if: ${{ needs.precheck.outputs.run_agent_service == 'true' }}
- runs-on: ${{ matrix.os }}
- strategy:
- fail-fast: false
- matrix:
- os: [ubuntu-latest, macos-latest]
- bun-version: ['1.3.3']
- defaults:
- run:
- working-directory: agent-service
- steps:
- - name: Checkout Texera
- uses: actions/checkout@v5
- - name: Setup Bun
- run: |
- curl -fsSL https://bun.sh/install | bash -s -- bun-v${{
matrix.bun-version }}
- echo "$HOME/.bun/bin" >> $GITHUB_PATH
- - name: Install production dependencies
- run: bun install --production --frozen-lockfile
- - name: Generate agent-service license manifest
- if: matrix.os == 'ubuntu-latest'
- run: |
- mkdir -p dist
- bun run bin/collect-licenses.ts > dist/3rdpartylicenses.json
- - name: Check bundled agent-service packages against LICENSE-binary
- if: matrix.os == 'ubuntu-latest'
- run: ../bin/licensing/check_binary_deps.py agent-npm
dist/3rdpartylicenses.json
- - name: Install development dependencies
- run: bun install --frozen-lockfile
- - name: Lint with Prettier
- run: bun run format:check
- - name: Typecheck
- run: bun run typecheck
- - name: Run unit tests
- run: bun test
-
- backport:
- needs: precheck
- if: ${{ needs.precheck.outputs.backport_targets != '[]' }}
- strategy:
- fail-fast: false
- matrix:
- target: ${{ fromJson(needs.precheck.outputs.backport_targets) }}
- uses: ./.github/workflows/reusable-build.yml
- with:
- checkout_ref: refs/pull/${{ github.event.pull_request.number }}/head
- backport_target_branch: ${{ matrix.target }}
- backport_commit_range: ${{ format('{0}..{1}',
github.event.pull_request.base.sha, github.event.pull_request.head.sha) }}
- job_name_suffix: ""
- run_frontend: true
- run_scala: true
- run_python: true
- run_agent_service: true
- secrets: inherit
-
- required-checks:
- # Do not rename this job — its display name is referenced in .asf.yaml.
- name: Required Checks
- needs: [precheck, frontend, scala, python, agent-service, backport]
- if: always()
- runs-on: ubuntu-latest
- steps:
- - name: Verify all required checks succeeded or were skipped
- run: |
- declare -A results=(
- [precheck]="${{ needs.precheck.result }}"
- [frontend]="${{ needs.frontend.result }}"
- [scala]="${{ needs.scala.result }}"
- [python]="${{ needs.python.result }}"
- [agent-service]="${{ needs.agent-service.result }}"
- [backport]="${{ needs.backport.result }}"
- )
- failed=0
- for job in "${!results[@]}"; do
- r="${results[$job]}"
- echo "${job}: ${r}"
- if [[ "$r" != "success" && "$r" != "skipped" ]]; then
- failed=1
- fi
- done
- if (( failed )); then
- echo "::error::One or more required checks did not succeed."
- exit 1
- fi
- echo "All required checks succeeded or were skipped."
diff --git a/.github/workflows/required-checks.yml
b/.github/workflows/required-checks.yml
new file mode 100644
index 0000000000..e189e79c38
--- /dev/null
+++ b/.github/workflows/required-checks.yml
@@ -0,0 +1,178 @@
+# 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: Required Checks
+
+on:
+ push:
+ branches:
+ - 'ci-enable/**'
+ - 'main'
+ - 'release/**'
+ pull_request:
+ types:
+ - opened
+ - reopened
+ - synchronize
+ - labeled
+ - unlabeled
+ workflow_dispatch:
+
+permissions:
+ checks: write
+ contents: read
+ pull-requests: read
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
+
+jobs:
+ # Precheck decides which downstream jobs run for this event:
+ # - run_frontend / run_scala / run_python / run_agent_service: gate the
+ # main build stacks. All true today; placeholder for future path- or
+ # label-based selection.
+ # - backport_targets: JSON array of release/* labels currently on the PR.
+ # Drives the backport matrix; empty array means no backport runs.
+ precheck:
+ name: Precheck
+ runs-on: ubuntu-latest
+ outputs:
+ run_frontend: ${{ steps.decide.outputs.run_frontend }}
+ run_scala: ${{ steps.decide.outputs.run_scala }}
+ run_python: ${{ steps.decide.outputs.run_python }}
+ run_agent_service: ${{ steps.decide.outputs.run_agent_service }}
+ backport_targets: ${{ steps.decide.outputs.backport_targets }}
+ steps:
+ - name: Decide which jobs to run
+ id: decide
+ uses: actions/github-script@v8
+ with:
+ script: |
+ const eventName = context.eventName;
+
+ // Main build stacks: always run.
+ const stacks = ["run_frontend", "run_scala", "run_python",
"run_agent_service"];
+ for (const key of stacks) {
+ core.setOutput(key, "true");
+ }
+
+ // Backport targets: all current release/* labels on the PR.
+ let targets = [];
+ if (eventName === "pull_request") {
+ const labels = context.payload.pull_request.labels.map((l) =>
l.name);
+ targets = [...new Set(labels.filter((n) =>
/^release\/.+$/.test(n)))].sort();
+ }
+
+ if (targets.length === 0) {
+ core.info(`No backport targets on PR.`);
+ } else {
+ core.info(`Backport targets: ${targets.join(", ")}`);
+ }
+ core.setOutput("backport_targets", JSON.stringify(targets));
+
+ cleanup-stale-backport:
+ if: ${{ github.event_name == 'pull_request' && github.event.action ==
'unlabeled' && startsWith(github.event.label.name, 'release/') }}
+ runs-on: ubuntu-latest
+ steps:
+ - name: Cancel obsolete backport check_runs for the removed target
+ uses: actions/github-script@v8
+ with:
+ script: |
+ const { owner, repo } = context.repo;
+ const target = context.payload.label.name;
+ const headSha = context.payload.pull_request.head.sha;
+ const prefix = `backport (${target}) `;
+
+ const checks = await github.paginate(
+ github.rest.checks.listForRef,
+ { owner, repo, ref: headSha, per_page: 100 }
+ );
+
+ for (const check of checks) {
+ if (!check.name.startsWith(prefix)) continue;
+ if (check.status === "completed" && check.conclusion ===
"cancelled") continue;
+ try {
+ await github.rest.checks.update({
+ owner,
+ repo,
+ check_run_id: check.id,
+ status: "completed",
+ conclusion: "cancelled",
+ });
+ core.info(`Cancelled check ${check.name}`);
+ } catch (e) {
+ core.warning(`Failed to update check ${check.id}
(${check.name}): ${e.message}`);
+ }
+ }
+
+ build:
+ needs: precheck
+ uses: ./.github/workflows/build.yml
+ with:
+ run_frontend: ${{ needs.precheck.outputs.run_frontend == 'true' }}
+ run_scala: ${{ needs.precheck.outputs.run_scala == 'true' }}
+ run_python: ${{ needs.precheck.outputs.run_python == 'true' }}
+ run_agent_service: ${{ needs.precheck.outputs.run_agent_service ==
'true' }}
+ secrets: inherit
+
+ backport:
+ needs: precheck
+ if: ${{ needs.precheck.outputs.backport_targets != '[]' }}
+ strategy:
+ fail-fast: false
+ matrix:
+ target: ${{ fromJson(needs.precheck.outputs.backport_targets) }}
+ uses: ./.github/workflows/build.yml
+ with:
+ checkout_ref: refs/pull/${{ github.event.pull_request.number }}/head
+ backport_target_branch: ${{ matrix.target }}
+ backport_commit_range: ${{ format('{0}..{1}',
github.event.pull_request.base.sha, github.event.pull_request.head.sha) }}
+ job_name_suffix: ""
+ run_frontend: ${{ needs.precheck.outputs.run_frontend == 'true' }}
+ run_scala: ${{ needs.precheck.outputs.run_scala == 'true' }}
+ run_python: ${{ needs.precheck.outputs.run_python == 'true' }}
+ run_agent_service: ${{ needs.precheck.outputs.run_agent_service ==
'true' }}
+ secrets: inherit
+
+ required-checks:
+ # Do not rename this job — its display name is referenced in .asf.yaml.
+ name: Required Checks
+ needs: [precheck, build, backport]
+ if: always()
+ runs-on: ubuntu-latest
+ steps:
+ - name: Verify all required checks succeeded or were skipped
+ run: |
+ declare -A results=(
+ [precheck]="${{ needs.precheck.result }}"
+ [build]="${{ needs.build.result }}"
+ [backport]="${{ needs.backport.result }}"
+ )
+ failed=0
+ for job in "${!results[@]}"; do
+ r="${results[$job]}"
+ echo "${job}: ${r}"
+ if [[ "$r" != "success" && "$r" != "skipped" ]]; then
+ failed=1
+ fi
+ done
+ if (( failed )); then
+ echo "::error::One or more required checks did not succeed."
+ exit 1
+ fi
+ echo "All required checks succeeded or were skipped."