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-13, 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}" }
106 shell: ${{ matrix.sys.shell }}
108 - name: Work around XDG directories existence (haskell-actions/setup#62)
109 if: runner.os == 'macOS'
111 rm -rf ~/.config/cabal
112 rm -rf ~/.cache/cabal
114 - uses: actions/checkout@v4
116 # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions
117 - name: Add manually supplied allow-newer
118 if: github.event_name == 'workflow_dispatch' && github.event.inputs.allow-newer != ''
120 echo "allow-newer: ${{ github.event.inputs.allow-newer }}" >> cabal.validate.project
122 - name: Add manually supplied constraints
123 if: github.event_name == 'workflow_dispatch' && github.event.inputs.constraints != ''
125 echo "constraints: ${{ github.event.inputs.constraints }}" >> cabal.validate.project
127 - uses: haskell-actions/setup@v2
130 ghc-version: ${{ matrix.ghc }}
131 cabal-version: 3.12.1.0 # see https://github.com/haskell/cabal/pull/10251
132 ghcup-release-channel: https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-prereleases-0.0.8.yaml
134 # See the following link for a breakdown of the following step
135 # https://github.com/haskell/actions/issues/7#issuecomment-745697160
136 - uses: actions/cache@v4
138 # validate.sh uses a special build dir
140 ${{ steps.setup-haskell.outputs.cabal-store }}
142 key: ${{ runner.os }}-${{ matrix.ghc }}-${{ github.sha }}
143 restore-keys: ${{ runner.os }}-${{ matrix.ghc }}-
145 # The tool is not essential to the rest of the test suite. If
146 # hackage-repo-tool is not present, any test that requires it will
148 # We want to keep this in the loop but we don't want to fail if
149 # hackage-repo-tool breaks or fails to support a newer GHC version.
150 - name: Install hackage-repo-tool
151 continue-on-error: true
152 run: cabal install --ignore-project hackage-repo-tool
154 # Needed by cabal-testsuite/PackageTests/Configure/setup.test.hs
155 - name: "MAC: Install Autotools"
156 if: runner.os == 'macOS'
157 run: brew install automake
159 # Needed by cabal-testsuite/PackageTests/Configure/setup.test.hs
160 - name: "WIN: Install Autotools"
161 if: runner.os == 'Windows'
162 run: /usr/bin/pacman --noconfirm -S autotools
164 - name: Set validate inputs
166 FLAGS="${{ env.COMMON_FLAGS }}"
167 if [[ "${{ matrix.ghc }}" == "${{ env.GHC_FOR_SOLVER_BENCHMARKS }}" ]]; then
168 FLAGS="$FLAGS --solver-benchmarks"
170 if [[ "${{ matrix.ghc }}" == "${{ env.GHC_FOR_COMPLETE_HACKAGE_TESTS }}" ]]; then
171 FLAGS="$FLAGS --complete-hackage-tests"
173 echo "FLAGS=$FLAGS" >> "$GITHUB_ENV"
175 - name: Validate print-config
176 run: sh validate.sh $FLAGS -s print-config
178 - name: Validate print-tool-versions
179 run: sh validate.sh $FLAGS -s print-tool-versions
181 - name: Validate build
182 run: sh validate.sh $FLAGS -s build
184 - name: Tar cabal head executable
185 if: matrix.ghc == env.GHC_FOR_RELEASE
187 CABAL_EXEC=$(cabal list-bin --builddir=dist-newstyle-validate-ghc-${{ matrix.ghc }} --project-file=cabal.validate.project cabal-install:exe:cabal)
188 # We have to tar the executable to preserve executable permissions
189 # see https://github.com/actions/upload-artifact/issues/38
190 if [[ "${{ runner.os }}" == "Windows" ]]; then
191 # `cabal list-bin` gives us a windows path but tar needs the posix one
192 CABAL_EXEC=$(cygpath "$CABAL_EXEC")
194 if [[ "${{ runner.os }}" == "macOS" ]]; then
195 # Workaround to avoid bsdtar corrupts the executable
196 # so executing it after untar throws `cannot execute binary file`
197 # see https://github.com/actions/virtual-environments/issues/2619#issuecomment-788397841
200 DIR=$(dirname "$CABAL_EXEC")
201 FILE=$(basename "$CABAL_EXEC")
202 CABAL_EXEC_TAR="cabal-head-${{ runner.os }}-x86_64.tar.gz"
203 tar -czvf "$CABAL_EXEC_TAR" -C "$DIR" "$FILE"
204 echo "CABAL_EXEC_TAR=$CABAL_EXEC_TAR" >> "$GITHUB_ENV"
206 # We upload the cabal executable built with the ghc used in the release for:
207 # - Reuse it in the dogfooding job (although we could use the cached build dir)
208 # - Make it available in the workflow to make easier testing it locally
209 - name: Upload cabal-install executable to workflow artifacts
210 if: matrix.ghc == env.GHC_FOR_RELEASE
211 uses: actions/upload-artifact@v4
213 name: cabal-${{ runner.os }}-x86_64
214 path: ${{ env.CABAL_EXEC_TAR }}
216 - name: Validate lib-tests
218 # `rawSystemStdInOut reports text decoding errors`
219 # test does not find ghc without the full path in windows
220 GHCPATH: ${{ steps.setup-haskell.outputs.ghc-exe }}
221 run: sh validate.sh $FLAGS -s lib-tests
223 - name: Validate lib-suite
224 run: sh validate.sh $FLAGS -s lib-suite
226 - name: Validate cli-tests
227 run: sh validate.sh $FLAGS -s cli-tests
229 - name: Validate cli-suite
230 run: sh validate.sh $FLAGS -s cli-suite
232 - name: Validate solver-benchmarks-tests
233 if: matrix.ghc == env.GHC_FOR_SOLVER_BENCHMARKS
234 run: sh validate.sh $FLAGS -s solver-benchmarks-tests
236 - name: Validate solver-benchmarks-run
237 if: matrix.ghc == env.GHC_FOR_SOLVER_BENCHMARKS
238 run: sh validate.sh $FLAGS -s solver-benchmarks-run
241 name: Validate old ghcs ${{ matrix.extra-ghc }}
242 runs-on: ubuntu-latest
248 ["8.4.4", "8.2.2", "8.0.2"]
249 ## GHC 7.10.3 does not install on ubuntu-22.04 with ghcup.
250 ## Older GHCs are not supported by ghcup in the first place.
254 - uses: actions/checkout@v4
256 - name: Install prerequisites for old GHCs
259 sudo apt-get install libncurses5 libtinfo5
261 - name: Install extra compiler
262 run: ghcup install ghc ${{ matrix.extra-ghc }}
266 run: cat /usr/local/.ghcup/logs/*
268 - name: Install primary compiler
269 uses: haskell-actions/setup@v2
272 ghc-version: ${{ env.GHC_FOR_RELEASE }}
273 cabal-version: latest
278 "ghc-${{ matrix.extra-ghc }}" --version
280 # As we are reusing the cached build dir from the previous step
281 # the generated artifacts are available here,
282 # including the cabal executable and the test suite
283 - uses: actions/cache@v4
286 ${{ steps.setup-haskell.outputs.cabal-store }}
288 key: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-${{ github.sha }}
289 restore-keys: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-
291 - name: Validate build
292 run: sh validate.sh ${{ env.COMMON_FLAGS }} -s build
294 - name: "Validate lib-suite-extras --extra-hc ghc-${{ matrix.extra-ghc }}"
296 EXTRA_GHC: ghc-${{ matrix.extra-ghc }}
297 run: sh validate.sh ${{ env.COMMON_FLAGS }} --lib-only -s lib-suite-extras --extra-hc "${{ env.EXTRA_GHC }}"
300 name: Build statically linked using alpine
301 runs-on: ubuntu-latest
302 container: "alpine:3.19"
304 - name: Install extra dependencies
307 apk add bash curl sudo jq pkgconfig \
308 zlib-dev zlib-static binutils-gold curl \
309 gcc g++ gmp-dev libc-dev libffi-dev make \
310 musl-dev ncurses-dev perl tar xz
312 - uses: actions/checkout@v4
314 # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions
315 - name: Manually supplied constraints/allow-newer
316 if: github.event_name == 'workflow_dispatch'
318 echo "allow-newer: ${ALLOWNEWER}" >> cabal.validate.project
319 echo "constraints: ${CONSTRAINTS}" >> cabal.validate.project
321 - uses: haskell-actions/setup@v2
324 ghc-version: ${{ env.GHC_FOR_RELEASE }}
325 cabal-version: latest # latest is mandatory for cabal-testsuite, see https://github.com/haskell/cabal/issues/8133
327 # See the following link for a breakdown of the following step
328 # https://github.com/haskell/actions/issues/7#issuecomment-745697160
329 - uses: actions/cache@v4
331 # validate.sh uses a special build dir
333 ${{ steps.setup-haskell.outputs.cabal-store }}
335 key: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-${{ github.sha }}
336 restore-keys: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-
338 - name: Enable statically linked executables
340 echo 'executable-static: true' >> cabal.validate.project
343 run: sh validate.sh $FLAGS -s build
345 - name: Tar cabal head executable
347 CABAL_EXEC=$(cabal list-bin --builddir=dist-newstyle-validate-ghc-${{ env.GHC_FOR_RELEASE }} --project-file=cabal.validate.project cabal-install:exe:cabal)
348 # We have to tar the executable to preserve executable permissions
349 # see https://github.com/actions/upload-artifact/issues/38
350 DIR=$(dirname "$CABAL_EXEC")
351 FILE=$(basename "$CABAL_EXEC")
352 CABAL_EXEC_TAR="cabal-head-${{ runner.os }}-static-x86_64.tar.gz"
353 tar -czvf "$CABAL_EXEC_TAR" -C "$DIR" "$FILE"
354 echo "CABAL_EXEC_TAR=$CABAL_EXEC_TAR" >> "$GITHUB_ENV"
356 - name: Upload cabal-install executable to workflow artifacts
357 uses: actions/upload-artifact@v4
359 name: cabal-${{ runner.os }}-static-x86_64
360 path: ${{ env.CABAL_EXEC_TAR }}
362 # The previous jobs use a released version of cabal to build cabal HEAD itself
363 # This one uses the cabal HEAD generated executable in the previous step
364 # to build itself again, as sanity check
366 name: Dogfooding ${{ matrix.os }} ghc-${{ matrix.ghc }}
367 runs-on: ${{ matrix.os }}
371 os: [ubuntu-latest, macos-13, windows-latest]
372 # We only use one ghc version the used one for the next release (defined at top of the workflow)
373 # We need to build an array dynamically to inject the appropiate env var in a previous job,
374 # see https://docs.github.com/en/actions/learn-github-actions/expressions#fromjson
375 ghc: ${{ fromJSON (needs.validate.outputs.GHC_FOR_RELEASE) }}
378 - name: Work around XDG directories existence (haskell-actions/setup#62)
379 if: runner.os == 'macOS'
381 rm -rf ~/.config/cabal
382 rm -rf ~/.cache/cabal
384 - uses: actions/checkout@v4
386 - uses: haskell-actions/setup@v2
389 ghc-version: ${{ matrix.ghc }}
390 cabal-version: latest # default, we are not using it in this job
392 - name: Download cabal executable from workflow artifacts
393 uses: actions/download-artifact@v4
395 name: cabal-${{ runner.os }}-x86_64
398 - name: Untar the cabal executable
399 run: tar -xzf "./cabal-head/cabal-head-${{ runner.os }}-x86_64.tar.gz" -C cabal-head
401 - name: print-config using cabal HEAD
402 run: sh validate.sh ${{ env.COMMON_FLAGS }} --with-cabal ./cabal-head/cabal -s print-config
404 # We dont use cache to force a build with a fresh store dir and build dir
405 # This way we check cabal can build all its dependencies
406 - name: Build using cabal HEAD
407 run: sh validate.sh ${{ env.COMMON_FLAGS }} --with-cabal ./cabal-head/cabal -s build
410 name: Create a GitHub prerelease with the binary artifacts
411 runs-on: ubuntu-latest
412 if: github.ref == 'refs/heads/master'
414 # IMPORTANT! Any job added to the workflow should be added here too
415 needs: [validate, validate-old-ghcs, build-alpine, dogfooding]
418 - uses: actions/download-artifact@v4
420 name: cabal-Windows-x86_64
422 - uses: actions/download-artifact@v4
424 name: cabal-Linux-x86_64
426 - uses: actions/download-artifact@v4
428 name: cabal-Linux-static-x86_64
430 - uses: actions/download-artifact@v4
432 name: cabal-macOS-x86_64
434 - name: Create GitHub prerelease
435 uses: marvinpinto/action-automatic-releases@v1.2.1
437 repo_token: ${{ secrets.GITHUB_TOKEN }}
438 automatic_release_tag: cabal-head
442 cabal-head-Windows-x86_64.tar.gz
443 cabal-head-Linux-x86_64.tar.gz
444 cabal-head-Linux-static-x86_64.tar.gz
445 cabal-head-macOS-x86_64.tar.gz
447 # We use this job as a summary of the workflow
448 # It will fail if any of the previous jobs does
449 # This way we can use it exclusively in branch protection rules
450 # and abstract away the concrete jobs of the workflow, including their names
453 name: Validate post job
454 runs-on: ubuntu-latest
455 # IMPORTANT! Any job added to the workflow should be added here too
456 needs: [validate, validate-old-ghcs, build-alpine, dogfooding]
460 echo "jobs info: ${{ toJSON(needs) }}"
461 - if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')