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.
29 # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions
33 description: allow-newer line
37 description: constraints line
42 # We choose a stable ghc version across all os's
43 # which will be used to do the next release
44 GHC_FOR_RELEASE: "9.4.8"
45 # Ideally we should use the version about to be released for hackage tests and benchmarks
46 GHC_FOR_SOLVER_BENCHMARKS: "9.4.8"
47 GHC_FOR_COMPLETE_HACKAGE_TESTS: "9.4.8"
48 COMMON_FLAGS: "-j 2 -v"
50 # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions
51 ALLOWNEWER: ${{ github.event.inputs.allow-newer }}
52 CONSTRAINTS: ${{ github.event.inputs.constraints }}
56 name: Validate ${{ matrix.sys.os }} ghc-${{ matrix.ghc }}
57 runs-on: ${{ matrix.sys.os }}
59 GHC_FOR_RELEASE: ${{ format('["{0}"]', env.GHC_FOR_RELEASE) }}
64 - { os: windows-latest, shell: "C:/msys64/usr/bin/bash.exe -e {0}" }
65 - { os: ubuntu-latest, shell: bash }
66 - { os: macos-13, shell: bash }
67 # If you remove something from here, then add it to the old-ghcs job.
68 # Also a removed GHC from here means that we are actually dropping
69 # support, so the PR *must* have a changelog entry.
82 # Throws fatal "cabal-tests.exe: fd:8: hGetLine: end of file" exception
83 # even with --io-manager=native
85 { os: windows-latest, shell: "C:/msys64/usr/bin/bash.exe -e {0}" }
87 # corrupts GHA cache or the fabric of reality itself, see https://github.com/haskell/cabal/issues/8356
89 { os: windows-latest, shell: "C:/msys64/usr/bin/bash.exe -e {0}" }
91 # lot of segfaults caused by ghc bugs
93 { os: windows-latest, shell: "C:/msys64/usr/bin/bash.exe -e {0}" }
97 shell: ${{ matrix.sys.shell }}
99 - name: Work around XDG directories existence (haskell-actions/setup#62)
100 if: runner.os == 'macOS'
102 rm -rf ~/.config/cabal
103 rm -rf ~/.cache/cabal
105 - uses: actions/checkout@v4
107 # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions
108 - name: Add manually supplied allow-newer
109 if: github.event_name == 'workflow_dispatch' && github.event.inputs.allow-newer != ''
111 echo "allow-newer: ${{ github.event.inputs.allow-newer }}" >> cabal.validate.project
113 - name: Add manually supplied constraints
114 if: github.event_name == 'workflow_dispatch' && github.event.inputs.constraints != ''
116 echo "constraints: ${{ github.event.inputs.constraints }}" >> cabal.validate.project
118 - uses: haskell-actions/setup@v2
121 ghc-version: ${{ matrix.ghc }}
122 cabal-version: 3.12.1.0 # see https://github.com/haskell/cabal/pull/10251
123 ghcup-release-channel: https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-prereleases-0.0.8.yaml
125 # See the following link for a breakdown of the following step
126 # https://github.com/haskell/actions/issues/7#issuecomment-745697160
127 - uses: actions/cache@v4
129 # validate.sh uses a special build dir
131 ${{ steps.setup-haskell.outputs.cabal-store }}
133 key: ${{ runner.os }}-${{ matrix.ghc }}-${{ github.sha }}
134 restore-keys: ${{ runner.os }}-${{ matrix.ghc }}-
136 - name: Work around git problem https://bugs.launchpad.net/ubuntu/+source/git/+bug/1993586 (cabal PR #8546)
137 run: git config --global protocol.file.allow always
139 # The tool is not essential to the rest of the test suite. If
140 # hackage-repo-tool is not present, any test that requires it will
142 # We want to keep this in the loop but we don't want to fail if
143 # hackage-repo-tool breaks or fails to support a newer GHC version.
144 - name: Install hackage-repo-tool
145 continue-on-error: true
146 run: cabal install --ignore-project hackage-repo-tool
148 # Needed by cabal-testsuite/PackageTests/Configure/setup.test.hs
149 - name: Install Autotools
150 if: runner.os == 'macOS'
151 run: brew install automake
153 - name: Set validate inputs
155 FLAGS="${{ env.COMMON_FLAGS }}"
156 if [[ "${{ matrix.ghc }}" == "${{ env.GHC_FOR_SOLVER_BENCHMARKS }}" ]]; then
157 FLAGS="$FLAGS --solver-benchmarks"
159 if [[ "${{ matrix.ghc }}" == "${{ env.GHC_FOR_COMPLETE_HACKAGE_TESTS }}" ]]; then
160 FLAGS="$FLAGS --complete-hackage-tests"
162 echo "FLAGS=$FLAGS" >> "$GITHUB_ENV"
164 - name: Validate print-config
165 run: sh validate.sh $FLAGS -s print-config
167 - name: Validate print-tool-versions
168 run: sh validate.sh $FLAGS -s print-tool-versions
170 - name: Validate build
171 run: sh validate.sh $FLAGS -s build
173 - name: Tar cabal head executable
174 if: matrix.ghc == env.GHC_FOR_RELEASE
176 CABAL_EXEC=$(cabal list-bin --builddir=dist-newstyle-validate-ghc-${{ matrix.ghc }} --project-file=cabal.validate.project cabal-install:exe:cabal)
177 # We have to tar the executable to preserve executable permissions
178 # see https://github.com/actions/upload-artifact/issues/38
179 if [[ "${{ runner.os }}" == "Windows" ]]; then
180 # `cabal list-bin` gives us a windows path but tar needs the posix one
181 CABAL_EXEC=$(cygpath "$CABAL_EXEC")
183 if [[ "${{ runner.os }}" == "macOS" ]]; then
184 # Workaround to avoid bsdtar corrupts the executable
185 # so executing it after untar throws `cannot execute binary file`
186 # see https://github.com/actions/virtual-environments/issues/2619#issuecomment-788397841
189 DIR=$(dirname "$CABAL_EXEC")
190 FILE=$(basename "$CABAL_EXEC")
191 CABAL_EXEC_TAR="cabal-head-${{ runner.os }}-x86_64.tar.gz"
192 tar -czvf "$CABAL_EXEC_TAR" -C "$DIR" "$FILE"
193 echo "CABAL_EXEC_TAR=$CABAL_EXEC_TAR" >> "$GITHUB_ENV"
195 # We upload the cabal executable built with the ghc used in the release for:
196 # - Reuse it in the dogfooding job (although we could use the cached build dir)
197 # - Make it available in the workflow to make easier testing it locally
198 - name: Upload cabal-install executable to workflow artifacts
199 if: matrix.ghc == env.GHC_FOR_RELEASE
200 uses: actions/upload-artifact@v4
202 name: cabal-${{ runner.os }}-x86_64
203 path: ${{ env.CABAL_EXEC_TAR }}
205 - name: Validate lib-tests
207 # `rawSystemStdInOut reports text decoding errors`
208 # test does not find ghc without the full path in windows
209 GHCPATH: ${{ steps.setup-haskell.outputs.ghc-exe }}
210 run: sh validate.sh $FLAGS -s lib-tests
212 - name: Validate lib-suite
213 run: sh validate.sh $FLAGS -s lib-suite
215 - name: Validate cli-tests
216 run: sh validate.sh $FLAGS -s cli-tests
218 - name: Validate cli-suite
219 run: sh validate.sh $FLAGS -s cli-suite
221 - name: Validate solver-benchmarks-tests
222 if: matrix.ghc == env.GHC_FOR_SOLVER_BENCHMARKS
223 run: sh validate.sh $FLAGS -s solver-benchmarks-tests
225 - name: Validate solver-benchmarks-run
226 if: matrix.ghc == env.GHC_FOR_SOLVER_BENCHMARKS
227 run: sh validate.sh $FLAGS -s solver-benchmarks-run
230 name: Validate old ghcs ${{ matrix.extra-ghc }}
231 runs-on: ubuntu-latest
237 ["8.4.4", "8.2.2", "8.0.2"]
238 ## GHC 7.10.3 does not install on ubuntu-22.04 with ghcup.
239 ## Older GHCs are not supported by ghcup in the first place.
243 - uses: actions/checkout@v4
245 - name: Install prerequisites for old GHCs
248 sudo apt-get install libncurses5 libtinfo5
250 - name: Install extra compiler
251 run: ghcup install ghc ${{ matrix.extra-ghc }}
255 run: cat /usr/local/.ghcup/logs/*
257 - name: Install primary compiler
258 uses: haskell-actions/setup@v2
261 ghc-version: ${{ env.GHC_FOR_RELEASE }}
262 cabal-version: latest
267 "ghc-${{ matrix.extra-ghc }}" --version
269 # As we are reusing the cached build dir from the previous step
270 # the generated artifacts are available here,
271 # including the cabal executable and the test suite
272 - uses: actions/cache@v4
275 ${{ steps.setup-haskell.outputs.cabal-store }}
277 key: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-${{ github.sha }}
278 restore-keys: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-
280 - name: Validate build
281 run: sh validate.sh ${{ env.COMMON_FLAGS }} -s build
283 - name: "Validate lib-suite-extras --extra-hc ghc-${{ matrix.extra-ghc }}"
285 EXTRA_GHC: ghc-${{ matrix.extra-ghc }}
286 run: sh validate.sh ${{ env.COMMON_FLAGS }} --lib-only -s lib-suite-extras --extra-hc "${{ env.EXTRA_GHC }}"
289 name: Build statically linked using alpine
290 runs-on: ubuntu-latest
291 container: "alpine:3.19"
293 - name: Install extra dependencies
296 apk add bash curl sudo jq pkgconfig \
297 zlib-dev zlib-static binutils-gold curl \
298 gcc g++ gmp-dev libc-dev libffi-dev make \
299 musl-dev ncurses-dev perl tar xz
301 - uses: actions/checkout@v4
303 # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions
304 - name: Manually supplied constraints/allow-newer
305 if: github.event_name == 'workflow_dispatch'
307 echo "allow-newer: ${ALLOWNEWER}" >> cabal.validate.project
308 echo "constraints: ${CONSTRAINTS}" >> cabal.validate.project
310 - uses: haskell-actions/setup@v2
313 ghc-version: ${{ env.GHC_FOR_RELEASE }}
314 cabal-version: latest # latest is mandatory for cabal-testsuite, see https://github.com/haskell/cabal/issues/8133
316 # See the following link for a breakdown of the following step
317 # https://github.com/haskell/actions/issues/7#issuecomment-745697160
318 - uses: actions/cache@v4
320 # validate.sh uses a special build dir
322 ${{ steps.setup-haskell.outputs.cabal-store }}
324 key: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-${{ github.sha }}
325 restore-keys: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-
327 - name: Enable statically linked executables
329 echo 'executable-static: true' >> cabal.validate.project
332 run: sh validate.sh $FLAGS -s build
334 - name: Tar cabal head executable
336 CABAL_EXEC=$(cabal list-bin --builddir=dist-newstyle-validate-ghc-${{ env.GHC_FOR_RELEASE }} --project-file=cabal.validate.project cabal-install:exe:cabal)
337 # We have to tar the executable to preserve executable permissions
338 # see https://github.com/actions/upload-artifact/issues/38
339 DIR=$(dirname "$CABAL_EXEC")
340 FILE=$(basename "$CABAL_EXEC")
341 CABAL_EXEC_TAR="cabal-head-${{ runner.os }}-static-x86_64.tar.gz"
342 tar -czvf "$CABAL_EXEC_TAR" -C "$DIR" "$FILE"
343 echo "CABAL_EXEC_TAR=$CABAL_EXEC_TAR" >> "$GITHUB_ENV"
345 - name: Upload cabal-install executable to workflow artifacts
346 uses: actions/upload-artifact@v4
348 name: cabal-${{ runner.os }}-static-x86_64
349 path: ${{ env.CABAL_EXEC_TAR }}
351 # The previous jobs use a released version of cabal to build cabal HEAD itself
352 # This one uses the cabal HEAD generated executable in the previous step
353 # to build itself again, as sanity check
355 name: Dogfooding ${{ matrix.os }} ghc-${{ matrix.ghc }}
356 runs-on: ${{ matrix.os }}
360 os: [ubuntu-latest, macos-13, windows-latest]
361 # We only use one ghc version the used one for the next release (defined at top of the workflow)
362 # We need to build an array dynamically to inject the appropiate env var in a previous job,
363 # see https://docs.github.com/en/actions/learn-github-actions/expressions#fromjson
364 ghc: ${{ fromJSON (needs.validate.outputs.GHC_FOR_RELEASE) }}
367 - name: Work around XDG directories existence (haskell-actions/setup#62)
368 if: runner.os == 'macOS'
370 rm -rf ~/.config/cabal
371 rm -rf ~/.cache/cabal
373 - uses: actions/checkout@v4
375 - uses: haskell-actions/setup@v2
378 ghc-version: ${{ matrix.ghc }}
379 cabal-version: latest # default, we are not using it in this job
381 - name: Download cabal executable from workflow artifacts
382 uses: actions/download-artifact@v4
384 name: cabal-${{ runner.os }}-x86_64
387 - name: Untar the cabal executable
388 run: tar -xzf "./cabal-head/cabal-head-${{ runner.os }}-x86_64.tar.gz" -C cabal-head
390 - name: print-config using cabal HEAD
391 run: sh validate.sh ${{ env.COMMON_FLAGS }} --with-cabal ./cabal-head/cabal -s print-config
393 # We dont use cache to force a build with a fresh store dir and build dir
394 # This way we check cabal can build all its dependencies
395 - name: Build using cabal HEAD
396 run: sh validate.sh ${{ env.COMMON_FLAGS }} --with-cabal ./cabal-head/cabal -s build
399 name: Create a GitHub prerelease with the binary artifacts
400 runs-on: ubuntu-latest
401 if: github.ref == 'refs/heads/master'
403 # IMPORTANT! Any job added to the workflow should be added here too
404 needs: [validate, validate-old-ghcs, build-alpine, dogfooding]
407 - uses: actions/download-artifact@v4
409 name: cabal-Windows-x86_64
411 - uses: actions/download-artifact@v4
413 name: cabal-Linux-x86_64
415 - uses: actions/download-artifact@v4
417 name: cabal-Linux-static-x86_64
419 - uses: actions/download-artifact@v4
421 name: cabal-macOS-x86_64
423 - name: Create GitHub prerelease
424 uses: marvinpinto/action-automatic-releases@v1.2.1
426 repo_token: ${{ secrets.GITHUB_TOKEN }}
427 automatic_release_tag: cabal-head
431 cabal-head-Windows-x86_64.tar.gz
432 cabal-head-Linux-x86_64.tar.gz
433 cabal-head-Linux-static-x86_64.tar.gz
434 cabal-head-macOS-x86_64.tar.gz
436 # We use this job as a summary of the workflow
437 # It will fail if any of the previous jobs does
438 # This way we can use it exclusively in branch protection rules
439 # and abstract away the concrete jobs of the workflow, including their names
442 name: Validate post job
443 runs-on: ubuntu-latest
444 # IMPORTANT! Any job added to the workflow should be added here too
445 needs: [validate, validate-old-ghcs, build-alpine, dogfooding]
449 echo "jobs info: ${{ toJSON(needs) }}"
450 - if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')