on-pr.yml is the main entry point for pull-request checks across all S-CORE
repositories. It auto-detects what a repository contains and runs the relevant
checks — pre-commit, Python tests, Bazel format/copyright, and the Bazel bzlmod
lockfile checks — as a single job.
Create .github/workflows/pr.yml in your repository:
name: PR
on:
pull_request:
types: [opened, reopened, synchronize]
merge_group:
types: [checks_requested]
jobs:
common:
uses: eclipse-score/cicd-workflows/.github/workflows/on-pr.yml@main
permissions:
contents: readThat is all that is required. The workflow detects your repository's capabilities and runs only the applicable checks — no per-repo configuration needed.
on-pr supports the common, optional inter-repo access interface used by
newer workflows that need to fetch private Bazel dependencies:
| Caller field | Purpose |
|---|---|
with.github-app-client-id |
GitHub App client ID |
secrets.github-app-private-key |
Corresponding GitHub App private key |
secrets.token |
Alternative token; omit the App fields when using it |
This interface is deliberately opt-in: workflows that do not need private dependencies should not declare these fields. Existing/legacy workflow APIs are not retrofitted to it.
Example with a GitHub App:
jobs:
common:
uses: eclipse-score/cicd-workflows/.github/workflows/on-pr.yml@main
with:
github-app-client-id: ${{ vars.PRIVATE_DEPENDENCY_APP_ID }}
secrets:
github-app-private-key: ${{ secrets.PRIVATE_DEPENDENCY_APP_PRIVATE_KEY }}
permissions:
contents: readThe credentials are configured only for Bazel-capable repositories and only when one of the optional credential values is supplied.
Every check runs in one job, and only if its capability is detected (and it is not explicitly skipped — see Skipping checks).
| Check | Runs when | Command |
|---|---|---|
| pre-commit | .pre-commit-config.yaml exists |
uvx pre-commit run --all-files |
| Python tests | pyproject.toml and uv.lock exist |
uv run --frozen python -m pytest |
| Bazel format | //:format.check target exists |
bazel test //:format.check |
| Bazel copyright | //:copyright.check target exists |
bazel run //:copyright.check |
| Bzlmod tidy | MODULE.bazel.lock exists |
bazel mod tidy + git diff --exit-code |
| Bzlmod lockfile | MODULE.bazel.lock exists |
bazel mod deps --lockfile_mode=error |
Capability detection looks for:
- Bazel —
MODULE.bazel,WORKSPACE, orWORKSPACE.bazel - Bazel lockfile —
MODULE.bazel.lock - Python/uv — both
pyproject.tomlanduv.lock - pre-commit —
.pre-commit-config.yaml
The presence of the Bazel //:format.check and //:copyright.check targets is
detected by querying Bazel directly, so those checks only run when the target
actually exists.
A Bazel module-name check exists but is currently disabled until its detection script is fixed.
Sometimes a capability is present but you do not want on-pr to run that check
(for example, you already run pre-commit a different way). Set the matching input
to true:
| Input | Skips |
|---|---|
skip-pre-commit |
pre-commit |
skip-python-tests |
Python / pytest |
skip-format |
bazel //:format.check |
skip-copyright |
bazel //:copyright.check |
skip-bzlmod-lock |
both the bzlmod tidy and lockfile checks |
All inputs default to false, so existing callers are unaffected. Example:
jobs:
common:
uses: eclipse-score/cicd-workflows/.github/workflows/on-pr.yml@main
with:
skip-pre-commit: true
permissions:
contents: read- All checks run, even if one fails. A failing check does not stop the ones after it — each reports its own pass/fail, and the job as a whole fails if any check failed.
- Failures come with guidance. When a check fails, its own log explains what failed, how to reproduce it locally, and how to fix it. No annotations, run summaries, or PR comments are created.
- Shared checkout stays clean. All checks share one checkout, so a check that
rewrites files (pre-commit,
bazel mod tidy) restores the working tree afterwards. Later git-diff-based checks therefore see the original PR state, not the auto-fixed one. - Sequential. Checks run one after another in a single runner rather than in parallel across jobs. This trades a little wall-clock time for far less runner spin-up overhead and no skipped-job clutter in the PR checks UI.
- Nothing heavy installs unless needed.
uvand Bazel are set up only when a relevant capability is detected, and Bazel is set up once and shared by all Bazel checks. pull_request_targetis refused. The workflow exits immediately on that event, which would otherwise expose repository secrets to untrusted fork code. Usepull_requestormerge_groupinstead.
No additional permissions required. Standard contents: read is sufficient.
permissions:
contents: readon-pr uses the standard S-CORE runner-label resolution:
runner-labels input → runner_labels_ghub24_standard_x64 → REPO_RUNNER_LABELS → ubuntu-24.04. See
Runner Selection Logic for details.