Skip to content

Commit ea69cbb

Browse files
hsyl20claude
andcommitted
ci: test ghcup install of the bindist on every platform
Add plinth-ghcup-test-{linux,linux-musl,macos,windows} jobs that install each platform's bindist as the custom `plinth` ghcup tool -- the same path end users take -- on every push, not just on tags. This catches a broken dlInstallSpec, generator, or metadata-schema drift in the PR that introduces it rather than only at release time. - Refactor plinth-ghcup-test.sh to run from just a bindist tarball (no boot GHC / source tree): derive the version from the tarball name, locate ghcup's dirs via `ghcup whereis`, and translate MSYS<->native paths with cygpath so it works on Windows too. The script now capability-gates on ghcup >= 0.2.1.0. - Keep the ghcup prefix short on Windows. ghcup stages an install in a temp dir whose layout repeats the whole install path underneath it, so every character of GHCUP_INSTALL_BASE_PREFIX is paid for twice; with the prefix under MSYS's /tmp, the staged path of GHC's deepest library files reached 261 characters -- one over MAX_PATH -- and the copy failed with "The system cannot find the path specified". Fall back to $TMPDIR with a warning when the drive root is not usable (UNC workspace, read-only root). - Make ghcup failures legible: ghcup wraps its error codes in an OSC-8 hyperlink escape, and GitHub's log viewer swallows it along with the rest of the line, hiding every error behind a bare "[". Strip terminal escapes from ghcup's output and dump ghcup's own logs before the test env is removed. - Verify the uplc-* links with -e rather than -L, so a link towards a file the bindist does not ship fails the test instead of being shipped broken. - Assert the musl job really received the musl bindist (EXPECT_MUSL=1), and give Alpine the GNU coreutils/findutils/grep that the bindist's `make install` (which ghcup runs) is exercised with upstream. - Gate the `release` job on these install tests (they transitively require the builds), and drop its now-redundant inline validation step. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent a2bcc57 commit ea69cbb

2 files changed

Lines changed: 359 additions & 101 deletions

File tree

.github/workflows/ci.yml

Lines changed: 189 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,187 @@ jobs:
615615
- name: Test uplc-ghc
616616
run: JOBS=1 GHC="$GITHUB_WORKSPACE/_build/install/bin/uplc-ghc" ./plinth-test.sh
617617

