Notcurses-Native.git | .github/workflows/ | _verify-linux-musl-x86_64.yml


# Reusable workflow: verify the linux-x86_64-musl prebuilt # installs + loads on Alpine. Source-builds Rakudo inside the # container via rakubrew (apk's `rakudo` is too old to accept # `Callable` in NativeCall's `is native(...)` trait, which # Notcurses::Native uses for lazy lib-path resolution). # # Why docker-run from a native ubuntu-22.04 host instead of GHA's # `container:` directive: GHA's Node 24 JS-action runtime needs # glibc — alpine ships musl, so actions/checkout etc. can't run # inside an alpine container. # # The Rakudo source-build (~10-20 min on first run) is split from # the test phase so a test failure doesn't bust the cache. Sequence: # # 1. cache/restore — pull cached $RAKUBREW_HOME if present. # 2. docker-run prep-musl-rakudo.sh — build Rakudo (idempotent; # short-circuits on cache hit). # 3. cache/save — save the Rakudo build immediately on success, # BEFORE tests can fail. Guarded by `cache-hit != 'true'`. # 4. docker-run verify-musl-tests.sh — zef install + prove6 + xt # + source-build pass. Cache is already preserved if this fails. name: _verify-linux-musl-x86_64 on: workflow_call: env: NOTCURSES_NATIVE_REQUIRE_SHIM: '1' RAKUDO_VERSION: '2026.03' jobs: verify: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v6 with: { submodules: recursive } - name: Restore cached Rakudo (alpine x86_64) # Key has `-rakudo-only-v2` suffix to invalidate caches that # carried stale zef state in # `versions/moar-*/install/share/perl6/site/`. With that # stale state, `zef install` short-circuits ("All candidates # are currently installed") and Build.rakumod never stages # the prebuilt notcurses bundle → dlopen fails at test time. id: rakubrew-cache uses: actions/cache/restore@v4 with: path: _ci-cache/rakubrew-alpine-x86_64 key: rakubrew-alpine-x86_64-${{ env.RAKUDO_VERSION }}-rakudo-only-v2 - name: Pull alpine:3.20 run: docker pull alpine:3.20 - name: Build Rakudo in alpine:3.20 (cacheable phase) run: | mkdir -p _ci-cache/rakubrew-alpine-x86_64 docker run --rm \ -v "$PWD:/work" -w /work \ -v "$PWD/_ci-cache/rakubrew-alpine-x86_64:/root/.rakubrew" \ -e RAKUDO_VERSION="${{ env.RAKUDO_VERSION }}" \ -e RAKUBREW_HOME=/root/.rakubrew \ alpine:3.20 \ sh -c 'apk add --no-cache bash >/dev/null && bash scripts/ci/prep-musl-rakudo.sh' - name: Fix cache permissions before save (docker ran as root) # docker mounted /root/.rakubrew as root-owned; actions/cache # runs as `runner` and can't tar root-owned files for the # cache save. chown back to the runner user before save. run: sudo chown -R "$(id -u):$(id -g)" _ci-cache/rakubrew-alpine-x86_64 - name: Strip zef module state — we cache Rakudo only, not installs # Belt-and-braces with the bumped cache key. Strip happens at # the host level (not inside docker) — the bind-mount makes # this safe and avoids spinning up an extra container. run: rm -rf _ci-cache/rakubrew-alpine-x86_64/versions/moar-*/install/share/perl6/site || true - name: Save Rakudo cache (build succeeded — independent of tests) # Save here, immediately after a successful Rakudo build, # so a downstream test failure doesn't invalidate the # cache. Guarded so we don't churn the cache on a hit. if: steps.rakubrew-cache.outputs.cache-hit != 'true' uses: actions/cache/save@v4 with: path: _ci-cache/rakubrew-alpine-x86_64 key: rakubrew-alpine-x86_64-${{ env.RAKUDO_VERSION }}-rakudo-only-v2 - name: Run tests in alpine:3.20 (flaky phase) run: | docker run --rm \ -v "$PWD:/work" -w /work \ -v "$PWD/_ci-cache/rakubrew-alpine-x86_64:/root/.rakubrew" \ -e RAKUDO_VERSION="${{ env.RAKUDO_VERSION }}" \ -e RAKUBREW_HOME=/root/.rakubrew \ -e NOTCURSES_NATIVE_REQUIRE_SHIM \ -e TERM=xterm \ -e COLORTERM=truecolor \ -e LANG=C.UTF-8 \ -e LC_ALL=C.UTF-8 \ alpine:3.20 \ sh -c 'apk add --no-cache bash >/dev/null && bash scripts/ci/verify-musl-tests.sh'