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
38 # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions
42 description: allow-newer line
46 description: constraints line
51 # We choose a stable ghc version across all os's
52 # which will be used to do the next release
53 GHC_FOR_RELEASE: "9.4.8"
54 # Ideally we should use the version about to be released for hackage tests and benchmarks
55 GHC_FOR_SOLVER_BENCHMARKS: "9.4.8"
56 GHC_FOR_COMPLETE_HACKAGE_TESTS: "9.4.8"
57 COMMON_FLAGS: "-j 2 -v"
59 # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions
60 ALLOWNEWER: ${{ github.event.inputs.allow-newer }}
61 CONSTRAINTS: ${{ github.event.inputs.constraints }}
65 name: Validate ${{ matrix.sys.os }} ghc-${{ matrix.ghc }}
66 runs-on: ${{ matrix.sys.os }}
68 GHC_FOR_RELEASE: ${{ format('["{0}"]', env.GHC_FOR_RELEASE) }}
73 - { os: windows-latest, shell: "C:/msys64/usr/bin/bash.exe -e {0}" }
74 - { os: ubuntu-latest, shell: bash }
75 - { os: macos-latest, shell: bash }
76 # If you remove something from here, then add it to the old-ghcs job.
77 # Also a removed GHC from here means that we are actually dropping
78 # support, so the PR *must* have a changelog entry.
91 # Throws fatal "cabal-tests.exe: fd:8: hGetLine: end of file" exception
92 # even with --io-manager=native
94 { os: windows-latest, shell: "C:/msys64/usr/bin/bash.exe -e {0}" }
96 # corrupts GHA cache or the fabric of reality itself, see https://github.com/haskell/cabal/issues/8356
98 { os: windows-latest, shell: "C:/msys64/usr/bin/bash.exe -e {0}" }
100 # lot of segfaults caused by ghc bugs
102 { os: windows-latest, shell: "C:/msys64/usr/bin/bash.exe -e {0}" }
104 # ghc before 8.10.5 doesn't run on AArch64
105 # 9.0.2 suffers from https://gitlab.haskell.org/ghc/ghc/-/issues/20592
106 # 8.10.7 throws asm errors in hashable's cbits suggesting the runner doesn't
107 # support a CPU extension for hardware SHA; may be fixable with flags
109 { os: macos-latest, shell: bash }
112 { os: macos-latest, shell: bash }
115 { os: macos-latest, shell: bash }
119 shell: ${{ matrix.sys.shell }}
121 - name: Work around XDG directories existence (haskell-actions/setup#62)
122 if: runner.os == 'macOS'
124 rm -rf ~/.config/cabal
125 rm -rf ~/.cache/cabal
127 - uses: actions/checkout@v4
129 # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions
130 - name: Add manually supplied allow-newer
131 if: github.event_name == 'workflow_dispatch' && github.event.inputs.allow-newer != ''
133 echo "allow-newer: ${{ github.event.inputs.allow-newer }}" >> cabal.validate.project
135 - name: Add manually supplied constraints
136 if: github.event_name == 'workflow_dispatch' && github.event.inputs.constraints != ''
138 echo "constraints: ${{ github.event.inputs.constraints }}" >> cabal.validate.project
140 - uses: haskell-actions/setup@v2
143 ghc-version: ${{ matrix.ghc }}
144 cabal-version: 3.12.1.0 # see https://github.com/haskell/cabal/pull/10251
145 ghcup-release-channel: https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-prereleases-0.0.8.yaml
147 # See the following link for a breakdown of the following step
148 # https://github.com/haskell/actions/issues/7#issuecomment-745697160
149 - uses: actions/cache@v4
151 # validate.sh uses a special build dir
153 ${{ steps.setup-haskell.outputs.cabal-store }}
155 key: ${{ runner.os }}-${{ matrix.ghc }}-${{ github.sha }}
156 restore-keys: ${{ runner.os }}-${{ matrix.ghc }}-
158 # The tool is not essential to the rest of the test suite. If
159 # hackage-repo-tool is not present, any test that requires it will
161 # We want to keep this in the loop but we don't want to fail if
162 # hackage-repo-tool breaks or fails to support a newer GHC version.
163 - name: Install hackage-repo-tool
164 continue-on-error: true
165 run: cabal install --ignore-project hackage-repo-tool
167 # Needed by cabal-testsuite/PackageTests/Configure/setup.test.hs
168 - name: "MAC: Install Autotools"
169 if: runner.os == 'macOS'
170 run: brew install automake
172 # Needed by cabal-testsuite/PackageTests/Configure/setup.test.hs
173 - name: "WIN: Install Autotools"
174 if: runner.os == 'Windows'
175 run: /usr/bin/pacman --noconfirm -S autotools
177 - name: Set validate inputs
179 FLAGS="${{ env.COMMON_FLAGS }}"
180 if [[ "${{ matrix.ghc }}" == "${{ env.GHC_FOR_SOLVER_BENCHMARKS }}" ]]; then
181 FLAGS="$FLAGS --solver-benchmarks"
183 if [[ "${{ matrix.ghc }}" == "${{ env.GHC_FOR_COMPLETE_HACKAGE_TESTS }}" ]]; then
184 FLAGS="$FLAGS --complete-hackage-tests"
186 echo "FLAGS=$FLAGS" >> "$GITHUB_ENV"
188 - name: Validate print-config
189 run: sh validate.sh $FLAGS -s print-config
191 - name: Validate print-tool-versions
192 run: sh validate.sh $FLAGS -s print-tool-versions
194 - name: Validate build
195 run: sh validate.sh $FLAGS -s build
197 - name: Canonicalize architecture
199 case ${{ runner.arch }} in
202 ARM64) arch=aarch64 ;;
203 *) echo "Unsupported architecture, please fix validate.yaml" 2>/dev/null; exit 1 ;;
205 echo "CABAL_ARCH=$arch" >> "$GITHUB_ENV"
207 - name: Tar cabal head executable
208 if: matrix.ghc == env.GHC_FOR_RELEASE
210 CABAL_EXEC=$(cabal list-bin --builddir=dist-newstyle-validate-ghc-${{ matrix.ghc }} --project-file=cabal.validate.project cabal-install:exe:cabal)
211 # We have to tar the executable to preserve executable permissions
212 # see https://github.com/actions/upload-artifact/issues/38
213 if [[ "${{ runner.os }}" == "Windows" ]]; then
214 # `cabal list-bin` gives us a windows path but tar needs the posix one
215 CABAL_EXEC=$(cygpath "$CABAL_EXEC")
217 if [[ "${{ runner.os }}" == "macOS" ]]; then
218 # Workaround to avoid bsdtar corrupts the executable
219 # so executing it after untar throws `cannot execute binary file`
220 # see https://github.com/actions/virtual-environments/issues/2619#issuecomment-788397841
223 DIR=$(dirname "$CABAL_EXEC")
224 FILE=$(basename "$CABAL_EXEC")
225 CABAL_EXEC_TAR="cabal-head-${{ runner.os }}-$CABAL_ARCH.tar.gz"
226 tar -czvf "$CABAL_EXEC_TAR" -C "$DIR" "$FILE"
227 echo "CABAL_EXEC_TAR=$CABAL_EXEC_TAR" >> "$GITHUB_ENV"
229 # We upload the cabal executable built with the ghc used in the release for:
230 # - Reuse it in the dogfooding job (although we could use the cached build dir)
231 # - Make it available in the workflow to make easier testing it locally
232 - name: Upload cabal-install executable to workflow artifacts
233 if: matrix.ghc == env.GHC_FOR_RELEASE
234 uses: actions/upload-artifact@v4
236 name: cabal-${{ runner.os }}-${{ env.CABAL_ARCH }}
237 path: ${{ env.CABAL_EXEC_TAR }}
239 - name: Validate tests
241 # `rawSystemStdInOut reports text decoding errors`
242 # test does not find ghc without the full path in windows
243 GHCPATH: ${{ steps.setup-haskell.outputs.ghc-exe }}
247 tests="lib-tests lib-suite cli-tests cli-suite"
248 if [ "${{ matrix.ghc }}" = "${{ env.GHC_FOR_SOLVER_BENCHMARKS }}" ]; then
249 tests="$tests solver-benchmarks-tests solver-benchmarks-run"
251 for test in $tests; do
252 echo Validate "$test"
253 sh validate.sh $FLAGS -s "$test" || rc=1
259 name: Validate old ghcs ${{ matrix.extra-ghc }}
260 runs-on: ubuntu-latest
266 ["8.4.4", "8.2.2", "8.0.2"]
267 ## GHC 7.10.3 does not install on ubuntu-22.04 with ghcup.
268 ## Older GHCs are not supported by ghcup in the first place.
272 - uses: actions/checkout@v4
274 - name: Install prerequisites for old GHCs
277 sudo apt-get install libncurses5 libtinfo5
279 - name: Install extra compiler
280 run: ghcup install ghc ${{ matrix.extra-ghc }}
284 run: cat /usr/local/.ghcup/logs/*
286 - name: Install primary compiler
287 uses: haskell-actions/setup@v2
290 ghc-version: ${{ env.GHC_FOR_RELEASE }}
291 cabal-version: latest
296 "ghc-${{ matrix.extra-ghc }}" --version
298 # As we are reusing the cached build dir from the previous step
299 # the generated artifacts are available here,
300 # including the cabal executable and the test suite
301 - uses: actions/cache@v4
304 ${{ steps.setup-haskell.outputs.cabal-store }}
306 key: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-${{ github.sha }}
307 restore-keys: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-
309 - name: Validate build
311 run: sh validate.sh ${{ env.COMMON_FLAGS }} -s build
313 - name: "Validate lib-suite-extras --extra-hc ghc-${{ matrix.extra-ghc }}"
315 EXTRA_GHC: ghc-${{ matrix.extra-ghc }}
316 continue-on-error: true
317 run: sh validate.sh ${{ env.COMMON_FLAGS }} --lib-only -s lib-suite-extras --extra-hc "${{ env.EXTRA_GHC }}"
320 name: Build statically linked using alpine
321 runs-on: ubuntu-latest
322 container: "alpine:3.19"
324 - name: Install extra dependencies
327 apk add bash curl sudo jq pkgconfig \
328 zlib-dev zlib-static binutils-gold curl \
329 gcc g++ gmp-dev libc-dev libffi-dev make \
330 musl-dev ncurses-dev perl tar xz
332 - uses: actions/checkout@v4
334 # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions
335 - name: Manually supplied constraints/allow-newer
336 if: github.event_name == 'workflow_dispatch'
338 echo "allow-newer: ${ALLOWNEWER}" >> cabal.validate.project
339 echo "constraints: ${CONSTRAINTS}" >> cabal.validate.project
341 - uses: haskell-actions/setup@v2
344 ghc-version: ${{ env.GHC_FOR_RELEASE }}
345 cabal-version: latest # latest is mandatory for cabal-testsuite, see https://github.com/haskell/cabal/issues/8133
347 # See the following link for a breakdown of the following step
348 # https://github.com/haskell/actions/issues/7#issuecomment-745697160
349 - uses: actions/cache@v4
351 # validate.sh uses a special build dir
353 ${{ steps.setup-haskell.outputs.cabal-store }}
355 key: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-${{ github.sha }}
356 restore-keys: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-
358 - name: Enable statically linked executables
360 echo 'executable-static: true' >> cabal.validate.project
363 run: sh validate.sh $FLAGS -s build
365 - name: Tar cabal head executable
367 CABAL_EXEC=$(cabal list-bin --builddir=dist-newstyle-validate-ghc-${{ env.GHC_FOR_RELEASE }} --project-file=cabal.validate.project cabal-install:exe:cabal)
368 # We have to tar the executable to preserve executable permissions
369 # see https://github.com/actions/upload-artifact/issues/38
370 DIR=$(dirname "$CABAL_EXEC")
371 FILE=$(basename "$CABAL_EXEC")
372 CABAL_EXEC_TAR="cabal-head-${{ runner.os }}-static-x86_64.tar.gz"
373 tar -czvf "$CABAL_EXEC_TAR" -C "$DIR" "$FILE"
374 echo "CABAL_EXEC_TAR=$CABAL_EXEC_TAR" >> "$GITHUB_ENV"
376 - name: Upload cabal-install executable to workflow artifacts
377 uses: actions/upload-artifact@v4
379 name: cabal-${{ runner.os }}-static-x86_64
380 path: ${{ env.CABAL_EXEC_TAR }}
382 # The previous jobs use a released version of cabal to build cabal HEAD itself
383 # This one uses the cabal HEAD generated executable in the previous step
384 # to build itself again, as sanity check
386 name: Dogfooding ${{ matrix.sys.os }} ghc-${{ matrix.ghc }}
387 runs-on: ${{ matrix.sys.os }}
392 - { os: windows-latest, shell: "C:/msys64/usr/bin/bash.exe -e {0}" }
393 - { os: ubuntu-latest, shell: bash }
394 - { os: macos-latest, shell: bash }
395 # We only use one ghc version the used one for the next release (defined at top of the workflow)
396 # We need to build an array dynamically to inject the appropiate env var in a previous job,
397 # see https://docs.github.com/en/actions/learn-github-actions/expressions#fromjson
398 ghc: ${{ fromJSON (needs.validate.outputs.GHC_FOR_RELEASE) }}
402 shell: ${{ matrix.sys.shell }}
405 # TODO: make a reusable action for this
406 - name: Canonicalize architecture
408 case ${{ runner.arch }} in
411 ARM64) arch=aarch64 ;;
412 *) echo "Unsupported architecture" 2>/dev/null; exit 1 ;;
414 echo "CABAL_ARCH=$arch" >> "$GITHUB_ENV"
416 - name: Work around XDG directories existence (haskell-actions/setup#62)
417 if: runner.os == 'macOS'
419 rm -rf ~/.config/cabal
420 rm -rf ~/.cache/cabal
422 - uses: actions/checkout@v4
424 - uses: haskell-actions/setup@v2
427 ghc-version: ${{ matrix.ghc }}
428 cabal-version: latest # default, we are not using it in this job
430 - name: Download cabal executable from workflow artifacts
431 uses: actions/download-artifact@v4
433 name: cabal-${{ runner.os }}-${{ env.CABAL_ARCH }}
436 - name: Untar the cabal executable
437 run: tar -xzf "./cabal-head/cabal-head-${{ runner.os }}-$CABAL_ARCH.tar.gz" -C cabal-head
439 - name: print-config using cabal HEAD
440 run: sh validate.sh ${{ env.COMMON_FLAGS }} --with-cabal ./cabal-head/cabal -s print-config
442 # We dont use cache to force a build with a fresh store dir and build dir
443 # This way we check cabal can build all its dependencies
444 - name: Build using cabal HEAD
445 run: sh validate.sh ${{ env.COMMON_FLAGS }} --with-cabal ./cabal-head/cabal -s build
448 name: Create a GitHub prerelease with the binary artifacts
449 runs-on: ubuntu-latest
450 if: github.ref == 'refs/heads/master'
454 # IMPORTANT! Any job added to the workflow should be added here too
455 needs: [validate, validate-old-ghcs, build-alpine, dogfooding]
458 # for now this is hardcoded. is there a better way?
459 - uses: actions/download-artifact@v4
464 - name: Create GitHub prerelease
465 uses: softprops/action-gh-release@v2
469 files: binaries/cabal-*
472 name: Create a GitHub LTS prerelease with the binary artifacts
473 runs-on: ubuntu-latest
474 # The LTS branch is hardcoded for now, update it on a new LTS!
475 if: github.ref == 'refs/heads/3.12'
477 # IMPORTANT! Any job added to the workflow should be added here too
478 needs: [validate, validate-old-ghcs, build-alpine, dogfooding]
481 - uses: actions/download-artifact@v4
487 # bash-ism, but we forced bash above
488 mv cabal-{,lts-}head-Windows-x86_64.tar.gz
489 mv cabal-{,lts-}head-Linux-x86_64.tar.gz
490 mv cabal-{,lts-}head-Linux-static-x86_64.tar.gz
491 mv cabal-{,lts-}head-macOS-aarch64.tar.gz
493 - name: Create GitHub prerelease
494 uses: softprops/action-gh-release@v2
496 tag_name: cabal-lts-head
498 files: binaries/cabal-*
500 # We use this job as a summary of the workflow
501 # It will fail if any of the previous jobs does
502 # This way we can use it exclusively in branch protection rules
503 # and abstract away the concrete jobs of the workflow, including their names
506 name: Validate post job
507 runs-on: ubuntu-latest
508 # IMPORTANT! Any job added to the workflow should be added here too
509 needs: [validate, validate-old-ghcs, build-alpine, dogfooding]
513 echo "jobs info: ${{ toJSON(needs) }}"
514 - if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')