From 0812a35ce18dbd27ee559742ee5324be9265583b Mon Sep 17 00:00:00 2001 From: Redlex Gilgamesh Date: Mon, 8 Jun 2026 14:27:40 +0200 Subject: [PATCH] ci: prefer self-hosted runners with GitHub-hosted fallback Wrap elixir/node/python jobs in the self-hosted-preferred pattern: each canonical job now depends on a continue-on-error self-hosted leg and only re-runs on GitHub-hosted runners when the self-hosted leg did not pass. The Node/archgate leg routes to the macOS self-hosted runner (archgate has no linux/arm64 binary). Original check-name contexts (Elixir tests, Node.js tests & ADR check, Python pipeline-runner, All checks passed) are preserved exactly. Part of r3dlex/github-runners-for-repo#12 Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/ci.yml | 132 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ed80d3a..5b25fec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,60 +14,181 @@ jobs: # -------------------------------------------------------------------------- # Elixir / Mix: all umbrella apps # -------------------------------------------------------------------------- + _elixir-self-hosted: + name: "Elixir tests (self-hosted)" + runs-on: [self-hosted, ubuntu-latest] + continue-on-error: true + timeout-minutes: 15 + outputs: + passed: ${{ steps.mark.outputs.passed }} + steps: + - uses: actions/checkout@v4 + + - uses: erlef/setup-beam@v1 + with: + otp-version: "27" + elixir-version: "1.17" + + - name: Install dependencies (excluding musician_tui — ratatouille→ex_termbox uses removed Python imp module) + run: mix deps.get --exclude-apps musician_tui + + - name: Remove broken transitive deps and update lock + run: | + rm -rf deps/ex_termbox deps/ratatouille _build/MIX/@lib/musician_tui 2>/dev/null || true + mix lock --remove ratatouille 2>/dev/null || true + + - name: Run tests with coverage and generate XML + run: bash .github/workflows/gen-coverage.sh + + - name: Check coverage thresholds + run: elixir .github/workflows/check-coverage.exs + + - id: mark + if: success() + run: echo "passed=true" >> "$GITHUB_OUTPUT" + elixir: name: Elixir tests + needs: _elixir-self-hosted + if: always() runs-on: ubuntu-latest timeout-minutes: 15 steps: + - name: Route + run: echo "self-hosted passed=${{ needs._elixir-self-hosted.outputs.passed }}" + - uses: actions/checkout@v4 + if: needs._elixir-self-hosted.outputs.passed != 'true' - uses: erlef/setup-beam@v1 + if: needs._elixir-self-hosted.outputs.passed != 'true' with: otp-version: "27" elixir-version: "1.17" - name: Install dependencies (excluding musician_tui — ratatouille→ex_termbox uses removed Python imp module) + if: needs._elixir-self-hosted.outputs.passed != 'true' run: mix deps.get --exclude-apps musician_tui - name: Remove broken transitive deps and update lock + if: needs._elixir-self-hosted.outputs.passed != 'true' run: | rm -rf deps/ex_termbox deps/ratatouille _build/MIX/@lib/musician_tui 2>/dev/null || true mix lock --remove ratatouille 2>/dev/null || true - name: Run tests with coverage and generate XML + if: needs._elixir-self-hosted.outputs.passed != 'true' run: bash .github/workflows/gen-coverage.sh - name: Check coverage thresholds + if: needs._elixir-self-hosted.outputs.passed != 'true' run: elixir .github/workflows/check-coverage.exs # -------------------------------------------------------------------------- # Node.js: tests + archgate ADR check # -------------------------------------------------------------------------- + _node-self-hosted: + name: "Node.js tests & ADR check (self-hosted)" + # archgate ships no linux/arm64 binary; route to the macOS (darwin/arm64) self-hosted runner where it is supported. + runs-on: [self-hosted, macOS] + continue-on-error: true + timeout-minutes: 15 + outputs: + passed: ${{ steps.mark.outputs.passed }} + steps: + - uses: actions/checkout@v4 + + - uses: jdx/mise-action@v2 + with: + cache: true + + - name: Install Node.js dependencies + run: npm ci --ignore-scripts + + - name: Run tests with coverage + run: npx vitest run --coverage + + - name: Archgate ADR compliance check + run: npx --yes archgate@latest check + + - id: mark + if: success() + run: echo "passed=true" >> "$GITHUB_OUTPUT" + node: name: Node.js tests & ADR check + needs: _node-self-hosted + if: always() runs-on: ubuntu-latest timeout-minutes: 15 steps: + - name: Route + run: echo "self-hosted passed=${{ needs._node-self-hosted.outputs.passed }}" + - uses: actions/checkout@v4 + if: needs._node-self-hosted.outputs.passed != 'true' - uses: jdx/mise-action@v2 + if: needs._node-self-hosted.outputs.passed != 'true' with: cache: true - name: Install Node.js dependencies + if: needs._node-self-hosted.outputs.passed != 'true' run: npm ci --ignore-scripts - name: Run tests with coverage + if: needs._node-self-hosted.outputs.passed != 'true' run: npx vitest run --coverage - name: Archgate ADR compliance check + if: needs._node-self-hosted.outputs.passed != 'true' run: npx --yes archgate@latest check # -------------------------------------------------------------------------- # Python: pipeline runner tests + lint # -------------------------------------------------------------------------- + _python-self-hosted: + name: "Python pipeline-runner (self-hosted)" + runs-on: [self-hosted, ubuntu-latest] + continue-on-error: true + timeout-minutes: 10 + defaults: + run: + working-directory: tools/pipeline_runner + outputs: + passed: ${{ steps.mark.outputs.passed }} + steps: + - uses: actions/checkout@v4 + + - uses: jdx/mise-action@v2 + with: + cache: true + + - name: Install Poetry + run: pipx install poetry + + - name: Install dependencies + run: poetry install --no-interaction + + - name: Ruff lint + run: poetry run ruff check . + + - name: Mypy type check + run: poetry run mypy pipeline_runner + + - name: Run tests + run: poetry run pytest --tb=short + + - id: mark + if: success() + working-directory: ${{ github.workspace }} + run: echo "passed=true" >> "$GITHUB_OUTPUT" + python: name: Python pipeline-runner + needs: _python-self-hosted + if: always() runs-on: ubuntu-latest timeout-minutes: 10 defaults: @@ -75,25 +196,36 @@ jobs: working-directory: tools/pipeline_runner steps: + - name: Route + working-directory: ${{ github.workspace }} + run: echo "self-hosted passed=${{ needs._python-self-hosted.outputs.passed }}" + - uses: actions/checkout@v4 + if: needs._python-self-hosted.outputs.passed != 'true' - uses: jdx/mise-action@v2 + if: needs._python-self-hosted.outputs.passed != 'true' with: cache: true - name: Install Poetry + if: needs._python-self-hosted.outputs.passed != 'true' run: pipx install poetry - name: Install dependencies + if: needs._python-self-hosted.outputs.passed != 'true' run: poetry install --no-interaction - name: Ruff lint + if: needs._python-self-hosted.outputs.passed != 'true' run: poetry run ruff check . - name: Mypy type check + if: needs._python-self-hosted.outputs.passed != 'true' run: poetry run mypy pipeline_runner - name: Run tests + if: needs._python-self-hosted.outputs.passed != 'true' run: poetry run pytest --tb=short # --------------------------------------------------------------------------