Skip to content

ci: run touched port tests on pull requests #2

ci: run touched port tests on pull requests

ci: run touched port tests on pull requests #2

Workflow file for this run

name: pr-ci
# PR CI: runs the tests of the ports a pull request touches, on GitHub-hosted runners
# (free for a public repo). hygiene.yml still owns the `leak-scan` status; this workflow
# adds the port lanes that used to run only on main, nightly and release tags.
#
# THIN WRAPPER: scripts/ci-local.sh is the single definition of every check here. Each
# job installs the toolchain its lane needs and calls the script with that lane's
# `--only` selector and `--no-integration`, so a local run is the same check. Change a
# check in the script, never here.
#
# WHICH PORTS: `detect` maps the PR's changed paths to ports with
# scripts/ci-affected-ports.sh, the same mapper local-ci.yml uses. A change under a
# port's directory selects that port; a change to fixtures/, spec/, scripts/, .github/,
# agent-context/ or anything unrecognised selects ALL ports (the mapper fails open); a
# docs-only change selects none and runs only the offline `gates` lane.
#
# WHAT RUNS PER PORT: unit tests plus the conformance corpora, not the docker
# integration suites (integration-tests.yml owns those, on tags and on demand):
# ts — ts-fast (build + typecheck, conformance, completeness) and ts-unit
# (the per-package suites)
# java — java-slow: the full reactor build with tests on, which already holds the
# java and kotlin conformance classes
# python / csharp — the port's full test suite and conformance
#
# THE REQUIRED CHECK: the final job, `pr-ci`, is the name to put in branch protection
# when a maintainer decides to (it is not required yet; `leak-scan` is). It always runs
# and is green only when every lane that was selected passed, so the set of lanes can
# change per PR without touching branch protection. Do not rename it.
#
# SECURITY: this is a `pull_request` workflow on GitHub-hosted runners with a read-only
# token and no secrets, so fork-submitted code cannot reach anything. It must NEVER move
# onto the self-hosted runner (see local-ci.yml, which must never gain this trigger).
on:
pull_request:
permissions:
contents: read
# A new push to a PR cancels the superseded run.
concurrency:
group: pr-ci-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
detect:
runs-on: ubuntu-latest
outputs:
ports: ${{ steps.sel.outputs.ports }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false
- id: sel
run: |
# HEAD is the PR's merge commit; its first parent is the base tip the merge was
# built on, so HEAD^1..HEAD is exactly the PR's change even after main moves.
ports="$(scripts/ci-affected-ports.sh HEAD^1 HEAD)"
echo "selected ports: '$ports'"
echo "ports=$ports" >> "$GITHUB_OUTPUT"
gates:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # the version gates diff against origin/main
persist-credentials: false
- uses: oven-sh/setup-bun@v2
with:
bun-version: '1.3.14'
- name: Cache Bun install cache
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Gates
env:
MO_CI_LEAK_BASE: origin/${{ github.base_ref }}
run: scripts/ci-local.sh --only gates --strict-toolchains
ts:
needs: detect
if: contains(format(' {0} ', needs.detect.outputs.ports), ' ts ')
runs-on: ubuntu-latest
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
lane: [ts-fast, ts-unit]
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: oven-sh/setup-bun@v2
with:
bun-version: '1.3.14'
- name: Cache Bun install cache
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: ${{ matrix.lane }}
env:
LANE: ${{ matrix.lane }}
run: scripts/ci-local.sh --only "$LANE" --no-integration --strict-toolchains
java:
needs: detect
if: contains(format(' {0} ', needs.detect.outputs.ports), ' java ')
runs-on: ubuntu-latest
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
# java-slow = the full reactor with tests on, which already holds every java and
# kotlin conformance class (java-fast would run the same classes a second time).
lane: [java-slow]
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'
cache: maven
- name: ${{ matrix.lane }}
env:
LANE: ${{ matrix.lane }}
run: |
METAOBJECTS_CI_M2_REPO="$HOME/.m2/repository" \
scripts/ci-local.sh --only "$LANE" --no-integration --strict-toolchains
python:
needs: detect
if: contains(format(' {0} ', needs.detect.outputs.ports), ' python ')
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: astral-sh/setup-uv@v3
with:
enable-cache: true
- run: scripts/ci-local.sh --only python --no-integration --strict-toolchains
csharp:
needs: detect
if: contains(format(' {0} ', needs.detect.outputs.ports), ' csharp ')
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Cache NuGet packages
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('server/csharp/**/*.csproj') }}
restore-keys: |
${{ runner.os }}-nuget-
- run: scripts/ci-local.sh --only csharp --no-integration --strict-toolchains
# The stable required-check name. Runs even when lanes are skipped or failed.
pr-ci:
if: always()
needs: [detect, gates, ts, java, python, csharp]
runs-on: ubuntu-latest
steps:
- name: Every selected lane passed
env:
RESULTS: ${{ join(needs.*.result, ' ') }}
run: |
echo "lane results: $RESULTS"
for r in $RESULTS; do
case "$r" in
success|skipped) ;;
*) echo "a lane finished '$r'" >&2; exit 1 ;;
esac
done