3 # We use bash as default even in windows
4 # to try keep the workflow as uniform as possible
9 # See: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#concurrency.
11 group: ${{ github.ref }}-${{ github.workflow }}
12 cancel-in-progress: true
14 # Note: This workflow file contains the required job "Validate post job". We are using path filtering
15 # here to ignore PRs which only change documentation. This can cause a problem, see the workflow file
16 # "validate.skip.yml" for a description of the problem and the solution provided in that file.
35 # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions
39 description: allow-newer line
43 description: constraints line
48 # We choose a stable ghc version across all os's
49 # which will be used to do the next release
50 GHC_FOR_RELEASE: '9.2.8'
51 # Ideally we should use the version about to be released for hackage tests and benchmarks
52 GHC_FOR_SOLVER_BENCHMARKS: '9.2.8'
53 GHC_FOR_COMPLETE_HACKAGE_TESTS: '9.2.8'
54 COMMON_FLAGS: '-j 2 -v'
56 # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions
57 ALLOWNEWER: ${{ github.event.inputs.allow-newer }}
58 CONSTRAINTS: ${{ github.event.inputs.constraints }}
63 name: Validate ${{ matrix.os }} ghc-${{ matrix.ghc }}
64 runs-on: ${{ matrix.os }}
66 GHC_FOR_RELEASE: ${{ format('["{0}"]', env.GHC_FOR_RELEASE) }}
69 os: ["ubuntu-latest", "macos-latest", "windows-latest"]
70 ghc: ["9.8.1", "9.6.3", "9.4.8", "9.2.8", "9.0.2", "8.10.7", "8.8.4", "8.6.5"]
72 # corrupts GHA cache or the fabric of reality itself, see https://github.com/haskell/cabal/issues/8356
73 - os: "windows-latest"
75 # lot of segfaults caused by ghc bugs
76 - os: "windows-latest"
78 # it also throws segfaults randomly
79 - os: "windows-latest"
81 # it often randomly does "C:\Users\RUNNER~1\AppData\Local\Temp\ghcFEDE.c: DeleteFile "\\\\?\\C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\ghcFEDE.c": permission denied (Access is denied.)"
82 - os: "windows-latest"
87 - name: Work around XDG directories existence (haskell-actions/setup#62)
88 if: ${{ runner.os == 'macOS' }}
90 rm -rf ~/.config/cabal
93 - uses: actions/checkout@v4
95 # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions
96 - name: Manually supplied constraints/allow-newer
97 if: ${{ github.event_name == 'workflow_dispatch' }}
99 echo 'allow-newer:' ${ALLOWNEWER} >> cabal.project.validate
100 echo 'constraints:' ${CONSTRAINTS} >> cabal.project.validate
102 # See the following link for a breakdown of the following step
103 # https://github.com/haskell/actions/issues/7#issuecomment-745697160
104 - uses: actions/cache@v3
106 # validate.sh uses a special build dir
108 ${{ steps.setup-haskell.outputs.cabal-store }}
110 key: ${{ runner.os }}-${{ matrix.ghc }}-${{ github.sha }}
111 restore-keys: ${{ runner.os }}-${{ matrix.ghc }}-
113 - uses: haskell-actions/setup@v2
116 ghc-version: ${{ matrix.ghc }}
117 cabal-version: latest # latest is mandatory for cabal-testsuite, see https://github.com/haskell/cabal/issues/8133
119 - name: Work around git problem https://bugs.launchpad.net/ubuntu/+source/git/+bug/1993586 (cabal PR #8546)
121 git config --global protocol.file.allow always
123 # The tool is not essential to the rest of the test suite. If
124 # hackage-repo-tool is not present, any test that requires it will
126 # We want to keep this in the loop but we don't want to fail if
127 # hackage-repo-tool breaks or fails to support a newer GHC version.
128 - name: Install hackage-repo-tool
129 continue-on-error: true
132 cabal install hackage-repo-tool
134 # Needed by cabal-testsuite/PackageTests/Configure/setup.test.hs
135 - name: Install Autotools
136 if: runner.os == 'macOS'
138 brew install automake
140 - name: Set validate inputs
142 FLAGS="${{ env.COMMON_FLAGS }}"
143 if [[ ${{ matrix.ghc }} == ${{ env.GHC_FOR_SOLVER_BENCHMARKS }} ]]; then
144 FLAGS="$FLAGS --solver-benchmarks"
146 if [[ ${{ matrix.ghc }} == ${{ env.GHC_FOR_COMPLETE_HACKAGE_TESTS }} ]]; then
147 FLAGS="$FLAGS --complete-hackage-tests"
149 echo "FLAGS=$FLAGS" >> $GITHUB_ENV
151 - name: Validate print-config
152 run: sh validate.sh $FLAGS -s print-config
154 - name: Validate print-tool-versions
155 run: sh validate.sh $FLAGS -s print-tool-versions
157 - name: Validate build
158 run: sh validate.sh $FLAGS -s build
160 - name: Tar cabal head executable
161 if: matrix.ghc == env.GHC_FOR_RELEASE
163 CABAL_EXEC=$(cabal list-bin --builddir=dist-newstyle-validate-ghc-${{ matrix.ghc }} --project-file=cabal.project.validate cabal-install:exe:cabal)
164 # We have to tar the executable to preserve executable permissions
165 # see https://github.com/actions/upload-artifact/issues/38
166 if [[ ${{ runner.os }} == 'Windows' ]]; then
167 # `cabal list-bin` gives us a windows path but tar needs the posix one
168 CABAL_EXEC=$(cygpath $CABAL_EXEC)
170 if [[ "${{ runner.os }}" == "macOS" ]]; then
171 # Workaround to avoid bsdtar corrupts the executable
172 # so executing it after untar throws `cannot execute binary file`
173 # see https://github.com/actions/virtual-environments/issues/2619#issuecomment-788397841
176 export CABAL_EXEC_TAR="cabal-head-${{ runner.os }}-x86_64.tar.gz"
177 tar -czvf $CABAL_EXEC_TAR -C $(dirname "$CABAL_EXEC") $(basename "$CABAL_EXEC")
178 echo "CABAL_EXEC_TAR=$CABAL_EXEC_TAR" >> $GITHUB_ENV
180 # We upload the cabal executable built with the ghc used in the release for:
181 # - Reuse it in the dogfooding job (although we could use the cached build dir)
182 # - Make it available in the workflow to make easier testing it locally
183 - name: Upload cabal-install executable to workflow artifacts
184 if: matrix.ghc == env.GHC_FOR_RELEASE
185 uses: actions/upload-artifact@v3
187 name: cabal-${{ runner.os }}-x86_64
188 path: ${{ env.CABAL_EXEC_TAR }}
190 - name: Validate lib-tests
192 # `rawSystemStdInOut reports text decoding errors`
193 # test does not find ghc without the full path in windows
194 GHCPATH: ${{ steps.setup-haskell.outputs.ghc-exe }}
195 run: sh validate.sh $FLAGS -s lib-tests
197 - name: Validate lib-suite
198 # Have to disable *-suite validation:
199 # - the Windows@9.6.1 problem is tracked at https://github.com/haskell/cabal/issues/8858
200 # - but curently can't run it with GHC 9.6, tracking: https://github.com/haskell/cabal/issues/8883
201 run: sh validate.sh $FLAGS -s lib-suite
203 - name: Validate cli-tests
204 run: sh validate.sh $FLAGS -s cli-tests
206 - name: Validate cli-suite
207 # Have to disable *-suite validation, see above the comment for lib-suite
208 run: sh validate.sh $FLAGS -s cli-suite
210 - name: Validate solver-benchmarks-tests
212 if [[ ${{ matrix.ghc }} == ${{ env.GHC_FOR_SOLVER_BENCHMARKS }} ]]; then
213 sh validate.sh $FLAGS -s solver-benchmarks-tests
216 - name: Validate solver-benchmarks-run
218 if [[ ${{ matrix.ghc }} == ${{ env.GHC_FOR_SOLVER_BENCHMARKS }} ]]; then
219 sh validate.sh $FLAGS -s solver-benchmarks-run
223 name: Validate old ghcs ${{ matrix.extra-ghc }}
224 runs-on: ubuntu-latest
226 # This job needs an older ubuntu (16.04) cause
227 # the required old ghcs using the `-dyn` flavour
228 # are not installable from ppa/hvr in newer ones
229 # see https://github.com/haskell/cabal/issues/8011
231 image: phadej/ghc:8.8.4-xenial
235 # Newer ghc versions than 8.8.4 have to be installed with ghcup cause
236 # they are not available in ppa/hvr. The ghcup installation
237 # needs `sudo` which is not available in the xenial container
239 extra-ghc: ["7.10.3", "7.8.4", "7.6.3", "7.4.2", "7.2.2", "7.0.4"]
243 # We can't use actions/checkout with the xenial docker container
244 # cause it does not work with the git version included in it, see:
245 # https://github.com/actions/checkout/issues/170
246 # https://github.com/actions/checkout/issues/295
247 # - uses: actions/checkout@v4
250 echo $GITHUB_REF $GITHUB_SHA
251 git clone --depth 1 https://github.com/$GITHUB_REPOSITORY.git .
252 git fetch origin $GITHUB_SHA:temporary-ci-branch
253 git checkout $GITHUB_SHA || (git fetch && git checkout $GITHUB_SHA)
255 - name: Install extra compiler
258 apt-get install -y ghc-${{ matrix.extra-ghc }}-dyn
260 - uses: haskell-actions/setup@v2
263 ghc-version: ${{ matrix.ghc }}
264 # Make sure this bindist works in this old environment
265 cabal-version: 3.10.1.0
267 # As we are reusing the cached build dir from the previous step
268 # the generated artifacts are available here,
269 # including the cabal executable and the test suite
270 - uses: actions/cache@v3
273 ${{ steps.setup-haskell.outputs.cabal-store }}
275 key: ${{ runner.os }}-${{ matrix.ghc }}-${{ github.sha }}
276 restore-keys: ${{ runner.os }}-${{ matrix.ghc }}-
278 - name: Validate build
279 run: sh validate.sh ${{ env.COMMON_FLAGS }} -s build
281 - name: "Validate lib-suite-extras --extra-hc ghc-${{ matrix.extra-ghc }}"
283 EXTRA_GHC: "/opt/ghc/${{ matrix.extra-ghc }}/bin/ghc-${{ matrix.extra-ghc }}"
284 run: sh validate.sh ${{ env.COMMON_FLAGS }} --lib-only -s lib-suite-extras --extra-hc ${{ env.EXTRA_GHC }}
287 name: Build statically linked using alpine
288 runs-on: "ubuntu-latest"
289 container: "alpine:3.19"
291 - name: Install extra dependencies
294 apk add bash curl sudo jq pkgconfig \
295 zlib-dev zlib-static binutils-gold curl \
296 gcc g++ gmp-dev libc-dev libffi-dev make \
297 musl-dev ncurses-dev perl tar xz
299 - uses: actions/checkout@v4
301 # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions
302 - name: Manually supplied constraints/allow-newer
303 if: ${{ github.event_name == 'workflow_dispatch' }}
305 echo 'allow-newer:' ${ALLOWNEWER} >> cabal.project.validate
306 echo 'constraints:' ${CONSTRAINTS} >> cabal.project.validate
308 # See the following link for a breakdown of the following step
309 # https://github.com/haskell/actions/issues/7#issuecomment-745697160
310 - uses: actions/cache@v3
312 # validate.sh uses a special build dir
314 ${{ steps.setup-haskell.outputs.cabal-store }}
316 key: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-${{ github.sha }}
317 restore-keys: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-
319 - uses: haskell-actions/setup@v2
322 ghc-version: ${{ env.GHC_FOR_RELEASE }}
323 cabal-version: latest # latest is mandatory for cabal-testsuite, see https://github.com/haskell/cabal/issues/8133
325 - name: Enable statically linked executables
327 echo 'executable-static: true' >> cabal.project.validate
330 run: sh validate.sh $FLAGS -s build
332 - name: Tar cabal head executable
334 CABAL_EXEC=$(cabal list-bin --builddir=dist-newstyle-validate-ghc-${{ env.GHC_FOR_RELEASE }} --project-file=cabal.project.validate cabal-install:exe:cabal)
335 # We have to tar the executable to preserve executable permissions
336 # see https://github.com/actions/upload-artifact/issues/38
337 export CABAL_EXEC_TAR="cabal-head-${{ runner.os }}-static-x86_64.tar.gz"
338 tar -czvf $CABAL_EXEC_TAR -C $(dirname "$CABAL_EXEC") $(basename "$CABAL_EXEC")
339 echo "CABAL_EXEC_TAR=$CABAL_EXEC_TAR" >> $GITHUB_ENV
341 - name: Upload cabal-install executable to workflow artifacts
342 uses: actions/upload-artifact@v3
344 name: cabal-${{ runner.os }}-static-x86_64
345 path: ${{ env.CABAL_EXEC_TAR }}
348 # The previous jobs use a released version of cabal to build cabal HEAD itself
349 # This one uses the cabal HEAD generated executable in the previous step
350 # to build itself again, as sanity check
352 name: Dogfooding ${{ matrix.os }} ghc-${{ matrix.ghc }}
353 runs-on: ${{ matrix.os }}
357 os: ["ubuntu-latest", "macos-latest", "windows-latest"]
358 # We only use one ghc version the used one for the next release (defined at top of the workflow)
359 # We need to build an array dynamically to inject the appropiate env var in a previous job,
360 # see https://docs.github.com/en/actions/learn-github-actions/expressions#fromjson
361 ghc: ${{ fromJSON (needs.validate.outputs.GHC_FOR_RELEASE) }}
364 - name: Work around XDG directories existence (haskell-actions/setup#62)
365 if: ${{ runner.os == 'macOS' }}
367 rm -rf ~/.config/cabal
368 rm -rf ~/.cache/cabal
370 - uses: actions/checkout@v4
372 # See https://github.com/haskell/cabal/pull/8739
373 - name: Sudo chmod to permit ghcup to update its cache
375 if [[ "${{ runner.os }}" == "Linux" ]]; then
376 sudo ls -lah /usr/local/.ghcup/cache
377 sudo mkdir -p /usr/local/.ghcup/cache
378 sudo ls -lah /usr/local/.ghcup/cache
379 sudo chown -R $USER /usr/local/.ghcup
380 sudo chmod -R 777 /usr/local/.ghcup
382 - uses: haskell-actions/setup@v2
385 ghc-version: ${{ matrix.ghc }}
386 cabal-version: latest # default, we are not using it in this job
388 - name: Download cabal executable from workflow artifacts
389 uses: actions/download-artifact@v3
391 name: cabal-${{ runner.os }}-x86_64
394 - name: Untar the cabal executable
395 run: tar -xzf ./cabal-head/cabal-head-${{ runner.os }}-x86_64.tar.gz -C cabal-head
397 - name: print-config using cabal HEAD
398 run: sh validate.sh ${{ env.COMMON_FLAGS }} --with-cabal ./cabal-head/cabal -s print-config
400 # We dont use cache to force a build with a fresh store dir and build dir
401 # This way we check cabal can build all its dependencies
402 - name: Build using cabal HEAD
403 run: sh validate.sh ${{ env.COMMON_FLAGS }} --with-cabal ./cabal-head/cabal -s build
406 name: Create a GitHub prerelease with the binary artifacts
407 runs-on: ubuntu-latest
408 if: github.ref == 'refs/heads/master'
410 # IMPORTANT! Any job added to the workflow should be added here too
411 needs: [validate, validate-old-ghcs, build-alpine, dogfooding]
414 - uses: actions/download-artifact@v3
416 name: cabal-Windows-x86_64
418 - uses: actions/download-artifact@v3
420 name: cabal-Linux-x86_64
422 - uses: actions/download-artifact@v3
424 name: cabal-Linux-static-x86_64
426 - uses: actions/download-artifact@v3
428 name: cabal-macOS-x86_64
430 - name: Create GitHub prerelease
431 uses: "marvinpinto/action-automatic-releases@v1.2.1"
433 repo_token: "${{ secrets.GITHUB_TOKEN }}"
434 automatic_release_tag: "cabal-head"
438 cabal-head-Windows-x86_64.tar.gz
439 cabal-head-Linux-x86_64.tar.gz
440 cabal-head-Linux-static-x86_64.tar.gz
441 cabal-head-macOS-x86_64.tar.gz
443 # We use this job as a summary of the workflow
444 # It will fail if any of the previous jobs does it
445 # This way we can use it exclusively in branch protection rules
446 # and abstract away the concrete jobs of the workflow, including their names
449 name: Validate post job
450 runs-on: ubuntu-latest
451 # IMPORTANT! Any job added to the workflow should be added here too
452 needs: [validate, validate-old-ghcs, build-alpine, dogfooding]
456 echo "jobs info: ${{ toJSON(needs) }}"
457 - if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')