3 # See: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#concurrency.
5 group: ${{ github.ref }}-${{ github.workflow }}
6 cancel-in-progress: true
8 # Note: This workflow file contains the required job "Validate post job". We are using path filtering
9 # here to ignore PRs which only change documentation. This can cause a problem, see the workflow file
10 # "validate.skip.yml" for a description of the problem and the solution provided in that file.
18 # only top level for these, because various test packages have them too
24 # hardcoded LTS branch, change when new LTS released!
40 # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions
44 description: allow-newer line
48 description: constraints line
53 # We choose a stable ghc version across all os's
54 # which will be used to do the next release
55 GHC_FOR_RELEASE: "9.4.8"
56 # Ideally we should use the version about to be released for hackage tests and benchmarks
57 GHC_FOR_SOLVER_BENCHMARKS: "9.4.8"
58 GHC_FOR_COMPLETE_HACKAGE_TESTS: "9.4.8"
59 COMMON_FLAGS: "-j 2 -v"
61 # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions
62 ALLOWNEWER: ${{ github.event.inputs.allow-newer }}
63 CONSTRAINTS: ${{ github.event.inputs.constraints }}
67 name: Validate ${{ matrix.sys.os }} ghc-${{ matrix.ghc }}
68 runs-on: ${{ matrix.sys.os }}
70 GHC_FOR_RELEASE: ${{ format('["{0}"]', env.GHC_FOR_RELEASE) }}
75 - { os: windows-latest, shell: "C:/msys64/usr/bin/bash.exe -e {0}" }
76 - { os: ubuntu-22.04, shell: bash }
77 - { os: macos-latest, shell: bash }
78 # If you remove something from here, then add it to the old-ghcs job.
79 # Also a removed GHC from here means that we are actually dropping
80 # support, so the PR *must* have a changelog entry.
93 # Throws fatal "cabal-tests.exe: fd:8: hGetLine: end of file" exception
94 # even with --io-manager=native
96 { os: windows-latest, shell: "C:/msys64/usr/bin/bash.exe -e {0}" }
98 # corrupts GHA cache or the fabric of reality itself, see https://github.com/haskell/cabal/issues/8356
100 { os: windows-latest, shell: "C:/msys64/usr/bin/bash.exe -e {0}" }
102 # lot of segfaults caused by ghc bugs
104 { os: windows-latest, shell: "C:/msys64/usr/bin/bash.exe -e {0}" }
106 # ghc before 8.10.5 doesn't run on AArch64
107 # 9.0.2 suffers from https://gitlab.haskell.org/ghc/ghc/-/issues/20592
108 # 8.10.7 throws asm errors in hashable's cbits suggesting the runner doesn't
109 # support a CPU extension for hardware SHA; may be fixable with flags
111 { os: macos-latest, shell: bash }
114 { os: macos-latest, shell: bash }
117 { os: macos-latest, shell: bash }
121 shell: ${{ matrix.sys.shell }}
123 - name: Work around XDG directories existence (haskell-actions/setup#62)
124 if: runner.os == 'macOS'
126 rm -rf ~/.config/cabal
127 rm -rf ~/.cache/cabal
129 - name: "WIN: Setup TMP environment variable"
130 if: runner.os == 'Windows'
132 echo "TMP=${{ runner.temp }}" >> "$GITHUB_ENV"
134 - uses: actions/checkout@v4
136 # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions
137 - name: Add manually supplied allow-newer
138 if: github.event_name == 'workflow_dispatch' && github.event.inputs.allow-newer != ''
140 echo "allow-newer: ${{ github.event.inputs.allow-newer }}" >> cabal.validate.project
142 - name: Add manually supplied constraints
143 if: github.event_name == 'workflow_dispatch' && github.event.inputs.constraints != ''
145 echo "constraints: ${{ github.event.inputs.constraints }}" >> cabal.validate.project
147 - uses: haskell-actions/setup@v2
150 ghc-version: ${{ matrix.ghc }}
151 cabal-version: 3.12.1.0 # see https://github.com/haskell/cabal/pull/10251
152 ghcup-release-channel: https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-prereleases-0.0.8.yaml
154 # See the following link for a breakdown of the following step
155 # https://github.com/haskell/actions/issues/7#issuecomment-745697160
156 - uses: actions/cache@v4
158 # validate.sh uses a special build dir
160 ${{ steps.setup-haskell.outputs.cabal-store }}
162 key: ${{ runner.os }}-${{ matrix.ghc }}-${{ github.sha }}
163 restore-keys: ${{ runner.os }}-${{ matrix.ghc }}-
165 # The tool is not essential to the rest of the test suite. If
166 # hackage-repo-tool is not present, any test that requires it will
168 # We want to keep this in the loop but we don't want to fail if
169 # hackage-repo-tool breaks or fails to support a newer GHC version.
170 - name: Install hackage-repo-tool
171 continue-on-error: true
172 run: cabal install --ignore-project hackage-repo-tool
174 # Needed by cabal-testsuite/PackageTests/Configure/setup.test.hs
175 - name: "MAC: Install Autotools"
176 if: runner.os == 'macOS'
177 run: brew install automake
179 # Needed by cabal-testsuite/PackageTests/Configure/setup.test.hs
180 - name: "WIN: Install Autotools"
181 if: runner.os == 'Windows'
182 run: /usr/bin/pacman --noconfirm -S autotools
184 - name: Set validate inputs
186 FLAGS="${{ env.COMMON_FLAGS }}"
187 if [[ "${{ matrix.ghc }}" == "${{ env.GHC_FOR_SOLVER_BENCHMARKS }}" ]]; then
188 FLAGS="$FLAGS --solver-benchmarks"
190 if [[ "${{ matrix.ghc }}" == "${{ env.GHC_FOR_COMPLETE_HACKAGE_TESTS }}" ]]; then
191 FLAGS="$FLAGS --complete-hackage-tests"
193 echo "FLAGS=$FLAGS" >> "$GITHUB_ENV"
195 - name: Validate print-config
196 run: sh validate.sh $FLAGS -s print-config
198 - name: Validate print-tool-versions
199 run: sh validate.sh $FLAGS -s print-tool-versions
201 - name: Validate build
202 run: sh validate.sh $FLAGS -s build
204 - name: Canonicalize architecture
206 case ${{ runner.arch }} in
209 ARM64) arch=aarch64 ;;
210 *) echo "Unsupported architecture, please fix validate.yaml" 2>/dev/null; exit 1 ;;
212 echo "CABAL_ARCH=$arch" >> "$GITHUB_ENV"
214 - name: Tar cabal head executable
215 if: matrix.ghc == env.GHC_FOR_RELEASE
217 CABAL_EXEC=$(cabal list-bin --builddir=dist-newstyle-validate-ghc-${{ matrix.ghc }} --project-file=cabal.validate.project cabal-install:exe:cabal)
218 # We have to tar the executable to preserve executable permissions
219 # see https://github.com/actions/upload-artifact/issues/38
220 if [[ "${{ runner.os }}" == "Windows" ]]; then
221 # `cabal list-bin` gives us a windows path but tar needs the posix one
222 CABAL_EXEC=$(cygpath "$CABAL_EXEC")
224 if [[ "${{ runner.os }}" == "macOS" ]]; then
225 # Workaround to avoid bsdtar corrupts the executable
226 # so executing it after untar throws `cannot execute binary file`
227 # see https://github.com/actions/virtual-environments/issues/2619#issuecomment-788397841
230 DIR=$(dirname "$CABAL_EXEC")
231 FILE=$(basename "$CABAL_EXEC")
232 CABAL_EXEC_TAR="cabal-head-${{ runner.os }}-$CABAL_ARCH.tar.gz"
233 tar -czvf "$CABAL_EXEC_TAR" -C "$DIR" "$FILE"
234 echo "CABAL_EXEC_TAR=$CABAL_EXEC_TAR" >> "$GITHUB_ENV"
236 # We upload the cabal executable built with the ghc used in the release for:
237 # - Reuse it in the dogfooding job (although we could use the cached build dir)
238 # - Make it available in the workflow to make easier testing it locally
239 - name: Upload cabal-install executable to workflow artifacts
240 if: matrix.ghc == env.GHC_FOR_RELEASE
241 uses: actions/upload-artifact@v4
243 name: cabal-${{ runner.os }}-${{ env.CABAL_ARCH }}
244 path: ${{ env.CABAL_EXEC_TAR }}
246 - name: Validate tests
248 # `rawSystemStdInOut reports text decoding errors`
249 # test does not find ghc without the full path in windows
250 GHCPATH: ${{ steps.setup-haskell.outputs.ghc-exe }}
254 tests="lib-tests lib-suite cli-tests cli-suite"
255 if [ "${{ matrix.ghc }}" = "${{ env.GHC_FOR_SOLVER_BENCHMARKS }}" ]; then
256 tests="$tests solver-benchmarks-tests solver-benchmarks-run"
258 for test in $tests; do
259 echo Validate "$test"
260 sh validate.sh $FLAGS -s "$test" || rc=1
264 # The above ensures all the tests get run, for a single platform+ghc.
265 # Trying to ensure they run for *all* combinations but still fail
266 # at the end seems to be extremely difficult at best. It's doable,
267 # but it requires a continuously growing stack of conditions and
268 # one possibly nightmarish final conditional. 'fail-fast' gets us
269 # partway there, at least, but is still imperfect.
272 name: Validate old ghcs ${{ matrix.extra-ghc }}
273 runs-on: ubuntu-22.04
279 ["8.4.4", "8.2.2", "8.0.2"]
280 ## GHC 7.10.3 does not install on ubuntu-22.04 with ghcup.
281 ## Older GHCs are not supported by ghcup in the first place.
285 - uses: actions/checkout@v4
287 - name: Install prerequisites for old GHCs
290 sudo apt-get install libncurses5 libtinfo5
292 - name: Install extra compiler
293 run: ghcup install ghc ${{ matrix.extra-ghc }}
297 run: cat /usr/local/.ghcup/logs/*
299 - name: Install primary compiler
300 uses: haskell-actions/setup@v2
303 ghc-version: ${{ env.GHC_FOR_RELEASE }}
304 cabal-version: latest
309 "ghc-${{ matrix.extra-ghc }}" --version
311 # As we are reusing the cached build dir from the previous step
312 # the generated artifacts are available here,
313 # including the cabal executable and the test suite
314 - uses: actions/cache@v4
317 ${{ steps.setup-haskell.outputs.cabal-store }}
319 key: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-${{ github.sha }}
320 restore-keys: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-
322 - name: Validate build
324 run: sh validate.sh ${{ env.COMMON_FLAGS }} -s build
326 - name: "Validate lib-suite-extras --extra-hc ghc-${{ matrix.extra-ghc }}"
328 EXTRA_GHC: ghc-${{ matrix.extra-ghc }}
329 run: sh validate.sh ${{ env.COMMON_FLAGS }} --lib-only -s lib-suite-extras --extra-hc "${{ env.EXTRA_GHC }}"
330 # See the comment above about running all tests but still failing if one
331 # of them does; it also applies here.
334 name: Build statically linked using alpine
335 runs-on: ubuntu-latest
336 container: "alpine:3.19"
338 - name: Install extra dependencies
341 apk add bash curl sudo jq pkgconfig \
342 zlib-dev zlib-static binutils-gold curl \
343 gcc g++ gmp-dev libc-dev libffi-dev make \
344 musl-dev ncurses-dev perl tar xz
346 - uses: actions/checkout@v4
348 # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions
349 - name: Manually supplied constraints/allow-newer
350 if: github.event_name == 'workflow_dispatch'
352 echo "allow-newer: ${ALLOWNEWER}" >> cabal.validate.project
353 echo "constraints: ${CONSTRAINTS}" >> cabal.validate.project
355 - uses: haskell-actions/setup@v2
358 ghc-version: ${{ env.GHC_FOR_RELEASE }}
359 cabal-version: latest # latest is mandatory for cabal-testsuite, see https://github.com/haskell/cabal/issues/8133
361 # See the following link for a breakdown of the following step
362 # https://github.com/haskell/actions/issues/7#issuecomment-745697160
363 - uses: actions/cache@v4
365 # validate.sh uses a special build dir
367 ${{ steps.setup-haskell.outputs.cabal-store }}
369 key: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-${{ github.sha }}
370 restore-keys: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-
372 - name: Enable statically linked executables
374 echo 'executable-static: true' >> cabal.validate.project
377 run: sh validate.sh $FLAGS -s build
379 - name: Tar cabal head executable
381 CABAL_EXEC=$(cabal list-bin --builddir=dist-newstyle-validate-ghc-${{ env.GHC_FOR_RELEASE }} --project-file=cabal.validate.project cabal-install:exe:cabal)
382 # We have to tar the executable to preserve executable permissions
383 # see https://github.com/actions/upload-artifact/issues/38
384 DIR=$(dirname "$CABAL_EXEC")
385 FILE=$(basename "$CABAL_EXEC")
386 CABAL_EXEC_TAR="cabal-head-${{ runner.os }}-static-x86_64.tar.gz"
387 tar -czvf "$CABAL_EXEC_TAR" -C "$DIR" "$FILE"
388 echo "CABAL_EXEC_TAR=$CABAL_EXEC_TAR" >> "$GITHUB_ENV"
390 - name: Upload cabal-install executable to workflow artifacts
391 uses: actions/upload-artifact@v4
393 name: cabal-${{ runner.os }}-static-x86_64
394 path: ${{ env.CABAL_EXEC_TAR }}
396 # The previous jobs use a released version of cabal to build cabal HEAD itself
397 # This one uses the cabal HEAD generated executable in the previous step
398 # to build itself again, as sanity check
400 name: Dogfooding ${{ matrix.sys.os }} ghc-${{ matrix.ghc }}
401 runs-on: ${{ matrix.sys.os }}
406 - { os: windows-latest, shell: "C:/msys64/usr/bin/bash.exe -e {0}" }
407 - { os: ubuntu-22.04, shell: bash }
408 - { os: macos-latest, shell: bash }
409 # We only use one ghc version the used one for the next release (defined at top of the workflow)
410 # We need to build an array dynamically to inject the appropiate env var in a previous job,
411 # see https://docs.github.com/en/actions/learn-github-actions/expressions#fromjson
412 ghc: ${{ fromJSON (needs.validate.outputs.GHC_FOR_RELEASE) }}
415 shell: ${{ matrix.sys.shell }}
418 # TODO: make a reusable action for this
419 - name: Canonicalize architecture
421 case ${{ runner.arch }} in
424 ARM64) arch=aarch64 ;;
425 *) echo "Unsupported architecture" 2>/dev/null; exit 1 ;;
427 echo "CABAL_ARCH=$arch" >> "$GITHUB_ENV"
429 - name: "MAC: Work around XDG directories existence (haskell-actions/setup#62)"
430 if: runner.os == 'macOS'
432 rm -rf ~/.config/cabal
433 rm -rf ~/.cache/cabal
435 - name: "WIN: Setup TMP environment variable"
436 if: runner.os == 'Windows'
438 echo "TMP=${{ runner.temp }}" >> "$GITHUB_ENV"
440 - uses: actions/checkout@v4
442 - uses: haskell-actions/setup@v2
445 ghc-version: ${{ matrix.ghc }}
446 cabal-version: latest # default, we are not using it in this job
448 - name: Download cabal executable from workflow artifacts
449 uses: actions/download-artifact@v4
451 name: cabal-${{ runner.os }}-${{ env.CABAL_ARCH }}
454 - name: Untar the cabal executable
455 run: tar -xzf "./cabal-head/cabal-head-${{ runner.os }}-$CABAL_ARCH.tar.gz" -C cabal-head
457 - name: print-config using cabal HEAD
458 run: sh validate.sh ${{ env.COMMON_FLAGS }} --with-cabal ./cabal-head/cabal -s print-config
460 # We dont use cache to force a build with a fresh store dir and build dir
461 # This way we check cabal can build all its dependencies
462 - name: Build using cabal HEAD
463 run: sh validate.sh ${{ env.COMMON_FLAGS }} --with-cabal ./cabal-head/cabal -s build
466 name: Create a GitHub prerelease with the binary artifacts
467 runs-on: ubuntu-latest
468 if: github.ref == 'refs/heads/master'
472 # IMPORTANT! Any job added to the workflow should be added here too
473 needs: [validate, validate-old-ghcs, build-alpine, dogfooding]
476 # for now this is hardcoded. is there a better way?
477 - uses: actions/download-artifact@v4
483 - name: Create GitHub prerelease
484 uses: softprops/action-gh-release@v2
488 files: binaries/cabal-*
491 name: Create a GitHub LTS prerelease with the binary artifacts
492 runs-on: ubuntu-latest
493 # The LTS branch is hardcoded for now, update it on a new LTS!
494 # if: github.ref == 'refs/heads/3.12'
498 # IMPORTANT! Any job added to the workflow should be added here too
499 needs: [validate, validate-old-ghcs, build-alpine, dogfooding]
502 - uses: actions/download-artifact@v4
509 # bash-ism, but we forced bash above
512 mv "$f" "cabal-lts-${f##cabal-}"
515 - run: echo ${{ github.ref }}
517 - name: Create GitHub prerelease
518 if: github.ref == 'refs/heads/3.12'
519 uses: softprops/action-gh-release@v2
521 tag_name: cabal-lts-head
523 files: binaries/cabal-*
525 # We use this job as a summary of the workflow
526 # It will fail if any of the previous jobs does
527 # This way we can use it exclusively in branch protection rules
528 # and abstract away the concrete jobs of the workflow, including their names
531 name: Validate post job
532 runs-on: ubuntu-latest
533 # IMPORTANT! Any job added to the workflow should be added here too
534 needs: [validate, validate-old-ghcs, build-alpine, dogfooding]
538 echo "jobs info: ${{ toJSON(needs) }}"
539 - if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')