;ci: binaries-*: add more hx-based workflows, and arm linux binaries #4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # TRIGGER: Runs on any push to binaries-linux-arm64-hx or binaries branches. | |
| # ACTION: Builds, tests and saves linux arm64 DYNAMIC binaries with hx, | |
| # using the ghc configured in hx.toml and the deps saved in hx.lock. | |
| name: binaries-linux-arm64-hx | |
| on: | |
| push: | |
| branches: [ binaries-linux-arm64-hx, binaries ] | |
| workflow_dispatch: | |
| jobs: | |
| build: | |
| runs-on: ubuntu-24.04-arm | |
| # https://github.com/actions/partner-runner-images/blob/main/images/arm-ubuntu-24-image.md | |
| env: | |
| GH_TOKEN: ${{ github.token }} # lets `gh release download` authenticate & dodge rate limits | |
| HX_AUTO_INSTALL: "true" # install missing GHC toolchain without prompting (hx wants true/false, not 1) | |
| ghc: "9.14.1" # matches hx.toml [toolchain] ghc / stack.yaml compiler | |
| cabal: "3.16.1.0" # cabal-install version to fetch (official self-contained binary) | |
| hxasset: "aarch64-unknown-linux-gnu.tar.gz" # hx release asset suffix for this platform | |
| cabalarch: "aarch64-linux-deb12" # cabal-install bindist arch for this platform (deb12 = portable glibc) | |
| steps: | |
| - name: Show platform info | |
| run: | | |
| arch | |
| uname -a | |
| - name: Install system build deps | |
| run: | | |
| sudo apt-get update -qq | |
| sudo apt-get install -y libgmp-dev zlib1g-dev libncurses-dev | |
| - name: Check out | |
| uses: actions/checkout@v7 | |
| # have to fetch everything for git describe for --version | |
| with: | |
| fetch-depth: 0 | |
| - name: Check embedded files | |
| run: | | |
| tools/checkembeddedfiles | |
| - name: Cache - hx toolchains (GHC bindist) | |
| uses: actions/cache@v6 | |
| with: | |
| # ~/.ghcup too: on arm64 hx installs GHC via ghcup (its direct download lacks a checksum here), so GHC lands there | |
| path: | | |
| ~/.hx | |
| ~/.ghcup | |
| key: ${{ runner.os }}-arm64-hx-toolchain-${{ env.ghc }} | |
| - name: Cache - hx compiled dependency store | |
| uses: actions/cache@v6 | |
| with: | |
| # hx's compiled-dep store on linux is ~/.cache/hx: the `directories` crate uses the bare app | |
| # name under XDG, unlike macos which uses the reverse-DNS io.raskell.hx. (~800 MB; confirmed on CI.) | |
| path: ~/.cache/hx | |
| key: ${{ runner.os }}-arm64-hx-store-${{ env.ghc }}-${{ hashFiles('hx.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-arm64-hx-store-${{ env.ghc }}- | |
| - name: Cache - cabal Hackage index (used by the system cabal) | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/.cache/cabal | |
| key: ${{ runner.os }}-arm64-cabal-index-${{ hashFiles('hx.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-arm64-cabal-index- | |
| - name: Cache - cabal binary | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/.local/bin/cabal | |
| key: ${{ runner.os }}-arm64-cabal-bin-${{ env.cabal }} | |
| # NB: the project build (.hx/cabal/dist-newstyle) is deliberately NOT cached (stale --version commit otherwise). | |
| - name: Ensure ~/.local/bin exists and is in PATH | |
| run: | | |
| mkdir -p "$HOME/.local/bin" | |
| echo "$HOME/.local/bin" >> $GITHUB_PATH | |
| - name: Install hx (latest release) | |
| run: | | |
| mkdir -p /tmp/hxdl | |
| gh release download --repo arcanist-sh/hx --pattern "*$hxasset" --dir /tmp/hxdl --clobber | |
| tar xzf /tmp/hxdl/*"$hxasset" -C /tmp/hxdl | |
| install -m 755 "$(find /tmp/hxdl -type f -name hx | head -1)" "$HOME/.local/bin/hx" | |
| hx --version | |
| hx doctor || true | |
| - name: Install ghcup (arm64 runner lacks it; hx needs it for a verified GHC) | |
| run: | | |
| # Unlike the x64 ubuntu image, ubuntu-24.04-arm has no preinstalled ghcup. hx's direct GHC | |
| # download is refused here (no published aarch64 checksum for this GHC), so it falls back to | |
| # ghcup - which must be present. Install ghcup only (no GHC/cabal); hx then drives it. | |
| if ! command -v ghcup >/dev/null; then | |
| curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | \ | |
| BOOTSTRAP_HASKELL_NONINTERACTIVE=1 BOOTSTRAP_HASKELL_MINIMAL=1 sh | |
| echo "$HOME/.ghcup/bin" >> "$GITHUB_PATH" | |
| fi | |
| "$HOME/.ghcup/bin/ghcup" --version | |
| - name: Install GHC and cabal | |
| run: | | |
| hx toolchain install --set "$ghc" # delegates to ghcup (installed above) for the verified aarch64 GHC | |
| # fetch the official cabal binary unless already present (arm64 has no preinstalled cabal) | |
| if ! command -v cabal >/dev/null; then | |
| mkdir -p /tmp/cabaldl | |
| curl -fsSL "https://downloads.haskell.org/cabal/cabal-install-$cabal/cabal-install-$cabal-$cabalarch.tar.xz" -o /tmp/cabaldl/cabal.tar.xz | |
| tar xJf /tmp/cabaldl/cabal.tar.xz -C /tmp/cabaldl | |
| install -m 755 "$(find /tmp/cabaldl -type f -name cabal | head -1)" "$HOME/.local/bin/cabal" | |
| fi | |
| cabal --version | |
| # the system cabal has no Hackage index yet, so download it (kept fresh each run, cheap when ~/.cache/cabal is warm) | |
| cabal update | |
| hx toolchain status || true | |
| - name: List dependencies | |
| run: | | |
| hx list | |
| - name: Build hledger | |
| # and run unit + doc tests | |
| run: | | |
| # no --release: that forces -O2; we use hx.toml [build] optimization = 1 to match stack's -O1 | |
| hx build | |
| # hx test | |
| - name: Collect built binaries onto PATH | |
| run: | | |
| # hx builds via cabal into .hx/cabal/dist-newstyle; the exe is under .../x/<exe>/{,opt/}build/<exe>/<exe> | |
| for exe in hledger hledger-ui hledger-web; do | |
| bin=$(find .hx/cabal/dist-newstyle -type f -name "$exe" -path "*/x/$exe/*build/$exe/$exe" | head -1) | |
| if [[ -z "$bin" ]]; then | |
| echo "ERROR: $exe executable not found under .hx/cabal/dist-newstyle" >&2 | |
| find .hx/cabal/dist-newstyle -type f -name "$exe" >&2 || true | |
| exit 1 | |
| fi | |
| echo "$exe -> $bin" | |
| cp "$bin" "$HOME/.local/bin/$exe" | |
| done | |
| hledger --version | |
| - name: Install shelltestrunner | |
| run: | | |
| command -v shelltest >/dev/null || cabal install --overwrite-policy=always shelltestrunner-1.11 | |
| shelltest --version | |
| - name: Test functional tests (excluding addons) | |
| run: | | |
| COLUMNS=80 shelltest --execdir -j16 hledger/test -x /_ -x /addons -x ledger-compat/ledger-baseline -x ledger-compat/ledger-regress -x ledger-compat/ledger-collected | |
| # artifacts: | |
| - name: Gather binaries | |
| run: | | |
| mkdir tmp | |
| cp ~/.local/bin/hledger tmp | |
| cp ~/.local/bin/hledger-ui tmp | |
| cp ~/.local/bin/hledger-web tmp | |
| cp hledger/embeddedfiles/*.1 tmp | |
| cp hledger/embeddedfiles/*.info tmp | |
| cp hledger/shell-completion/hledger-completion.bash tmp | |
| strip tmp/hledger | |
| strip tmp/hledger-ui | |
| strip tmp/hledger-web | |
| cd tmp | |
| tar cvf hledger-linux-arm64.tar hledger hledger-ui hledger-web *.1 *.info hledger-completion.bash | |
| file hledger | |
| ldd hledger || true | |
| ./hledger --version | |
| ./hledger-ui --version | |
| ./hledger-web --version | |
| # upload-artifact loses execute permissions, so we tar the binaries to preserve them. | |
| - name: Upload binaries artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: hledger-linux-arm64 | |
| path: tmp/hledger-linux-arm64.tar |