mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-23 00:53:02 -05:00
Git for Windows 2.56 (runner image 20261002) moved from mingw64 to ucrt64, so the fixed SSL_CERT_FILE path no longer exists and the WinLibs CMake fails the FFmpeg download with status 60 on every Windows build. Take the bundle from whichever of ucrt64 and mingw64 exists. Co-Authored-By: Claude <noreply@anthropic.com>
434 lines
21 KiB
YAML
434 lines
21 KiB
YAML
name: Build
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
pull_request:
|
|
branches: [main]
|
|
types: [opened, synchronize, reopened]
|
|
workflow_dispatch:
|
|
inputs:
|
|
pr:
|
|
description: Pull request numbers to build together, separated by spaces or commas (up to 40)
|
|
required: true
|
|
type: string
|
|
linux:
|
|
description: Also build and test on Linux
|
|
required: false
|
|
default: true
|
|
type: boolean
|
|
full:
|
|
description: Run the full Linux and Windows builds (off runs only the relinker builds and tests on Linux, Windows and macOS)
|
|
required: false
|
|
default: true
|
|
type: boolean
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
concurrency:
|
|
group: build-${{ github.event_name }}-${{ github.event.pull_request.number || inputs.pr || github.ref }}
|
|
cancel-in-progress: ${{ github.event_name != 'push' }}
|
|
|
|
env:
|
|
CONFIGURE: >-
|
|
-G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON
|
|
-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++
|
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
|
|
|
jobs:
|
|
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:
|
|
sha: ${{ steps.gate.outputs.sha }}
|
|
pr: ${{ steps.gate.outputs.pr }}
|
|
head: ${{ steps.gate.outputs.head }}
|
|
relinker: ${{ steps.gate.outputs.relinker }}
|
|
register-context: ${{ steps.gate.outputs.register-context }}
|
|
write-watch: ${{ steps.gate.outputs.write-watch }}
|
|
full: ${{ steps.gate.outputs.full }}
|
|
relinker-hosts: ${{ steps.gate.outputs.relinker-hosts }}
|
|
steps:
|
|
- uses: actions/github-script@v8
|
|
id: gate
|
|
env:
|
|
PR_NUMBER: ${{ inputs.pr }}
|
|
LINUX_BUILD: ${{ inputs.linux }}
|
|
FULL_BUILD: ${{ inputs.full }}
|
|
with:
|
|
script: |
|
|
const { owner, repo } = context.repo;
|
|
const workflow = '.github/workflows/build.yml';
|
|
const libc = 'core/libs/prx/libc/';
|
|
const select = (paths, all) => {
|
|
const touches = (...prefixes) => all ||
|
|
paths.some((path) => prefixes.some((prefix) => prefix.endsWith('/') ? path.startsWith(prefix) : path === prefix));
|
|
return {
|
|
relinker: touches(
|
|
'core/relinker/', libc, 'core/libs/prx/libkernel/AppMetadata/', 'core/libs/tests/ParamJsonParser.cpp',
|
|
'core/shader/recompiler/tests/CacheFileReadTests.cpp', 'core/shader/recompiler/ShaderCacheDirectory.hpp',
|
|
'tools/', 'cmake/', 'CMakeLists.txt', workflow
|
|
),
|
|
registerContext: touches('core/libs/tests/register_context/', 'core/libs/tests/RegisterContext.cpp', libc, workflow),
|
|
writeWatch: touches('core/libs/tests/write_watch/', 'core/libs/tests/WriteWatch.cpp', libc, workflow),
|
|
};
|
|
};
|
|
const relinkerHosts = (full, linux) => JSON.stringify([
|
|
...(full && linux ? [] : [{ os: 'ubuntu-latest', compiler: 'g++' }]),
|
|
...(full ? [] : [{ os: 'windows-latest', compiler: 'g++' }]),
|
|
{ os: 'macos-latest', compiler: 'clang++' },
|
|
]);
|
|
if (context.eventName === 'push') {
|
|
if (context.ref !== 'refs/heads/main') {
|
|
throw new Error('Automatic full builds only run on main');
|
|
}
|
|
let paths = [];
|
|
let all = true;
|
|
if (!/^0+$/.test(context.payload.before)) {
|
|
try {
|
|
const { data } = await github.rest.repos.compareCommitsWithBasehead({
|
|
owner, repo, basehead: `${context.payload.before}...${context.sha}`
|
|
});
|
|
const files = data.files ?? [];
|
|
all = files.length >= 300;
|
|
paths = files.flatMap((file) => [file.filename, file.previous_filename].filter(Boolean));
|
|
} catch (error) {
|
|
core.warning(`Could not list the files of this push, so every test job runs: ${error.message}`);
|
|
}
|
|
}
|
|
const run = select(paths, all);
|
|
core.setOutput('sha', context.sha);
|
|
core.setOutput('pr', '');
|
|
core.setOutput('head', '');
|
|
core.setOutput('relinker', run.relinker);
|
|
core.setOutput('register-context', run.registerContext);
|
|
core.setOutput('write-watch', run.writeWatch);
|
|
core.setOutput('full', true);
|
|
core.setOutput('relinker-hosts', relinkerHosts(true, true));
|
|
await core.summary.addRaw(
|
|
`Building main at ${context.sha}: full builds enabled, ` +
|
|
`macOS relinker ${run.relinker ? 'enabled' : 'skipped'}, ` +
|
|
`register context tests ${run.registerContext ? 'enabled' : 'skipped'}, write watch tests ${run.writeWatch ? 'enabled' : 'skipped'}`
|
|
).write();
|
|
return;
|
|
}
|
|
const manual = context.eventName === 'workflow_dispatch';
|
|
const linux = process.env.LINUX_BUILD !== 'false';
|
|
const full = manual && process.env.FULL_BUILD !== 'false';
|
|
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]*([ ,]+[1-9][0-9]*){0,39}$/.test(process.env.PR_NUMBER.trim())) {
|
|
throw new Error('Enter up to 40 positive pull request numbers separated by spaces or commas');
|
|
}
|
|
}
|
|
const numbers = manual
|
|
? [...new Set(process.env.PR_NUMBER.trim().split(/[ ,]+/).map(Number))]
|
|
: [context.payload.pull_request.number];
|
|
if (numbers.some((pull_number) => !Number.isSafeInteger(pull_number) || pull_number < 1)) {
|
|
throw new Error('Invalid pull request number');
|
|
}
|
|
const pulls = [];
|
|
const paths = [];
|
|
let truncated = false;
|
|
for (const pull_number of numbers) {
|
|
let { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number });
|
|
for (let attempt = 0; pr.mergeable === null && attempt < 10; ++attempt) {
|
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
({ data: pr } = await github.rest.pulls.get({ owner, repo, pull_number }));
|
|
}
|
|
if (!manual && pr.state !== 'open') {
|
|
await core.summary.addRaw(`PR #${pull_number} was ${pr.merged ? 'merged' : 'closed'} before this run started: nothing to build`).write();
|
|
return;
|
|
}
|
|
if (pr.state !== 'open' || pr.base.ref !== 'main') {
|
|
throw new Error(`Pull request #${pull_number} 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');
|
|
}
|
|
if (pr.mergeable === false) {
|
|
throw new Error(`Pull request #${pull_number} does not merge cleanly into main; rebase it first`);
|
|
}
|
|
const files = await github.paginate(github.rest.pulls.listFiles, { owner, repo, pull_number, per_page: 100 });
|
|
truncated ||= files.length >= 3000;
|
|
paths.push(...files.flatMap((file) => [file.filename, file.previous_filename].filter(Boolean)));
|
|
pulls.push({ number: pull_number, head: pr.head.sha });
|
|
}
|
|
const run = select(paths, truncated);
|
|
let relinker = run.relinker;
|
|
if (relinker && !manual) {
|
|
const author = context.payload.pull_request.user.login;
|
|
const { data: commits } = await github.rest.repos.listCommits({
|
|
owner, repo, sha: 'main', author, per_page: 1
|
|
});
|
|
relinker = commits.length > 0;
|
|
if (!relinker) {
|
|
try {
|
|
const { data: mergedPRs } = await github.rest.search.issuesAndPullRequests({
|
|
q: `repo:${owner}/${repo} is:pr is:merged base:main author:${author}`,
|
|
per_page: 1
|
|
});
|
|
if (mergedPRs.incomplete_results) {
|
|
throw new Error('the search results are incomplete');
|
|
}
|
|
relinker = mergedPRs.total_count > 0;
|
|
} catch (error) {
|
|
core.warning(`Skipping the relinker: could not search the merged pull requests of ${author}: ${error.message}`);
|
|
}
|
|
}
|
|
}
|
|
const registerContext = run.registerContext;
|
|
const writeWatch = run.writeWatch;
|
|
const { data: main } = await github.rest.repos.getBranch({ owner, repo, branch: 'main' });
|
|
core.setOutput('sha', main.commit.sha);
|
|
core.setOutput('pr', pulls.map((pull) => pull.number).join(' '));
|
|
core.setOutput('head', pulls.map((pull) => pull.head).join(' '));
|
|
core.setOutput('relinker', relinker);
|
|
core.setOutput('register-context', registerContext);
|
|
core.setOutput('write-watch', writeWatch);
|
|
core.setOutput('full', full);
|
|
core.setOutput('relinker-hosts', relinkerHosts(full, linux));
|
|
const merged = pulls.map((pull) => `PR #${pull.number} at ${pull.head} merged into main at ${main.commit.sha}`);
|
|
merged.forEach((line) => core.info(line));
|
|
await core.summary.addRaw(
|
|
`${merged.join(', then ')}: full builds ${full ? 'enabled' : 'disabled'}, ` +
|
|
`relinker ${relinker ? (full ? (linux ? 'enabled on macOS (the full builds run the Linux and Windows relinker tests)' : 'enabled on Linux and macOS (the full Windows build runs the Windows relinker tests)') : 'enabled') : 'skipped: no relinker file changed, or no commit or merged pull request in main was found for the author'}, ` +
|
|
`register context tests ${registerContext ? 'enabled' : 'skipped'}, write watch tests ${writeWatch ? 'enabled' : 'skipped'}`
|
|
).write();
|
|
|
|
relinker:
|
|
needs: eligibility
|
|
if: ${{ needs.eligibility.outputs.relinker == 'true' }}
|
|
runs-on: ${{ matrix.os }}
|
|
timeout-minutes: 15
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include: ${{ fromJSON(needs.eligibility.outputs.relinker-hosts) }}
|
|
env:
|
|
WINLIBS_RELEASE: 15.2.0posix-14.0.0-ucrt-r7
|
|
WINLIBS_ZIP: winlibs-x86_64-posix-seh-gcc-15.2.0-mingw-w64ucrt-14.0.0-r7.zip
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
with:
|
|
ref: ${{ needs.eligibility.outputs.sha }}
|
|
persist-credentials: false
|
|
- name: Merge the pull request into main
|
|
if: ${{ needs.eligibility.outputs.head != '' }}
|
|
shell: bash
|
|
env:
|
|
PR_NUMBER: ${{ needs.eligibility.outputs.pr }}
|
|
PR_HEAD: ${{ needs.eligibility.outputs.head }}
|
|
run: |
|
|
read -ra numbers <<< "$PR_NUMBER"
|
|
read -ra heads <<< "$PR_HEAD"
|
|
refspecs=()
|
|
for number in "${numbers[@]}"; do refspecs+=("+refs/pull/$number/head:refs/remotes/pull/$number"); done
|
|
git fetch --no-tags --unshallow origin "${refspecs[@]}"
|
|
for i in "${!numbers[@]}"; do
|
|
if [ "$(git rev-parse "refs/remotes/pull/${numbers[i]}")" != "${heads[i]}" ]; then echo "::error::Pull request #${numbers[i]} has newer commits; start a new build"; exit 1; fi
|
|
if ! git -c user.name=ci -c user.email=ci@localhost merge --no-ff --no-edit "refs/remotes/pull/${numbers[i]}"; then echo "::error::Pull request #${numbers[i]} does not merge cleanly into main and the pull requests before it; rebase it first"; exit 1; fi
|
|
done
|
|
- if: runner.os == 'Windows'
|
|
id: toolchain
|
|
uses: actions/cache@v6
|
|
with:
|
|
path: C:\winlibs
|
|
key: ${{ env.WINLIBS_ZIP }}
|
|
- if: runner.os == 'Windows' && steps.toolchain.outputs.cache-hit != 'true'
|
|
run: |
|
|
curl -sSfL -o "$RUNNER_TEMP/winlibs.zip" "https://github.com/brechtsanders/winlibs_mingw/releases/download/$WINLIBS_RELEASE/$WINLIBS_ZIP"
|
|
7z x "$RUNNER_TEMP/winlibs.zip" -oC:/winlibs > /dev/null
|
|
- if: runner.os == 'Windows'
|
|
run: echo 'C:\winlibs\mingw64\bin' >> "$GITHUB_PATH"
|
|
- run: cmake -S . -B build-relinker -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DANYPS5_RELINKER_ONLY=ON -DBUILD_TESTING=ON
|
|
- run: cmake --build build-relinker --parallel 3
|
|
- run: ctest --test-dir build-relinker --output-on-failure --timeout 120
|
|
|
|
register-context:
|
|
needs: eligibility
|
|
if: ${{ needs.eligibility.outputs.register-context == 'true' }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
os: [ubuntu-latest, macos-15-intel]
|
|
configuration: [Debug, Release]
|
|
runs-on: ${{ matrix.os }}
|
|
timeout-minutes: 5
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
- run: cmake -S core/libs/tests/register_context -B build/register-context -DCMAKE_BUILD_TYPE=${{ matrix.configuration }}
|
|
- run: cmake --build build/register-context --parallel
|
|
- run: ctest --test-dir build/register-context --output-on-failure --repeat until-fail:3 --no-tests=error
|
|
|
|
write-watch:
|
|
needs: eligibility
|
|
if: ${{ needs.eligibility.outputs.write-watch == 'true' }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
os: [macos-15-intel, macos-15]
|
|
runs-on: ${{ matrix.os }}
|
|
timeout-minutes: 5
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
- run: cmake -S core/libs/tests/write_watch -B build/write-watch -DCMAKE_BUILD_TYPE=Release
|
|
- run: cmake --build build/write-watch --parallel
|
|
- run: ctest --test-dir build/write-watch --output-on-failure --repeat until-fail:3 --no-tests=error
|
|
|
|
linux:
|
|
needs: eligibility
|
|
if: ${{ (github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.linux)) && needs.eligibility.outputs.full == 'true' }}
|
|
runs-on: [self-hosted, linux, x64, anyps5]
|
|
timeout-minutes: 60
|
|
env:
|
|
CCACHE_DIR: /var/cache/anyps5/ccache
|
|
CCACHE_MAXSIZE: 30G
|
|
CCACHE_COMPILERCHECK: content
|
|
MESA_SHADER_CACHE_DIR: /var/cache/anyps5/mesa
|
|
MESA_SHADER_CACHE_MAX_SIZE: 4G
|
|
CMAKE_BUILD_PARALLEL_LEVEL: 1
|
|
CTEST_PARALLEL_LEVEL: 1
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
with:
|
|
ref: ${{ needs.eligibility.outputs.sha }}
|
|
persist-credentials: false
|
|
submodules: recursive
|
|
- name: Merge the pull request into main
|
|
if: ${{ needs.eligibility.outputs.head != '' }}
|
|
shell: bash
|
|
env:
|
|
PR_NUMBER: ${{ needs.eligibility.outputs.pr }}
|
|
PR_HEAD: ${{ needs.eligibility.outputs.head }}
|
|
run: |
|
|
read -ra numbers <<< "$PR_NUMBER"
|
|
read -ra heads <<< "$PR_HEAD"
|
|
refspecs=()
|
|
for number in "${numbers[@]}"; do refspecs+=("+refs/pull/$number/head:refs/remotes/pull/$number"); done
|
|
fetch_options=()
|
|
if [ "$(git rev-parse --is-shallow-repository)" = true ]; then fetch_options+=(--unshallow); fi
|
|
git fetch --no-tags "${fetch_options[@]}" origin "${refspecs[@]}"
|
|
for i in "${!numbers[@]}"; do
|
|
if [ "$(git rev-parse "refs/remotes/pull/${numbers[i]}")" != "${heads[i]}" ]; then echo "::error::Pull request #${numbers[i]} has newer commits; start a new build"; exit 1; fi
|
|
if ! git -c user.name=ci -c user.email=ci@localhost merge --no-ff --no-edit "refs/remotes/pull/${numbers[i]}"; then echo "::error::Pull request #${numbers[i]} does not merge cleanly into main and the pull requests before it; rebase it first"; exit 1; fi
|
|
done
|
|
git submodule update --init --recursive
|
|
- name: Prepare persistent caches
|
|
run: |
|
|
mkdir -p "$CCACHE_DIR" "$MESA_SHADER_CACHE_DIR"
|
|
test -w "$CCACHE_DIR" && test -w "$MESA_SHADER_CACHE_DIR"
|
|
ccache --zero-stats
|
|
ccache --show-config
|
|
dpkg-query -W mesa-vulkan-drivers
|
|
grep -m1 '^model name' /proc/cpuinfo
|
|
- run: cmake -S . -B build $CONFIGURE -DANYPS5_ENABLE_SPIRV_TOOLS=ON
|
|
- name: Check that every test executable is registered with ctest
|
|
run: python3 tools/check_test_registration.py build
|
|
- run: cmake --build build
|
|
- run: cmake --build build --target libs
|
|
- run: ctest --test-dir build --output-on-failure --timeout 120 --output-log ctest.log --output-junit ctest.xml
|
|
env:
|
|
ANYPS5_REQUIRE_VULKAN: 1
|
|
GALLIUM_OVERRIDE_CPU_CAPS: avx
|
|
- run: python3 tools/check_skips.py build/ctest.xml
|
|
- name: Report compiler cache statistics
|
|
if: ${{ !cancelled() }}
|
|
run: ccache --show-stats
|
|
- name: Report tests slower than 30 s
|
|
if: ${{ !cancelled() }}
|
|
shell: bash
|
|
run: |
|
|
[ -f ctest.log ] || exit 0
|
|
awk '/Test +#[0-9]+: / && $NF == "sec" { for (i = 1; i <= NF; i++) if ($i ~ /^#[0-9]+:$/) name = $(i + 1); t = $(NF - 1) + 0; if (t > max[name]) max[name] = t }
|
|
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: eligibility
|
|
if: ${{ (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && needs.eligibility.outputs.full == 'true' }}
|
|
runs-on: windows-latest
|
|
timeout-minutes: 45
|
|
env:
|
|
WINLIBS_RELEASE: 15.2.0posix-14.0.0-ucrt-r7
|
|
WINLIBS_ZIP: winlibs-x86_64-posix-seh-gcc-15.2.0-mingw-w64ucrt-14.0.0-r7.zip
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
with:
|
|
ref: ${{ needs.eligibility.outputs.sha }}
|
|
persist-credentials: false
|
|
submodules: recursive
|
|
- name: Merge the pull request into main
|
|
if: ${{ needs.eligibility.outputs.head != '' }}
|
|
shell: bash
|
|
env:
|
|
PR_NUMBER: ${{ needs.eligibility.outputs.pr }}
|
|
PR_HEAD: ${{ needs.eligibility.outputs.head }}
|
|
run: |
|
|
read -ra numbers <<< "$PR_NUMBER"
|
|
read -ra heads <<< "$PR_HEAD"
|
|
refspecs=()
|
|
for number in "${numbers[@]}"; do refspecs+=("+refs/pull/$number/head:refs/remotes/pull/$number"); done
|
|
git fetch --no-tags --unshallow origin "${refspecs[@]}"
|
|
for i in "${!numbers[@]}"; do
|
|
if [ "$(git rev-parse "refs/remotes/pull/${numbers[i]}")" != "${heads[i]}" ]; then echo "::error::Pull request #${numbers[i]} has newer commits; start a new build"; exit 1; fi
|
|
if ! git -c user.name=ci -c user.email=ci@localhost merge --no-ff --no-edit "refs/remotes/pull/${numbers[i]}"; then echo "::error::Pull request #${numbers[i]} does not merge cleanly into main and the pull requests before it; rebase it first"; exit 1; fi
|
|
done
|
|
git submodule update --init --recursive
|
|
- name: Point the WinLibs CMake at the CA bundle of Git for Windows
|
|
run: |
|
|
for prefix in ucrt64 mingw64; do
|
|
bundle="C:/Program Files/Git/$prefix/etc/ssl/certs/ca-bundle.crt"
|
|
if [ -f "$bundle" ]; then echo "SSL_CERT_FILE=$bundle" >> "$GITHUB_ENV"; exit 0; fi
|
|
done
|
|
echo "::error::No CA bundle found in Git for Windows"; exit 1
|
|
- id: toolchain
|
|
uses: actions/cache@v6
|
|
with:
|
|
path: C:\winlibs
|
|
key: ${{ env.WINLIBS_ZIP }}
|
|
- if: steps.toolchain.outputs.cache-hit != 'true'
|
|
run: |
|
|
curl -sSfL -o "$RUNNER_TEMP/winlibs.zip" "https://github.com/brechtsanders/winlibs_mingw/releases/download/$WINLIBS_RELEASE/$WINLIBS_ZIP"
|
|
7z x "$RUNNER_TEMP/winlibs.zip" -oC:/winlibs > /dev/null
|
|
- run: echo 'C:\winlibs\mingw64\bin' >> "$GITHUB_PATH"
|
|
- uses: hendrikmuhs/ccache-action@v1.2.24
|
|
with:
|
|
key: windows
|
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
|
evict-old-files: job
|
|
- shell: cmd
|
|
run: cmake -S . -B build %CONFIGURE% "-DANYPS5_AGC_EXECUTION_TESTS=F16ToF32Unpack;F64FmaSubnormals;RegistrationPrepareShutdown"
|
|
- name: Check that every test executable is registered with ctest
|
|
shell: cmd
|
|
run: python tools/check_test_registration.py build
|
|
- shell: cmd
|
|
run: cmake --build build
|
|
- shell: cmd
|
|
run: cmake --build build --target libs
|
|
- shell: cmd
|
|
run: ctest --test-dir build --output-on-failure --timeout 120 --parallel 4 --output-log ctest.log --output-junit ctest.xml
|
|
- run: python tools/check_skips.py build/ctest.xml --job windows
|
|
- name: Report tests slower than 30 s
|
|
if: ${{ !cancelled() }}
|
|
shell: bash
|
|
run: |
|
|
[ -f ctest.log ] || exit 0
|
|
awk '/Test +#[0-9]+: / && $NF == "sec" { for (i = 1; i <= NF; i++) if ($i ~ /^#[0-9]+:$/) name = $(i + 1); t = $(NF - 1) + 0; if (t > max[name]) max[name] = t }
|
|
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
|