Skip to content

Add a Windows plinth-test CI job #121

Add a Windows plinth-test CI job

Add a Windows plinth-test CI job #121

Workflow file for this run

name: CI
on:
pull_request:
types: [opened, synchronize]
push:
branches: [master, ghc-9.6-plinth]
workflow_dispatch:
# Least-privilege GITHUB_TOKEN: jobs only check out code (contents: read).
# Submodules use a dedicated SSH key and artifacts use the Actions runtime
# token, so no write scopes are needed.
permissions:
contents: read
jobs:
plinth-build-linux:
name: plinth-build / ${{ matrix.os }} / ghc ${{ matrix.ghc }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
ghc: ['9.6.7']
steps:
# checkout first: the local composite action (.github/actions/prepare) must
# be on disk before the runner can resolve it.
- uses: actions/checkout@v4
with:
submodules: false
- uses: ./.github/actions/prepare
with:
ghc-version: ${{ matrix.ghc }}
# BINDIST=1 produces the fixed-up uplc-ghc bindist (+ .tar.xz archive) while
# keeping the lean dev flavour. The plinth-test job consumes that archive.
- name: Build uplc-ghc bindist
run: BINDIST=1 ./plinth-build.sh
- name: Upload uplc-ghc bindist
uses: actions/upload-artifact@v4
with:
# key by platform + GHC so multiple build matrix legs (or another job)
# never collide on the artifact name within a single run. See the
# matching download in the plinth-test job, which shares this matrix.
name: plinth-bindist-${{ matrix.os }}-${{ matrix.ghc }}
path: _build/bindist/*.tar.xz
retention-days: 1
# the archive is already xz-compressed; don't re-zip it
compression-level: 0
# plinth-test runs in its own job for a separate status check and timeout
# budget. It depends on `plinth-build-linux` (it can't run in parallel: it
# needs the built compiler), downloading the bindist archive instead of
# rebuilding GHC. Its matrix mirrors the build so the artifact-name key
# matches per leg.
plinth-test-linux:
name: plinth-test / ${{ matrix.os }} / ghc ${{ matrix.ghc }}
needs: plinth-build-linux
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
ghc: ['9.6.7']
steps:
# checkout first: the local composite action (.github/actions/prepare) must
# be on disk before the runner can resolve it. The prepare action also
# fetches submodules, which the test needs: plinth/test/cabal.project pulls
# plutus-tx/plutus-core/plutus-ledger-api from the plutus submodule.
- uses: actions/checkout@v4
with:
submodules: false
- uses: ./.github/actions/prepare
with:
ghc-version: ${{ matrix.ghc }}
# A single Plinth plugin (Core -> PLC) compile of a makeLift-heavy module
# (PlutusLedgerApi.V3.Contexts) spikes past the ~16 GB runner RAM and gets
# OOM-killed even with JOBS=1. Add a 16 GB swapfile on the large /mnt disk
# so the spike spills to swap and the compile completes.
- name: Add 16 GB swap
run: |
sudo fallocate -l 16G /mnt/swapfile
sudo chmod 600 /mnt/swapfile
sudo mkswap /mnt/swapfile
sudo swapon /mnt/swapfile
swapon --show
free -h
- name: Download uplc-ghc bindist
uses: actions/download-artifact@v4
with:
# matches the plinth-build upload name; both jobs share the same matrix.
name: plinth-bindist-${{ matrix.os }}-${{ matrix.ghc }}
path: _build/artifact
# Install the bindist with the usual configure + make install; the bindist's
# wrappers/ dir (added by the BINDIST fixup) makes this produce bin/uplc-ghc.
# Each step is guarded so a missing artifact or failed install fails loudly
# here, not with a confusing error deep in the test.
- name: Install uplc-ghc bindist
run: |
shopt -s nullglob
archives=(_build/artifact/*.tar.xz)
if [ ${#archives[@]} -ne 1 ]; then
echo "error: expected exactly one bindist archive, found: ${archives[*]:-none}"
exit 1
fi
mkdir -p _build/bindist
echo "extracting ${archives[0]}"
tar --xz -xf "${archives[0]}" -C _build/bindist
bindirs=(_build/bindist/ghc-*)
if [ ${#bindirs[@]} -ne 1 ]; then
echo "error: expected one extracted bindist dir, found: ${bindirs[*]:-none}"
exit 1
fi
( cd "${bindirs[0]}" && ./configure --prefix="$GITHUB_WORKSPACE/_build/install" && make install )
uplc="$GITHUB_WORKSPACE/_build/install/bin/uplc-ghc"
if [ ! -x "$uplc" ]; then
echo "error: $uplc missing or not executable after make install"
ls -l "$GITHUB_WORKSPACE/_build/install/bin" || true
exit 1
fi
rm -rf _build/artifact
# Build packages serially (JOBS=1): compiling with the Plinth plugin
# (Core -> PLC) is memory-heavy, and concurrent GHC processes OOM-kill the
# runner (seen mid-compile on PlutusLedgerApi.V3).
- name: Test uplc-ghc
run: JOBS=1 GHC="$GITHUB_WORKSPACE/_build/install/bin/uplc-ghc" ./plinth-test.sh
# musl (Alpine) build, mirroring plinth-build-linux. GitHub runners are glibc
# and haskell-actions/setup only ships glibc GHC, so the toolchain + build run
# inside an alpine:3.20 container via `docker run` (with a musl boot-GHC from
# ghcup). The workspace is mounted in; host-level free-disk / submodule steps
# still run on the runner first. `docker run` (not a job-level `container:`)
# keeps those host steps working.
plinth-build-linux-musl:
name: plinth-build / ${{ matrix.os }} (musl) / ghc ${{ matrix.ghc }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
ghc: ['9.6.7']
steps:
- name: Free disk space
uses: jlumbroso/free-disk-space@main
with:
tool-cache: false
android: true
dotnet: true
haskell: false
large-packages: false
docker-images: true
swap-storage: true
- uses: actions/checkout@v4
with:
submodules: false
# The runner's workspace disk (/) is small; /mnt has ~70 GB. Bind-mount it as
# _build so the GHC build has room. docker -v is recursive, so this nested
# mount is visible inside the container at /workspace/_build.
- name: Build on the large /mnt disk
run: |
sudo mkdir -p /mnt/_build
mkdir -p "$GITHUB_WORKSPACE/_build"
sudo mount --bind /mnt/_build "$GITHUB_WORKSPACE/_build"
sudo chown "$USER" "$GITHUB_WORKSPACE/_build"
# The static plugin baked into uplc-ghc is built from the plutus submodule.
- name: Init and update submodules
run: |
git submodule sync
git submodule update --init --recursive --depth 1 --jobs 4
# BINDIST=1 produces the fixed-up uplc-ghc bindist (+ .tar.xz). plinth-build.sh
# appends a -musl suffix to the archive name when run on musl libc.
- name: Build uplc-ghc bindist (Alpine/musl)
run: |
docker run --rm \
-v "$GITHUB_WORKSPACE:/workspace" -w /workspace \
-e BINDIST=1 -e LANG=C.UTF-8 -e LC_ALL=C.UTF-8 \
alpine:3.20 sh -c '
set -eux
. ./.github/alpine-setup.sh
./plinth-build.sh
'
- name: Upload uplc-ghc bindist (musl)
uses: actions/upload-artifact@v4
with:
name: plinth-bindist-musl-${{ matrix.ghc }}
path: _build/bindist/*.tar.xz
retention-days: 1
# the archive is already xz-compressed; don't re-zip it
compression-level: 0
# musl test, mirroring plinth-test-linux: consume the musl bindist, install it
# and run the test suite inside alpine:3.20. Depends on plinth-build-linux-musl.
plinth-test-linux-musl:
name: plinth-test / ${{ matrix.os }} (musl) / ghc ${{ matrix.ghc }}
needs: plinth-build-linux-musl
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
ghc: ['9.6.7']
steps:
- name: Free disk space
uses: jlumbroso/free-disk-space@main
with:
tool-cache: false
android: true
dotnet: true
haskell: false
large-packages: false
docker-images: true
swap-storage: true
- uses: actions/checkout@v4
with:
submodules: false
# plinth/test/cabal.project pulls plutus-tx/plutus-core/plutus-ledger-api
# from the plutus submodule.
- name: Init and update submodules
run: |
git submodule sync
git submodule update --init --recursive --depth 1 --jobs 4
# A single Plinth plugin compile of a makeLift-heavy module
# (PlutusLedgerApi.V3.Contexts) spikes past the ~16 GB runner RAM and gets
# OOM-killed even with JOBS=1. Add a 16 GB swapfile on the large /mnt disk
# so the spike spills to swap; the container shares the host's memory+swap.
- name: Add 16 GB swap
run: |
sudo fallocate -l 16G /mnt/swapfile
sudo chmod 600 /mnt/swapfile
sudo mkswap /mnt/swapfile
sudo swapon /mnt/swapfile
swapon --show
free -h
- name: Download uplc-ghc bindist (musl)
uses: actions/download-artifact@v4
with:
name: plinth-bindist-musl-${{ matrix.ghc }}
path: _build/artifact
# Install the musl bindist (configure + make install) and run the test suite
# inside Alpine. Mirrors the glibc test job's install guards (exactly one
# archive, exactly one extracted dir, executable check) and JOBS=1.
- name: Install and test uplc-ghc (Alpine/musl)
run: |
docker run --rm \
-v "$GITHUB_WORKSPACE:/workspace" -w /workspace \
-e LANG=C.UTF-8 -e LC_ALL=C.UTF-8 \
alpine:3.20 sh -c '
set -eux
. ./.github/alpine-setup.sh
archives=$(ls _build/artifact/*.tar.xz)
n=$(echo "$archives" | wc -l)
if [ "$n" -ne 1 ]; then
echo "error: expected exactly one bindist archive, found: ${archives:-none}"
exit 1
fi
mkdir -p _build/bindist
echo "extracting $archives"
tar --xz -xf "$archives" -C _build/bindist
bindirs=$(ls -d _build/bindist/ghc-*)
if [ "$(echo "$bindirs" | wc -l)" -ne 1 ]; then
echo "error: expected one extracted bindist dir, found: ${bindirs:-none}"
exit 1
fi
( cd "$bindirs" && ./configure --prefix=/workspace/_build/install && make install )
uplc=/workspace/_build/install/bin/uplc-ghc
if [ ! -x "$uplc" ]; then
echo "error: $uplc missing or not executable after make install"
ls -l /workspace/_build/install/bin || true
exit 1
fi
rm -rf _build/artifact
JOBS=1 GHC="$uplc" ./plinth-test.sh
'
plinth-build-windows:
name: plinth-build / windows-latest / ghc ${{ matrix.ghc }}
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
ghc: ['9.6.7']
defaults:
run:
shell: msys2 {0}
steps:
# Git on Windows defaults to not creating symlinks; the submodules and
# bindist rely on them, so enable symlink support before checkout.
- name: Configure git for Windows
shell: bash
run: git config --global core.symlinks true
- uses: actions/checkout@v4
with:
submodules: false
# The pre-MSYS2 step runs in the default Git-for-Windows bash because the
# MSYS2 environment is not set up yet. All submodules are public HTTPS, so
# no credentials are needed.
- name: Init and update submodules
shell: bash
run: |
git submodule sync
# Shallow (single-commit) submodule clones: the build never needs
# submodule history, and these 29 submodules (notably plutus) carry a
# lot of it. --jobs fetches them in parallel. GitHub allows fetching
# the pinned SHA directly, so depth 1 works even when it isn't a
# branch tip.
git submodule update --init --recursive --depth 1 --jobs 4
# MINGW64 toolchain + the autotools/python/sphinx needed by the build.
# path-type: inherit keeps the Windows PATH (incl. the GHC/cabal installed
# below) visible inside the MSYS2 shell.
- name: Setup MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: MINGW64
path-type: inherit
update: false
install: >-
autoconf automake make tar xz patch curl
mingw-w64-x86_64-python mingw-w64-x86_64-python-sphinx
- uses: haskell-actions/setup@v2
id: setup
name: Setup Haskell tools
with:
ghc-version: ${{ matrix.ghc }}
cabal-version: "latest"
cabal-update: true
# BINDIST=1 produces the fixed-up uplc-ghc bindist (+ .tar.xz archive); the
# plinth-test-windows job consumes that archive instead of rebuilding.
- name: Build uplc-ghc bindist
run: BINDIST=1 ./plinth-build.sh
- name: Upload uplc-ghc bindist
uses: actions/upload-artifact@v4
with:
# key by GHC so this never collides with another job's artifact within a
# run. See the matching download in the plinth-test-windows job.
name: plinth-bindist-windows-${{ matrix.ghc }}
path: _build/bindist/*.tar.xz
retention-days: 1
# the archive is already xz-compressed; don't re-zip it
compression-level: 0
# plinth-test on Windows, mirroring plinth-test-linux: consume the bindist
# produced by plinth-build-windows, install it (configure + make install under
# MSYS2) and run the test suite. Depends on plinth-build-windows.
plinth-test-windows:
name: plinth-test / windows-latest / ghc ${{ matrix.ghc }}
needs: plinth-build-windows
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
ghc: ['9.6.7']
defaults:
run:
shell: msys2 {0}
steps:
# Git on Windows defaults to not creating symlinks; the submodules and the
# bindist's wrappers/ dir rely on them, so enable symlink support first.
- name: Configure git for Windows
shell: bash
run: git config --global core.symlinks true
- uses: actions/checkout@v4
with:
submodules: false
# The pre-MSYS2 step runs in the default Git-for-Windows bash because the
# MSYS2 environment is not set up yet. plinth/test/cabal.project pulls
# plutus-tx/plutus-core/plutus-ledger-api from the plutus submodule.
- name: Init and update submodules
shell: bash
run: |
git submodule sync
# Shallow (single-commit) submodule clones: the build never needs
# submodule history. --jobs fetches them in parallel.
git submodule update --init --recursive --depth 1 --jobs 4
# MINGW64 toolchain incl. tar/xz to extract the bindist. path-type: inherit
# keeps the Windows PATH (incl. the cabal installed below) visible.
- name: Setup MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: MINGW64
path-type: inherit
update: false
install: >-
autoconf automake make tar xz patch curl
mingw-w64-x86_64-python mingw-w64-x86_64-python-sphinx
# plinth-test.sh invokes cabal, so cabal must be on PATH. (The boot GHC this
# also installs is unused by the test.)
- uses: haskell-actions/setup@v2
id: setup
name: Setup Haskell tools
with:
ghc-version: ${{ matrix.ghc }}
cabal-version: "latest"
cabal-update: true
- name: Download uplc-ghc bindist
uses: actions/download-artifact@v4
with:
# matches the plinth-build-windows upload name.
name: plinth-bindist-windows-${{ matrix.ghc }}
path: _build/artifact
# Unlike Unix, the Windows GHC bindist has no configure/make install: it is
# relocatable, so we just extract it and run bin/uplc-ghc.exe in place.
- name: Extract uplc-ghc bindist
run: |
shopt -s nullglob
archives=(_build/artifact/*.tar.xz)
if [ ${#archives[@]} -ne 1 ]; then
echo "error: expected exactly one bindist archive, found: ${archives[*]:-none}"
exit 1
fi
mkdir -p _build/install
echo "extracting ${archives[0]}"
tar --xz -xf "${archives[0]}" -C _build/install
bindirs=(_build/install/ghc-*)
if [ ${#bindirs[@]} -ne 1 ]; then
echo "error: expected one extracted bindist dir, found: ${bindirs[*]:-none}"
exit 1
fi
uplc="${bindirs[0]}/bin/uplc-ghc.exe"
if [ ! -x "$uplc" ]; then
echo "error: $uplc missing or not executable in extracted bindist"
ls -l "${bindirs[0]}/bin" || true
exit 1
fi
rm -rf _build/artifact
# Build packages serially (JOBS=1): compiling with the Plinth plugin
# (Core -> PLC) is memory-heavy. plinth-test.sh cygpath -w's the GHC path.
- name: Test uplc-ghc
run: |
bindirs=(_build/install/ghc-*)
JOBS=1 GHC="${bindirs[0]}/bin/uplc-ghc.exe" ./plinth-test.sh