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


# 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'