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.4.8'
51 # Ideally we should use the version about to be released for hackage tests and benchmarks
52 GHC_FOR_SOLVER_BENCHMARKS: '9.4.8'
53 GHC_FOR_COMPLETE_HACKAGE_TESTS: '9.4.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-13, windows-latest]
70 # If you remove something from here, then add it to the old-ghcs job.
71 # Also a removed GHC from here means that we are actually dropping
72 # support, so the PR *must* have a changelog entry.
73 ghc: ['9.10.1', '9.8.2', '9.6.4', '9.4.8', '9.2.8', '9.0.2', '8.10.7', '8.8.4', '8.6.5']
75 # corrupts GHA cache or the fabric of reality itself, see https://github.com/haskell/cabal/issues/8356
78 # lot of segfaults caused by ghc bugs
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.)"
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.validate.project
100 echo "constraints: ${CONSTRAINTS}" >> cabal.validate.project
102 - uses: haskell-actions/setup@v2
105 ghc-version: ${{ matrix.ghc }}
106 cabal-version: latest # latest is mandatory for cabal-testsuite, see https://github.com/haskell/cabal/issues/8133
107 ghcup-release-channel: https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-prereleases-0.0.8.yaml
109 # See the following link for a breakdown of the following step
110 # https://github.com/haskell/actions/issues/7#issuecomment-745697160
111 - uses: actions/cache@v4
113 # validate.sh uses a special build dir
115 ${{ steps.setup-haskell.outputs.cabal-store }}
117 key: ${{ runner.os }}-${{ matrix.ghc }}-${{ github.sha }}
118 restore-keys: ${{ runner.os }}-${{ matrix.ghc }}-
120 - name: Work around git problem https://bugs.launchpad.net/ubuntu/+source/git/+bug/1993586 (cabal PR #8546)
121 run: 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
130 run: cabal install --ignore-project hackage-repo-tool
132 # Needed by cabal-testsuite/PackageTests/Configure/setup.test.hs
133 - name: Install Autotools
134 if: runner.os == 'macOS'
135 run: brew install automake
137 - name: Set validate inputs
139 FLAGS="${{ env.COMMON_FLAGS }}"
140 if [[ "${{ matrix.ghc }}" == "${{ env.GHC_FOR_SOLVER_BENCHMARKS }}" ]]; then
141 FLAGS="$FLAGS --solver-benchmarks"
143 if [[ "${{ matrix.ghc }}" == "${{ env.GHC_FOR_COMPLETE_HACKAGE_TESTS }}" ]]; then
144 FLAGS="$FLAGS --complete-hackage-tests"
146 echo "FLAGS=$FLAGS" >> "$GITHUB_ENV"
148 - name: Validate print-config
149 run: sh validate.sh $FLAGS -s print-config
151 - name: Validate print-tool-versions
152 run: sh validate.sh $FLAGS -s print-tool-versions
154 - name: Validate build
155 run: sh validate.sh $FLAGS -s build
157 - name: Tar cabal head executable
158 if: matrix.ghc == env.GHC_FOR_RELEASE
160 CABAL_EXEC=$(cabal list-bin --builddir=dist-newstyle-validate-ghc-${{ matrix.ghc }} --project-file=cabal.validate.project cabal-install:exe:cabal)
161 # We have to tar the executable to preserve executable permissions
162 # see https://github.com/actions/upload-artifact/issues/38
163 if [[ "${{ runner.os }}" == "Windows" ]]; then
164 # `cabal list-bin` gives us a windows path but tar needs the posix one
165 CABAL_EXEC=$(cygpath "$CABAL_EXEC")
167 if [[ "${{ runner.os }}" == "macOS" ]]; then
168 # Workaround to avoid bsdtar corrupts the executable
169 # so executing it after untar throws `cannot execute binary file`
170 # see https://github.com/actions/virtual-environments/issues/2619#issuecomment-788397841
173 DIR=$(dirname "$CABAL_EXEC")
174 FILE=$(basename "$CABAL_EXEC")
175 CABAL_EXEC_TAR="cabal-head-${{ runner.os }}-x86_64.tar.gz"
176 tar -czvf "$CABAL_EXEC_TAR" -C "$DIR" "$FILE"
177 echo "CABAL_EXEC_TAR=$CABAL_EXEC_TAR" >> "$GITHUB_ENV"
179 # We upload the cabal executable built with the ghc used in the release for:
180 # - Reuse it in the dogfooding job (although we could use the cached build dir)
181 # - Make it available in the workflow to make easier testing it locally
182 - name: Upload cabal-install executable to workflow artifacts
183 if: matrix.ghc == env.GHC_FOR_RELEASE
184 uses: actions/upload-artifact@v3
186 name: cabal-${{ runner.os }}-x86_64
187 path: ${{ env.CABAL_EXEC_TAR }}
189 - name: Validate lib-tests
191 # `rawSystemStdInOut reports text decoding errors`
192 # test does not find ghc without the full path in windows
193 GHCPATH: ${{ steps.setup-haskell.outputs.ghc-exe }}
194 run: sh validate.sh $FLAGS -s lib-tests
196 - name: Validate lib-suite
197 run: sh validate.sh $FLAGS -s lib-suite
199 - name: Validate cli-tests
200 run: sh validate.sh $FLAGS -s cli-tests
202 - name: Validate cli-suite
203 run: sh validate.sh $FLAGS -s cli-suite
205 - name: Validate solver-benchmarks-tests
206 if: matrix.ghc == env.GHC_FOR_SOLVER_BENCHMARKS
207 run: sh validate.sh $FLAGS -s solver-benchmarks-tests
209 - name: Validate solver-benchmarks-run
210 if: matrix.ghc == env.GHC_FOR_SOLVER_BENCHMARKS
211 run: sh validate.sh $FLAGS -s solver-benchmarks-run
215 name: Validate old ghcs ${{ matrix.extra-ghc }}
216 runs-on: ubuntu-latest
221 extra-ghc: ['8.4.4', '8.2.2', '8.0.2']
222 ## GHC 7.10.3 does not install on ubuntu-22.04 with ghcup.
223 ## Older GHCs are not supported by ghcup in the first place.
228 - uses: actions/checkout@v4
230 - name: Install prerequisites for old GHCs
233 sudo apt-get install libncurses5 libtinfo5
235 - name: Install extra compiler
236 run: ghcup install ghc ${{ matrix.extra-ghc }}
240 run: cat /usr/local/.ghcup/logs/*
242 - name: Install primary compiler
243 uses: haskell-actions/setup@v2
246 ghc-version: ${{ env.GHC_FOR_RELEASE }}
247 cabal-version: latest
252 "ghc-${{ matrix.extra-ghc }}" --version
254 # As we are reusing the cached build dir from the previous step
255 # the generated artifacts are available here,
256 # including the cabal executable and the test suite
257 - uses: actions/cache@v4
260 ${{ steps.setup-haskell.outputs.cabal-store }}
262 key: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-${{ github.sha }}
263 restore-keys: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-
265 - name: Validate build
266 run: sh validate.sh ${{ env.COMMON_FLAGS }} -s build
268 - name: "Validate lib-suite-extras --extra-hc ghc-${{ matrix.extra-ghc }}"
270 EXTRA_GHC: ghc-${{ matrix.extra-ghc }}
271 run: sh validate.sh ${{ env.COMMON_FLAGS }} --lib-only -s lib-suite-extras --extra-hc "${{ env.EXTRA_GHC }}"
274 name: Build statically linked using alpine
275 runs-on: ubuntu-latest
276 container: 'alpine:3.19'
278 - name: Install extra dependencies
281 apk add bash curl sudo jq pkgconfig \
282 zlib-dev zlib-static binutils-gold curl \
283 gcc g++ gmp-dev libc-dev libffi-dev make \
284 musl-dev ncurses-dev perl tar xz
286 - uses: actions/checkout@v4
288 # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions
289 - name: Manually supplied constraints/allow-newer
290 if: github.event_name == 'workflow_dispatch'
292 echo "allow-newer: ${ALLOWNEWER}" >> cabal.validate.project
293 echo "constraints: ${CONSTRAINTS}" >> cabal.validate.project
295 - uses: haskell-actions/setup@v2
298 ghc-version: ${{ env.GHC_FOR_RELEASE }}
299 cabal-version: latest # latest is mandatory for cabal-testsuite, see https://github.com/haskell/cabal/issues/8133
301 # See the following link for a breakdown of the following step
302 # https://github.com/haskell/actions/issues/7#issuecomment-745697160
303 - uses: actions/cache@v4
305 # validate.sh uses a special build dir
307 ${{ steps.setup-haskell.outputs.cabal-store }}
309 key: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-${{ github.sha }}
310 restore-keys: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-
312 - name: Enable statically linked executables
314 echo 'executable-static: true' >> cabal.validate.project
317 run: sh validate.sh $FLAGS -s build
319 - name: Tar cabal head executable
321 CABAL_EXEC=$(cabal list-bin --builddir=dist-newstyle-validate-ghc-${{ env.GHC_FOR_RELEASE }} --project-file=cabal.validate.project cabal-install:exe:cabal)
322 # We have to tar the executable to preserve executable permissions
323 # see https://github.com/actions/upload-artifact/issues/38
324 DIR=$(dirname "$CABAL_EXEC")
325 FILE=$(basename "$CABAL_EXEC")
326 CABAL_EXEC_TAR="cabal-head-${{ runner.os }}-static-x86_64.tar.gz"
327 tar -czvf "$CABAL_EXEC_TAR" -C "$DIR" "$FILE"
328 echo "CABAL_EXEC_TAR=$CABAL_EXEC_TAR" >> "$GITHUB_ENV"
330 - name: Upload cabal-install executable to workflow artifacts
331 uses: actions/upload-artifact@v3
333 name: cabal-${{ runner.os }}-static-x86_64
334 path: ${{ env.CABAL_EXEC_TAR }}
337 # The previous jobs use a released version of cabal to build cabal HEAD itself
338 # This one uses the cabal HEAD generated executable in the previous step
339 # to build itself again, as sanity check
341 name: Dogfooding ${{ matrix.os }} ghc-${{ matrix.ghc }}
342 runs-on: ${{ matrix.os }}
346 os: [ubuntu-latest, macos-13, windows-latest]
347 # We only use one ghc version the used one for the next release (defined at top of the workflow)
348 # We need to build an array dynamically to inject the appropiate env var in a previous job,
349 # see https://docs.github.com/en/actions/learn-github-actions/expressions#fromjson
350 ghc: ${{ fromJSON (needs.validate.outputs.GHC_FOR_RELEASE) }}
353 - name: Work around XDG directories existence (haskell-actions/setup#62)
354 if: runner.os == 'macOS'
356 rm -rf ~/.config/cabal
357 rm -rf ~/.cache/cabal
359 - uses: actions/checkout@v4
361 - uses: haskell-actions/setup@v2
364 ghc-version: ${{ matrix.ghc }}
365 cabal-version: latest # default, we are not using it in this job
367 - name: Download cabal executable from workflow artifacts
368 uses: actions/download-artifact@v3
370 name: cabal-${{ runner.os }}-x86_64
373 - name: Untar the cabal executable
374 run: tar -xzf "./cabal-head/cabal-head-${{ runner.os }}-x86_64.tar.gz" -C cabal-head
376 - name: print-config using cabal HEAD
377 run: sh validate.sh ${{ env.COMMON_FLAGS }} --with-cabal ./cabal-head/cabal -s print-config
379 # We dont use cache to force a build with a fresh store dir and build dir
380 # This way we check cabal can build all its dependencies
381 - name: Build using cabal HEAD
382 run: sh validate.sh ${{ env.COMMON_FLAGS }} --with-cabal ./cabal-head/cabal -s build
385 name: Create a GitHub prerelease with the binary artifacts
386 runs-on: ubuntu-latest
387 if: github.ref == 'refs/heads/master'
389 # IMPORTANT! Any job added to the workflow should be added here too
390 needs: [validate, validate-old-ghcs, build-alpine, dogfooding]
393 - uses: actions/download-artifact@v3
395 name: cabal-Windows-x86_64
397 - uses: actions/download-artifact@v3
399 name: cabal-Linux-x86_64
401 - uses: actions/download-artifact@v3
403 name: cabal-Linux-static-x86_64
405 - uses: actions/download-artifact@v3
407 name: cabal-macOS-x86_64
409 - name: Create GitHub prerelease
410 uses: marvinpinto/action-automatic-releases@v1.2.1
412 repo_token: ${{ secrets.GITHUB_TOKEN }}
413 automatic_release_tag: cabal-head
417 cabal-head-Windows-x86_64.tar.gz
418 cabal-head-Linux-x86_64.tar.gz
419 cabal-head-Linux-static-x86_64.tar.gz
420 cabal-head-macOS-x86_64.tar.gz
422 # We use this job as a summary of the workflow
423 # It will fail if any of the previous jobs does it
424 # This way we can use it exclusively in branch protection rules
425 # and abstract away the concrete jobs of the workflow, including their names
428 name: Validate post job
429 runs-on: ubuntu-latest
430 # IMPORTANT! Any job added to the workflow should be added here too
431 needs: [validate, validate-old-ghcs, build-alpine, dogfooding]
435 echo "jobs info: ${{ toJSON(needs) }}"
436 - if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')