Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/conformance.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
name: conformance

# COST: the cross-port conformance matrix + full Java reactor + drift/mutation gates
# are heavy, so they do NOT run on every push/PR — release gate (tag `v*`), a NIGHTLY
# schedule, and on-demand (workflow_dispatch). Run them LOCALLY before opening/merging
# are heavy, so they do NOT run on every push or PR (pr-ci.yml runs the touched ports'
# lanes on a PR) — release gate (tag `v*`), a NIGHTLY schedule, and on-demand
# (workflow_dispatch). Run them LOCALLY before opening/merging
# a PR:
# scripts/ci-local.sh # full parity (this + integration suite + drift)
# scripts/ci-local.sh --quick # everything except the docker integration suite
Expand Down
193 changes: 193 additions & 0 deletions .github/workflows/pr-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
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
20 changes: 13 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ conformance corpora. This guide covers how to propose changes.
1. **Fork** the repo and create a branch from `main`.
2. Make your change following the discipline below — **tests first (TDD)**.
3. Run the gates locally with **`scripts/ci-local.sh --quick`** and make sure it's
green. **This matters:** on a pull request GitHub Actions runs only the leak scan
(`hygiene.yml`); the conformance and integration lanes run on `main`, nightly and on
release tags, so your local run is the only check of the rest before merge — see the
*Local CI* section below.
green. On a pull request GitHub Actions runs the leak scan (`hygiene.yml`) and the
unit and conformance tests of the ports your change touches (`pr-ci.yml`); the docker
integration suites run on release tags and on manual dispatch — see the *Local CI*
section below.
4. Open a **pull request** against `main` and fill out the PR template.
5. A maintainer reviews the change and the checks on the pull request before merge. Who can
approve what, and which changes need a core maintainer, is in
Expand Down Expand Up @@ -84,9 +84,15 @@ GitHub Actions is enabled on this repository. The check workflows in
`.github/workflows/` are thin wrappers over `scripts/ci-local.sh`, the single
definition of the checks: each wrapper checks out, installs the toolchains its
lane needs, and calls the script, so a local run is the same check a workflow
run would be. A pull request runs only the leak scan; the other lanes run on
`main`, nightly and on release tags. Run the script locally before opening or
merging a PR, so nothing red reaches `main`:
run would be. A pull request runs the leak scan (`hygiene.yml`) and `pr-ci.yml`, which
runs the unit tests and conformance corpora of only the ports the PR touches (a change
under `fixtures/`, `spec/`, `scripts/`, `.github/` or `agent-context/`, or to any file
outside a port's directory that the selector does not recognise, touches every port; a
change only to `docs/` or to Markdown files outside those directories runs just the
offline gates). Its `pr-ci` job is green only when every selected lane is, and a newer
push cancels the superseded run. The docker integration suites run on release tags and on
manual dispatch. Run the script locally before opening or merging a PR, so nothing red
reaches `main`:

```bash
scripts/ci-local.sh # full parity: hygiene.yml's leak-scan, all-port
Expand Down
6 changes: 6 additions & 0 deletions GOVERNANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@ license does not grant use of the MetaObjects name or trademark.
Paid work or sponsorship does not grant a role, a vote or an exception to review. A change built
for a paying customer goes through the same review as any other change.

One commitment goes with the roles: a port maintainer gets first call on paid work in the port
they maintain, as listed in [MAINTAINERS.md](MAINTAINERS.md). When the creator or Doug Mealing LLC
has paid work that falls in a port, they offer it to that port's maintainer before anyone else; work
that spans several ports is offered to each of those ports' maintainers. This is an offer of work
only. It grants no role, vote or review exception, and the maintainer may decline it.

## Succession

The creator has stepped away when they say so in writing, or when they have not committed,
Expand Down
3 changes: 2 additions & 1 deletion scripts/ci-local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@
# so use it wherever a skip would mean a real gap rather than an absent toolchain:
# the pre-release run, and the no-mistakes gate's two commands (.no-mistakes.yaml).
#
# Called by: hygiene.yml (--only leak-scan) · conformance.yml (--only gates /
# Called by: hygiene.yml (--only leak-scan) · pr-ci.yml (the touched ports' lanes, with
# --no-integration) · conformance.yml (--only gates /
# ts-fast / csharp / java-fast / python, and java-slow for the reactor, all with
# --no-integration) · integration-tests.yml (--integration-only, one job per lane) ·
# local-ci.yml (one job per lane).
Expand Down
Loading