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'