From 2b775093777bead59df04def6eb1bfdb78636313 Mon Sep 17 00:00:00 2001 From: mattcapa Date: Wed, 24 Jun 2026 16:25:35 +0200 Subject: [PATCH 1/3] ci: add Linux workflow to run test_components on push to main/dev --- .github/workflows/linux_tests.yml | 78 +++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 .github/workflows/linux_tests.yml diff --git a/.github/workflows/linux_tests.yml b/.github/workflows/linux_tests.yml new file mode 100644 index 00000000..0bfd2c31 --- /dev/null +++ b/.github/workflows/linux_tests.yml @@ -0,0 +1,78 @@ +name: Linux tests + +on: + push: + branches: [main, dev] + pull_request: + branches: [main, dev] + workflow_dispatch: + +jobs: + test_components: + name: Build and run test_components + runs-on: ubuntu-latest + + env: + VCPKG_ROOT: ${{ github.workspace }}/external/vcpkg + # Cache vcpkg-built packages in the GH Actions cache + VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" + # Keep vcpkg memory/CPU usage modest on the GH runner + VCPKG_MAX_CONCURRENCY: "2" + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install build prerequisites + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends \ + build-essential \ + ninja-build \ + gfortran \ + pkg-config \ + curl zip unzip tar \ + autoconf automake autoconf-archive \ + bison flex \ + python3 python3-pip + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Bootstrap vcpkg + run: | + if [ ! -x "$VCPKG_ROOT/vcpkg" ]; then + "$VCPKG_ROOT/bootstrap-vcpkg.sh" -disableMetrics + fi + + # Required for VCPKG_BINARY_SOURCES=x-gha + - name: Export GitHub Actions cache env for vcpkg + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Configure (default preset) + run: cmake --preset default + + - name: Build test_components + run: cmake --build build --target test_components -j + + - name: Run test_components + working-directory: build + run: ctest --output-on-failure -R '^test_components$' + + - name: Upload test logs on failure + if: failure() + uses: actions/upload-artifact@v4 + with: + name: test-logs + path: | + build/Testing/**/*.log + build/Testing/**/LastTest.log + if-no-files-found: ignore From a00d0a196968b1f8ad8bdf9340c7cb5a6132f799 Mon Sep 17 00:00:00 2001 From: Matteo Capaldo <99035419+mattcapa@users.noreply.github.com> Date: Wed, 24 Jun 2026 16:41:49 +0200 Subject: [PATCH 2/3] ci: split build and test jobs; clone/bootstrap vcpkg if missing --- .github/workflows/linux_tests.yml | 35 +++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/.github/workflows/linux_tests.yml b/.github/workflows/linux_tests.yml index 0bfd2c31..48a9c7fb 100644 --- a/.github/workflows/linux_tests.yml +++ b/.github/workflows/linux_tests.yml @@ -8,8 +8,8 @@ on: workflow_dispatch: jobs: - test_components: - name: Build and run test_components + build: + name: Build runs-on: ubuntu-latest env: @@ -24,6 +24,7 @@ jobs: uses: actions/checkout@v4 with: submodules: recursive + fetch-depth: 0 - name: Install build prerequisites run: | @@ -43,10 +44,13 @@ jobs: with: python-version: "3.11" - - name: Bootstrap vcpkg + - name: Bootstrap vcpkg (clone if missing) run: | + if [ ! -d "$VCPKG_ROOT" ]; then + git clone --depth 1 https://github.com/microsoft/vcpkg "$VCPKG_ROOT" + fi if [ ! -x "$VCPKG_ROOT/vcpkg" ]; then - "$VCPKG_ROOT/bootstrap-vcpkg.sh" -disableMetrics + (cd "$VCPKG_ROOT" && ./bootstrap-vcpkg.sh -disableMetrics) fi # Required for VCPKG_BINARY_SOURCES=x-gha @@ -60,8 +64,27 @@ jobs: - name: Configure (default preset) run: cmake --preset default - - name: Build test_components - run: cmake --build build --target test_components -j + - name: Build all + run: cmake --build build -j + + - name: Upload build artifact + uses: actions/upload-artifact@v4 + with: + name: build-tree + path: build + retention-days: 1 + + test_components: + name: Run test_components + needs: build + runs-on: ubuntu-latest + + steps: + - name: Download build + uses: actions/download-artifact@v4 + with: + name: build-tree + path: build - name: Run test_components working-directory: build From f80bf87d5984f6d359ef599a3714290e02609b85 Mon Sep 17 00:00:00 2001 From: mattcapa Date: Wed, 24 Jun 2026 16:52:18 +0200 Subject: [PATCH 3/3] ci: split Linux build into a reusable workflow that tests depend on --- .github/workflows/linux_build.yml | 174 ++++++++++++++++++++++++++++++ .github/workflows/linux_tests.yml | 103 +++++++----------- 2 files changed, 210 insertions(+), 67 deletions(-) create mode 100644 .github/workflows/linux_build.yml diff --git a/.github/workflows/linux_build.yml b/.github/workflows/linux_build.yml new file mode 100644 index 00000000..faab90c8 --- /dev/null +++ b/.github/workflows/linux_build.yml @@ -0,0 +1,174 @@ +name: Linux build + +# This workflow can be triggered manually OR called by another workflow +# (e.g. linux_tests.yml) via `workflow_call`. It does NOT trigger on push or +# pull_request directly — the test workflow is the push/PR entry point, so +# the build does not run twice. +on: + workflow_dispatch: + workflow_call: + inputs: + preset: + description: "CMake preset to build" + required: false + type: string + default: "default" + artifact-name: + description: "Name of the uploaded build artifact" + required: false + type: string + default: "linux-build-tree" + artifact-retention-days: + description: "How long to keep the build artifact" + required: false + type: number + default: 3 + outputs: + artifact-name: + description: "Name of the uploaded build artifact" + value: ${{ inputs.artifact-name }} + +# Avoid stacking redundant standalone runs on the same ref. +concurrency: + group: linux-build-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: Build (${{ inputs.preset || 'default' }}) + runs-on: ubuntu-latest + timeout-minutes: 180 + + env: + # vcpkg *tool* clone (separate from external/vcpkg, which only holds the + # seahowl manifest + overlay ports). + VCPKG_ROOT: ${{ github.workspace }}/.vcpkg + # Cache built vcpkg packages in the GH Actions cache. + VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" + VCPKG_DISABLE_METRICS: "1" + # Keep memory/CPU usage modest on the standard GH runner. + VCPKG_MAX_CONCURRENCY: "2" + CMAKE_BUILD_PARALLEL_LEVEL: "2" + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 1 + + - name: Read pinned vcpkg baseline + id: vcpkg + run: | + set -euo pipefail + baseline=$(python3 -c \ + "import json; \ + print(json.load(open('external/vcpkg/vcpkg-configuration.json'))['default-registry']['baseline'])") + echo "baseline=$baseline" >> "$GITHUB_OUTPUT" + echo "Pinned vcpkg baseline: $baseline" + + - name: Install system build prerequisites + run: | + set -euxo pipefail + sudo apt-get update + sudo apt-get install -y --no-install-recommends \ + build-essential cmake ninja-build pkg-config \ + gfortran \ + curl zip unzip tar ca-certificates git \ + autoconf automake autoconf-archive libtool \ + bison flex \ + python3 python3-pip + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Cache vcpkg tool clone + id: cache-vcpkg-tool + uses: actions/cache@v4 + with: + path: ${{ env.VCPKG_ROOT }} + key: vcpkg-tool-${{ runner.os }}-${{ steps.vcpkg.outputs.baseline }} + + - name: Clone vcpkg at pinned baseline + if: steps.cache-vcpkg-tool.outputs.cache-hit != 'true' + run: | + set -euxo pipefail + rm -rf "$VCPKG_ROOT" + git clone https://github.com/microsoft/vcpkg.git "$VCPKG_ROOT" + git -C "$VCPKG_ROOT" checkout "${{ steps.vcpkg.outputs.baseline }}" + + - name: Bootstrap vcpkg if needed + run: | + set -euxo pipefail + if [ ! -x "$VCPKG_ROOT/vcpkg" ]; then + "$VCPKG_ROOT/bootstrap-vcpkg.sh" -disableMetrics + fi + "$VCPKG_ROOT/vcpkg" version + + # Required for VCPKG_BINARY_SOURCES=x-gha + - name: Export GitHub Actions cache env for vcpkg + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Configure + run: cmake --preset ${{ inputs.preset || 'default' }} + + - name: Build + run: cmake --build build + + # Tar the build tree so file permissions (executable bit on test + # binaries, symlinks on .so versions) survive the artifact round-trip. + - name: Package build tree + if: success() + run: | + set -euxo pipefail + tar --exclude='build/vcpkg_installed/vcpkg/buildtrees' \ + --exclude='build/vcpkg_installed/vcpkg/downloads' \ + --exclude='build/vcpkg_installed/vcpkg/packages' \ + --exclude='build/_deps' \ + -czf build-tree.tar.gz build + + - name: Upload build artifact + if: success() + uses: actions/upload-artifact@v4 + with: + name: ${{ inputs.artifact-name || 'linux-build-tree' }} + path: build-tree.tar.gz + if-no-files-found: error + retention-days: ${{ inputs.artifact-retention-days || 3 }} + + # --- Diagnostics on failure --------------------------------------------- + + - name: Collect failure logs + if: failure() + run: | + set +e + mkdir -p ci-logs + if [ -d build/vcpkg_installed/vcpkg ]; then + find build/vcpkg_installed/vcpkg -maxdepth 4 \ + \( -name 'install-*.log' \ + -o -name 'config-*.log' \ + -o -name 'build-*.log' \ + -o -name 'issue_body.md' \) \ + -exec cp --parents {} ci-logs/ \; + fi + for f in build/CMakeFiles/CMakeOutput.log \ + build/CMakeFiles/CMakeError.log \ + build/CMakeCache.txt; do + [ -f "$f" ] && cp --parents "$f" ci-logs/ + done + ls -R ci-logs || true + + - name: Upload failure logs + if: failure() + uses: actions/upload-artifact@v4 + with: + name: linux-build-failure-logs + path: ci-logs + if-no-files-found: ignore + retention-days: 7 diff --git a/.github/workflows/linux_tests.yml b/.github/workflows/linux_tests.yml index 48a9c7fb..ca87c11c 100644 --- a/.github/workflows/linux_tests.yml +++ b/.github/workflows/linux_tests.yml @@ -7,95 +7,64 @@ on: branches: [main, dev] workflow_dispatch: +concurrency: + group: linux-tests-${{ github.ref }} + cancel-in-progress: true + jobs: build: + # Call the reusable build workflow. Tests cannot run unless this succeeds. name: Build - runs-on: ubuntu-latest + uses: ./.github/workflows/linux_build.yml + with: + preset: default + artifact-name: linux-build-tree + artifact-retention-days: 1 - env: - VCPKG_ROOT: ${{ github.workspace }}/external/vcpkg - # Cache vcpkg-built packages in the GH Actions cache - VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" - # Keep vcpkg memory/CPU usage modest on the GH runner - VCPKG_MAX_CONCURRENCY: "2" + test_components: + name: Run test_components + needs: build + runs-on: ubuntu-latest + timeout-minutes: 30 steps: + # The test_components binary embeds SEAHOWL_DATADIR pointing at the + # source tree at configure time (see CMakeLists.txt). Re-checkout at the + # same workspace path so those paths resolve. - name: Checkout uses: actions/checkout@v4 with: submodules: recursive - fetch-depth: 0 + fetch-depth: 1 - - name: Install build prerequisites + - name: Install runtime prerequisites run: | + set -euxo pipefail sudo apt-get update - sudo apt-get install -y --no-install-recommends \ - build-essential \ - ninja-build \ - gfortran \ - pkg-config \ - curl zip unzip tar \ - autoconf automake autoconf-archive \ - bison flex \ - python3 python3-pip + sudo apt-get install -y --no-install-recommends cmake ninja-build - - name: Set up Python - uses: actions/setup-python@v5 + - name: Download build artifact + uses: actions/download-artifact@v4 with: - python-version: "3.11" + name: ${{ needs.build.outputs.artifact-name }} + path: . - - name: Bootstrap vcpkg (clone if missing) + - name: Unpack build tree run: | - if [ ! -d "$VCPKG_ROOT" ]; then - git clone --depth 1 https://github.com/microsoft/vcpkg "$VCPKG_ROOT" - fi - if [ ! -x "$VCPKG_ROOT/vcpkg" ]; then - (cd "$VCPKG_ROOT" && ./bootstrap-vcpkg.sh -disableMetrics) - fi - - # Required for VCPKG_BINARY_SOURCES=x-gha - - name: Export GitHub Actions cache env for vcpkg - uses: actions/github-script@v7 - with: - script: | - core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); - core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); - - - name: Configure (default preset) - run: cmake --preset default - - - name: Build all - run: cmake --build build -j - - - name: Upload build artifact - uses: actions/upload-artifact@v4 - with: - name: build-tree - path: build - retention-days: 1 - - test_components: - name: Run test_components - needs: build - runs-on: ubuntu-latest - - steps: - - name: Download build - uses: actions/download-artifact@v4 - with: - name: build-tree - path: build + set -euxo pipefail + tar -xzf build-tree.tar.gz + rm -f build-tree.tar.gz + ls build/tests || true - name: Run test_components working-directory: build - run: ctest --output-on-failure -R '^test_components$' + run: ctest --output-on-failure -R '^test_components$' --no-tests=error - - name: Upload test logs on failure + - name: Upload ctest logs on failure if: failure() uses: actions/upload-artifact@v4 with: - name: test-logs - path: | - build/Testing/**/*.log - build/Testing/**/LastTest.log + name: test_components-logs + path: build/Testing if-no-files-found: ignore + retention-days: 7