ci(build): require manual full builds and auto-test relinker for contributors

This commit is contained in:
boykopovar committed 2026-10-09 11:58:02 +03:00
1 parent 6cc0503dac
commit 0ab2a04dd7
3 files changed
+88 -44

No files matched your search

+72 -40
View File
@@ -1,16 +1,21 @@
name: Build
on:
push:
branches: [main]
pull_request:
branches: [main]
types: [opened, synchronize, reopened]
workflow_dispatch:
inputs:
pr:
description: Pull request number to build
required: true
type: string
permissions:
contents: read
concurrency:
group: build-${{ github.ref }}
group: build-${{ github.event_name }}-pr-${{ github.event.pull_request.number || inputs.pr }}
cancel-in-progress: true
env:
@@ -20,34 +25,66 @@ env:
-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
jobs:
changes:
if: github.event_name == 'pull_request'
eligibility:
if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
pull-requests: read
outputs:
relinker: ${{ steps.filter.outputs.relinker }}
code: ${{ steps.filter.outputs.code }}
sha: ${{ steps.gate.outputs.sha }}
relinker: ${{ steps.gate.outputs.relinker }}
full: ${{ steps.gate.outputs.full }}
steps:
- uses: dorny/paths-filter@v4
id: filter
- uses: actions/github-script@v8
id: gate
env:
PR_NUMBER: ${{ inputs.pr }}
with:
predicate-quantifier: some-with-excludes
filters: |
relinker:
- 'core/relinker/**'
- 'core/libs/prx/libc/src/specifics/windows/**'
- 'CMakeLists.txt'
- '.github/workflows/build.yml'
code:
- '**'
- '!**/*.md'
- '!docs/**'
script: |
const { owner, repo } = context.repo;
const manual = context.eventName === 'workflow_dispatch';
if (manual) {
for (const username of new Set([context.actor, process.env.GITHUB_TRIGGERING_ACTOR])) {
const { data } = await github.rest.repos.getCollaboratorPermissionLevel({ owner, repo, username });
if (!['write', 'maintain', 'admin'].includes(data.permission)) {
throw new Error('Only collaborators with write access can start or rerun builds');
}
}
if (!/^[1-9][0-9]*$/.test(process.env.PR_NUMBER)) {
throw new Error('Enter a positive pull request number');
}
}
const pull_number = manual ? Number(process.env.PR_NUMBER) : context.payload.pull_request.number;
if (!Number.isSafeInteger(pull_number) || pull_number < 1) {
throw new Error('Invalid pull request number');
}
const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number });
if (pr.state !== 'open' || pr.base.ref !== 'main') {
throw new Error('The pull request must be open and target main');
}
if (!manual && pr.head.sha !== context.payload.pull_request.head.sha) {
throw new Error('The pull request has newer commits; use the latest run');
}
let relinker = manual;
if (!manual) {
const { data: commits } = await github.rest.repos.listCommits({
owner, repo, sha: 'main', author: pr.user.login, per_page: 1
});
relinker = commits.length > 0;
}
core.setOutput('sha', pr.head.sha);
core.setOutput('relinker', relinker);
core.setOutput('full', manual);
await core.summary.addRaw(
`PR #${pull_number} at ${pr.head.sha}: full builds ${manual ? 'enabled' : 'disabled'}, ` +
`relinker ${relinker ? 'enabled' : 'skipped because the author has no commit in main'}`
).write();
relinker:
needs: changes
if: ${{ !cancelled() && (needs.changes.result != 'success' || needs.changes.outputs.relinker == 'true') }}
needs: eligibility
if: ${{ needs.eligibility.outputs.relinker == 'true' }}
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
@@ -68,6 +105,9 @@ jobs:
shell: bash
steps:
- uses: actions/checkout@v7
with:
ref: ${{ needs.eligibility.outputs.sha }}
persist-credentials: false
- if: runner.os == 'Windows'
id: toolchain
uses: actions/cache@v6
@@ -85,13 +125,15 @@ jobs:
- run: ctest --test-dir build-relinker --output-on-failure --timeout 120
linux:
needs: changes
if: ${{ !cancelled() && (needs.changes.result != 'success' || needs.changes.outputs.code == 'true') }}
needs: eligibility
if: ${{ github.event_name == 'workflow_dispatch' && needs.eligibility.outputs.full == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v7
with:
ref: ${{ needs.eligibility.outputs.sha }}
persist-credentials: false
submodules: true
- uses: hendrikmuhs/ccache-action@v1.2.24
with:
@@ -105,13 +147,7 @@ jobs:
run: python3 tools/check_test_registration.py build
- run: cmake --build build
- run: cmake --build build --target libs
- name: Save the compiler cache before the tests
if: github.event_name == 'push'
uses: actions/cache/save@v6
with:
path: ${{ github.workspace }}/.ccache
key: ccache-linux-${{ github.run_id }}-${{ github.run_attempt }}
- run: ctest --test-dir build --output-on-failure --timeout 120 ${{ github.event_name == 'push' && '--repeat until-fail:3' || '' }} --parallel 4 --output-log ctest.log
- run: ctest --test-dir build --output-on-failure --timeout 120 --parallel 4 --output-log ctest.log
env:
ANYPS5_REQUIRE_VULKAN: 1
GALLIUM_OVERRIDE_CPU_CAPS: avx
@@ -124,8 +160,8 @@ jobs:
END { for (name in max) if (max[name] > 30) printf "::warning title=Slow test::%s took %.1f s on %s; tests must finish in 30 s (CONTRIBUTING.md)\n", name, max[name], ENVIRON["RUNNER_OS"] }' ctest.log
windows:
needs: changes
if: ${{ !cancelled() && (needs.changes.result != 'success' || needs.changes.outputs.code == 'true') }}
needs: eligibility
if: ${{ github.event_name == 'workflow_dispatch' && needs.eligibility.outputs.full == 'true' }}
runs-on: windows-latest
timeout-minutes: 45
env:
@@ -138,6 +174,8 @@ jobs:
steps:
- uses: actions/checkout@v7
with:
ref: ${{ needs.eligibility.outputs.sha }}
persist-credentials: false
submodules: true
- id: toolchain
uses: actions/cache@v6
@@ -163,14 +201,8 @@ jobs:
run: cmake --build build
- shell: cmd
run: cmake --build build --target libs
- name: Save the compiler cache before the tests
if: github.event_name == 'push'
uses: actions/cache/save@v6
with:
path: ${{ github.workspace }}\.ccache
key: ccache-windows-${{ github.run_id }}-${{ github.run_attempt }}
- shell: cmd
run: ctest --test-dir build --output-on-failure --timeout 120 ${{ github.event_name == 'push' && '--repeat until-fail:3' || '' }} --parallel 4 --output-log ctest.log
run: ctest --test-dir build --output-on-failure --timeout 120 --parallel 4 --output-log ctest.log
- name: Report tests slower than 30 s
if: ${{ !cancelled() }}
shell: bash
+13 -3
View File
@@ -1,14 +1,14 @@
name: Conventions
on:
pull_request:
pull_request_target:
types: [opened, synchronize, reopened, edited]
permissions:
contents: read
concurrency:
group: conventions-${{ github.ref }}
group: conventions-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
@@ -18,5 +18,15 @@ jobs:
steps:
- uses: actions/checkout@v7
with:
ref: ${{ github.event.pull_request.base.sha }}
fetch-depth: 0
- run: python3 tools/check_conventions.py --base ${{ github.event.pull_request.base.sha }} --head ${{ github.event.pull_request.head.sha }}
persist-credentials: false
- name: Fetch pull request objects without checking out its code
env:
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: git fetch --no-tags origin "$HEAD_SHA"
- name: Check conventions with the trusted base script
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: python3 -I tools/check_conventions.py --base "$BASE_SHA" --head "$HEAD_SHA"
+3 -1
View File
@@ -29,7 +29,9 @@ ctest --test-dir build --output-on-failure
Python 3 is optional; without it some relinker tests are not registered.
The Conventions check runs on every pull request and fails when a rule on this page is broken. It accepts code comments only when the pull request also changes [TechnicalDebt](docs/dev/TechnicalDebt.md), and only UTF-8 text files. Run it locally before pushing:
Full Linux and Windows builds and tests run only when a collaborator with write access selects Actions > Build > Run workflow on `main` and enters an open pull request number targeting `main`. This manual run also builds and tests the relinker on Linux, Windows and macOS, regardless of the author's previous contributions or the changed files. The relinker matrix also runs automatically when a pull request targeting `main` is opened, updated or reopened, if its author already has a commit in `main`; full builds never run automatically. All build jobs use the selected pull request head commit. New commits require another manual run for full builds.
The Conventions check runs automatically for every contributor, including first-time contributors. It uses the base branch checker and reads pull request Git objects without executing pull request code. The Conventions check runs on every pull request and fails when a rule on this page is broken. It accepts code comments only when the pull request also changes [TechnicalDebt](docs/dev/TechnicalDebt.md), and only UTF-8 text files. Run it locally before pushing:
```
python3 tools/check_conventions.py --base origin/main