Skip to content

Haskell CI

Haskell CI #34088

Workflow file for this run

name: Haskell CI
on:
pull_request: # Required for workflows to be able to be approved from forks
merge_group:
push:
# we need this to populate cache for `main` branch to make it available to the child branches, see
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#restrictions-for-accessing-a-cache
branches:
- master
# GH caches are removed when not accessed within 7 days - this schedule runs the job every 6 days making
# sure that we always have some caches on main
schedule:
- cron: '0 0 */6 * *'
# DO NOT DELETE.
# This is required for nightly builds and is invoked by nightly-trigger.yml
# on a schedule trigger.
workflow_dispatch:
inputs:
reason:
description: 'Reason'
required: false
default: manual
tests:
description: 'Tests'
required: false
default: some
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# If you edit these versions, make sure the version in the lonely macos-latest job below is updated accordingly
ghc: [&ghc-stable "9.6", &ghc-latest "9.12", "9.14"]
cabal: [&cabal-version "3.16"]
os: [ubuntu-latest]
include:
# Using include, to make sure there will only be one macOS job, even if the matrix gets expanded later on.
# We want a single job, because macOS runners are scarce.
- ghc: *ghc-stable
cabal: *cabal-version
os: macos-latest
- ghc: *ghc-latest
cabal: *cabal-version
os: windows-latest
- ghc: *ghc-latest
validate-manifest: true
defaults:
run:
shell: bash
env:
# Modify this value to "invalidate" the cabal cache.
CABAL_CACHE_VERSION: "2024-07-26"
concurrency:
group: >
a+${{ github.event_name }}
b+${{ github.workflow_ref }}
c+${{ github.job }}
d+${{ matrix.ghc }}
e+${{ matrix.cabal }}
f+${{ matrix.os }}
g+${{ (startsWith(github.ref, 'refs/heads/gh-readonly-queue/') && github.run_id) || github.event.pull_request.number || github.ref }}
cancel-in-progress: true
steps:
- name: Concurrency group
run: >
echo
a+${{ github.event_name }}
b+${{ github.workflow_ref }}
c+${{ github.job }}
d+${{ matrix.ghc }}
e+${{ matrix.cabal }}
f+${{ matrix.os }}
g+${{ (startsWith(github.ref, 'refs/heads/gh-readonly-queue/') && github.run_id) || github.event.pull_request.number || github.ref }}
# The macos-26-arm64 image 20261013 ships Command Line Tools 27 (SDK 27.0)
# next to Xcode 26.6, whose ld cannot read the SDK 27 .tbd stubs
# ("tapi error: malformed file ... unknown architecture arm64e.x1").
# Use the Command Line Tools toolchain so ld and SDK match.
# Remove once https://github.com/actions/runner-images/issues/14940 is fixed
# in the image (its README lists Command Line Tools 26.x again).
- name: Use Command Line Tools toolchain on macOS
if: runner.os == 'macOS'
run: sudo xcode-select -s /Library/Developer/CommandLineTools
- name: Install Haskell
uses: input-output-hk/actions/haskell@dbb6ea6d50ffc37a2d481fd8047aff028bac3223 # latest
id: setup-haskell
with:
ghc-version: ${{ matrix.ghc }}
cabal-version: ${{ matrix.cabal }}
- name: Install system dependencies
uses: input-output-hk/actions/base@6217329012a2fd613c8eec9a3f523684a8e91720 # latest
with:
use-sodium-vrf: true # default is true
- name: Install gRPC system dependencies
uses: input-output-hk/cardano-dev/actions/grpc-deps@7bd271fb5d71f95250fc82bf433605b787dad3d4 # grpc-deps-0.1.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- name: Enable long paths on Windows
if: runner.os == 'Windows'
run: git config --system core.longpaths true
- name: Cache and install Cabal dependencies
uses: input-output-hk/cardano-dev/actions/cabal-cache@c7427b0921301778971d96b20ab234e8c34aedc3 # cabal-cache-0.0.1.2
with:
cabal-store: ${{ steps.setup-haskell.outputs.cabal-store }}
cache-version: ${{ env.CABAL_CACHE_VERSION }}
# Now we build.
- name: Build all
run: cabal build all --enable-tests
- name: Run tests
env:
TMPDIR: ${{ runner.temp }}
TMP: ${{ runner.temp }}
KEEP_WORKSPACE: 1
run: |
cabal test cardano-testnet cardano-node cardano-node-chairman cardano-submit-api
- name: Validate produced manifest and status output against schemas
if: matrix.validate-manifest
run: |
# This job has no nix, that is why we pin the version with pipx separately.
pipx install check-jsonschema==0.37.1
# Node sockets live under this directory, so it must stay well below
# the 108-character unix socket path limit ($RUNNER_TEMP is short).
dir="$RUNNER_TEMP/manifest-schema-check"
log="$RUNNER_TEMP/manifest-schema-check.log"
"$(cabal list-bin cardano-testnet)" cardano --output-dir "$dir" > "$log" 2>&1 &
testnet_pid=$!
# The manifest is written at readiness, so the file appearing is the ready signal.
for _ in $(seq 1 120); do
if [ -f "$dir/manifest.json" ]; then break; fi
if ! kill -0 "$testnet_pid" 2>/dev/null; then break; fi
sleep 5
done
# Exit code 0: the chain is producing blocks.
status_rc=0
"$(cabal list-bin cardano-testnet)" status --testnet-dir "$dir" --json > "$RUNNER_TEMP/status.json" || status_rc=$?
cat "$RUNNER_TEMP/status.json"
# SIGINT, not SIGTERM: the harness tears its nodes down on SIGINT only
# (see Testnet.Signal.interruptNodesOnSigINT).
kill -INT "$testnet_pid" 2>/dev/null || true
wait "$testnet_pid" 2>/dev/null || true
if [ ! -f "$dir/manifest.json" ]; then
echo "ERROR: testnet did not produce $dir/manifest.json in time"
tail -n 100 "$log"
exit 1
fi
check-jsonschema --schemafile cardano-testnet/schemas/manifest.schema.json "$dir/manifest.json"
if [ "$status_rc" != 0 ]; then
echo "ERROR: cardano-testnet status exited with $status_rc"
exit 1
fi
check-jsonschema --schemafile cardano-testnet/schemas/status.schema.json "$RUNNER_TEMP/status.json"
- name: Tar failed tests workspaces
if: ${{ failure() }}
env:
TMP: ${{ runner.temp }}
run: |
cd $TMP
find . -name 'module' -type f -exec dirname {} \; | xargs -I "{}" basename "{}" | sort -u | xargs -I "{}" tar -czvf workspaces.tgz "{}"
- name: Upload workspaces on tests failure
if: ${{ failure() }}
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: failed-test-workspaces-${{ matrix.os }}-ghc${{ matrix.ghc }}-cabal${{ matrix.cabal }}.tgz
path: ${{ runner.temp }}/workspaces.tgz
- name: "Tar artifacts"
run: |
mkdir -p artifacts
for exe in $(cat dist-newstyle/cache/plan.json | jq -r '."install-plan"[] | select(.style == "local" and (."component-name" | startswith("exe:"))) | ."bin-file"'); do
if [ -f $exe ]; then
echo "Including artifact $exe"
( cd artifacts
tar -C "$(dirname $exe)" -czf "$(basename $exe).tar.gz" "$(basename $exe)"
)
else
echo "Skipping artifact $exe"
fi
done
# Uncomment the following back in for debugging. Remember to launch a `pwsh` from
# the tmux session to debug `pwsh` issues.
#
# - name: Setup tmate session
# if: ${{ failure() }}
# uses: mxschmitt/action-tmate@v3
# with:
# limit-access-to-actor: true
build-complete:
needs: [build]
if: ${{ always() }}
runs-on: ubuntu-latest
steps:
- name: Check if any previous job failed
run: |
if [[ "${{ needs.build.result }}" == "failure" ]]; then
# this ignores skipped dependencies
echo 'Required jobs failed to build.'
exit 1
else
echo 'Build complete'
fi