618+
# ghcup install tests: verify each platform's bindist installs cleanly as the
619+
# custom `plinth` ghcup tool -- the same path end users take -- on every push,
620+
# not just on tags. Each mirrors its plinth-test-* sibling but installs via
621+
# ghcup + generate-ghcup-metadata.py (file:// metadata) instead of a bare
622+
# configure+make, so a broken dlInstallSpec / generator / metadata schema is
623+
# caught in the PR that introduces it. plinth-ghcup-test.sh does the work; it
624+
# needs only the bindist tarball + python3 + a ghcup >= 0.2.1.0 (no GHC
625+
# rebuild, no submodules -- the sample it compiles is plain Haskell).
626+
plinth-ghcup-test-linux:
627+
name: plinth-ghcup-test / ${{ matrix.os }} / ghc ${{ matrix.ghc }}
628+
needs: plinth-build-linux
629+
runs-on: ${{ matrix.os }}
630+
strategy:
631+
fail-fast: false
632+
matrix:
633+
os: [ubuntu-latest, ubuntu-24.04-arm]
634+
ghc: ['9.6.7']
635+
636+
steps:
637+
638+
- uses: actions/checkout@v4
639+
with:
640+
submodules: false
641+
642+
- name: Download uplc-ghc bindist
643+
uses: actions/download-artifact@v4
644+
with:
645+
name: plinth-bindist-${{ matrix.os }}-${{ matrix.ghc }}
646+
path: _build/artifact
647+
648+
# A stock ghcup for this architecture; the installer DSL needs >= 0.2.1.0
649+
# (plinth-ghcup-test.sh capability-gates on it).
650+
- name: Install stock ghcup
651+
run: |
652+
set -eux
653+
mkdir -p "$HOME/.local/bin"
654+
curl -fL "https://downloads.haskell.org/~ghcup/$(uname -m)-linux-ghcup" \
655+
-o "$HOME/.local/bin/ghcup"
656+
chmod +x "$HOME/.local/bin/ghcup"
657+
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
658+
659+
- name: Install and test uplc-ghc via ghcup
660+
run: BINDIST_DIR=_build/artifact ./plinth-ghcup-test.sh
661+
662+
plinth-ghcup-test-linux-musl:
663+
name: plinth-ghcup-test / ${{ matrix.os }} (musl) / ghc ${{ matrix.ghc }}
664+
needs: plinth-build-linux-musl
665+
runs-on: ${{ matrix.os }}
666+
strategy:
667+
fail-fast: false
668+
matrix:
669+
os: [ubuntu-latest, ubuntu-24.04-arm]
670+
ghc: ['9.6.7']
671+
672+
steps:
673+
674+
- uses: actions/checkout@v4
675+
with:
676+
submodules: false
677+
678+
- name: Download uplc-ghc bindist (musl)
679+
uses: actions/download-artifact@v4
680+
with:
681+
name: plinth-bindist-musl-${{ matrix.os }}-${{ matrix.ghc }}
682+
path: _build/artifact
683+
684+
# Run inside Alpine so the musl uplc-ghc can execute. Unlike the build/test
685+
# jobs we do NOT source alpine-setup.sh: that bootstraps a full boot GHC +
686+
# cabal we would never use here. Instead install just the deps needed to run
687+
# uplc-ghc and link the sample, and download the ghcup binary directly --
688+
# the same x86_64/aarch64-linux ghcup the official installer uses on Alpine.
689+
#
690+
# coreutils/findutils/grep are the GNU tools the bindist's `make install`
691+
# (which ghcup runs for us) is exercised with upstream; busybox's applets
692+
# differ in flag support, so don't rely on them for that path.
693+
#
694+
# EXPECT_MUSL=1 asserts the artifact really is the musl bindist: the ghcup
695+
# platform is derived from the bindist name, and a musl bindist mislabelled
696+
# as glibc installs fine here while being broken for users on Alpine.
697+
- name: Install and test uplc-ghc via ghcup (Alpine/musl)
698+
run: |
699+
docker run --rm \
700+
-v "$GITHUB_WORKSPACE:/workspace" -w /workspace \
701+
-e LANG=C.UTF-8 -e LC_ALL=C.UTF-8 \
702+
alpine:3.20 sh -c '
703+
set -eux
704+
apk add --no-cache bash build-base coreutils curl findutils grep \
705+
gmp-dev ncurses-dev python3 tar xz
706+
mkdir -p "$HOME/.local/bin"
707+
curl -fL "https://downloads.haskell.org/~ghcup/$(uname -m)-linux-ghcup" \
708+
-o "$HOME/.local/bin/ghcup"
709+
chmod +x "$HOME/.local/bin/ghcup"
710+
BINDIST_DIR=_build/artifact GHCUP_BIN="$HOME/.local/bin/ghcup" \
711+
EXPECT_MUSL=1 bash ./plinth-ghcup-test.sh
712+
'
713+
714+
plinth-ghcup-test-macos:
715+
name: plinth-ghcup-test / macos-15 / ghc ${{ matrix.ghc }}
716+
needs: plinth-build-macos
717+
runs-on: macos-15
718+
strategy:
719+
fail-fast: false
720+
matrix:
721+
ghc: ['9.6.7']
722+
723+
steps:
724+
725+
- uses: actions/checkout@v4
726+
with:
727+
submodules: false
728+
729+
- name: Download uplc-ghc bindist
730+
uses: actions/download-artifact@v4
731+
with:
732+
name: plinth-bindist-macos-${{ matrix.ghc }}
733+
path: _build/artifact
734+
735+
# macos-15 is Apple Silicon (aarch64-apple-darwin).
736+
- name: Install stock ghcup
737+
run: |
738+
set -eux
739+
mkdir -p "$HOME/.local/bin"
740+
curl -fL "https://downloads.haskell.org/~ghcup/aarch64-apple-darwin-ghcup" \
741+
-o "$HOME/.local/bin/ghcup"
742+
chmod +x "$HOME/.local/bin/ghcup"
743+
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
744+
745+
- name: Install and test uplc-ghc via ghcup
746+
run: BINDIST_DIR=_build/artifact ./plinth-ghcup-test.sh
747+
748+
plinth-ghcup-test-windows:
749+
name: plinth-ghcup-test / windows-latest / ghc ${{ matrix.ghc }}
750+
needs: plinth-build-windows
751+
runs-on: windows-latest
752+
strategy:
753+
fail-fast: false
754+
matrix:
755+
ghc: ['9.6.7']
756+
defaults:
757+
run:
758+
shell: msys2 {0}
759+
760+
steps:
761+
762+
# The bindist / ghcup use symlinks; enable them before checkout.
763+
- name: Configure git for Windows
764+
shell: bash
765+
run: git config --global core.symlinks true
766+
767+
- uses: actions/checkout@v4
768+
with:
769+
submodules: false
770+
771+
# python3 (for generate-ghcup-metadata.py) + tar/xz/curl to fetch ghcup and
772+
# unpack. cygpath (used by plinth-ghcup-test.sh for native/MSYS path
773+
# translation) is part of the base MSYS2 install.
774+
- name: Setup MSYS2
775+
uses: msys2/setup-msys2@v2
776+
with:
777+
msystem: MINGW64
778+
path-type: inherit
779+
update: false
780+
install: >-
781+
tar xz curl mingw-w64-x86_64-python
782+
783+
- name: Download uplc-ghc bindist
784+
uses: actions/download-artifact@v4
785+
with:
786+
name: plinth-bindist-windows-${{ matrix.ghc }}
787+
path: _build/artifact
788+
789+
- name: Install stock ghcup
790+
run: |
791+
set -eux
792+
mkdir -p "$HOME/.local/bin"
793+
curl -fL "https://downloads.haskell.org/~ghcup/x86_64-mingw64-ghcup.exe" \
794+
-o "$HOME/.local/bin/ghcup.exe"
795+
796+
- name: Install and test uplc-ghc via ghcup
797+
run: BINDIST_DIR=_build/artifact GHCUP_BIN="$HOME/.local/bin/ghcup.exe" ./plinth-ghcup-test.sh
798+
618799
# Note [ghcup release channel]
619800
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
620801
# On a v* tag, publish the per-platform bindists as a GitHub Release and
@@ -634,11 +815,13 @@ jobs:
634815
release:
635816
name: release / ghcup channel
636817
if: startsWith(github.ref, 'refs/tags/')
818+
# Gate publishing on the per-platform ghcup install tests (which transitively
819+
# require the build jobs and their uploaded bindist artifacts).
637820
needs:
638-
- plinth-build-linux
639-
- plinth-build-linux-musl
640-
- plinth-build-windows
641-
- plinth-build-macos
821+
- plinth-ghcup-test-linux
822+
- plinth-ghcup-test-linux-musl
823+
- plinth-ghcup-test-windows
824+
- plinth-ghcup-test-macos
642825
runs-on: ubuntu-latest
643826
# Overrides the top-level `contents: read`: this job creates a Release and
644827
# pushes the regenerated channel to gh-pages.
@@ -669,50 +852,8 @@ jobs:
669852
# ghcup tool version: the tag without the leading 'v'.
670853
echo "VERSION=${TAG#v}" >> "$GITHUB_ENV"
671854
672-
# A stock ghcup for the pre-publish validation gate. Download the latest
673-
# released ghcup; the installer DSL for custom tools needs >= 0.2.1.0.
674-
- name: Install stock ghcup
675-
run: |
676-
set -eux
677-
mkdir -p "$HOME/.local/bin"
678-
curl -fL https://downloads.haskell.org/~ghcup/x86_64-linux-ghcup \
679-
-o "$HOME/.local/bin/ghcup"
680-
chmod +x "$HOME/.local/bin/ghcup"
681-
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
682-
"$HOME/.local/bin/ghcup" --version
683-
684-
# Validation gate: generate metadata with file:// URLs to the downloaded
685-
# tarballs and actually install the linux bindist as the plinth tool. This
686-
# exercises the installer DSL (configure + make install + symlinks) before
687-
# anything is published.
688-
- name: Validate ghcup install (linux bindist)
689-
run: |
690-
set -eux
691-
python3 generate-ghcup-metadata.py \
692-
--version "$VERSION" \
693-
--base-url "file://$PWD/dist" \
694-
--db "$RUNNER_TEMP/validate.versions.json" \
695-
--output "$RUNNER_TEMP/ghcup-plinth-validate.yaml" \
696-
--set-latest \
697-
dist/*.tar.xz
698-
# Capability gate: a ghcup that predates the installer DSL (< 0.2.1.0)
699-
# won't recognize the custom `plinth` tool. Fail loudly with an upgrade
700-
# hint rather than with a cryptic error deep in `install`.
701-
if ! ghcup --url-source "file://$RUNNER_TEMP/ghcup-plinth-validate.yaml" \
702-
list -t plinth 2>/dev/null | grep -q plinth; then
703-
echo "error: this ghcup ($(ghcup --version)) does not recognize the custom"
704-
echo " 'plinth' tool. The installer DSL needs ghcup >= 0.2.1.0."
705-
exit 1
706-
fi
707-
export GHCUP_INSTALL_BASE_PREFIX="$RUNNER_TEMP/ghcup-validate"
708-
export XDG_CONFIG_HOME="$RUNNER_TEMP/ghcup-validate/config"
709-
export XDG_DATA_HOME="$RUNNER_TEMP/ghcup-validate/data"
710-
mkdir -p "$XDG_CONFIG_HOME" "$XDG_DATA_HOME"
711-
ghcup --url-source "file://$RUNNER_TEMP/ghcup-plinth-validate.yaml" \
712-
install plinth "$VERSION"
713-
ghcup --url-source "file://$RUNNER_TEMP/ghcup-plinth-validate.yaml" \
714-
set plinth "$VERSION"
715-
"$GHCUP_INSTALL_BASE_PREFIX/.ghcup/bin/uplc-ghc" --version
855+
# The install is already validated end-to-end on every platform by the
856+
# plinth-ghcup-test-* jobs this job `needs`, so no re-validation here.
716857

717858
# Publish the Release with all tarballs. Create it if missing, otherwise
718859
# (re-)upload the assets.

0 commit comments

Comments
 (0)