Migrate to haskell-actions/setup
[cabal.git] / .github / workflows / validate.yml
blob4dbc94def3291f4f6a9f7697e768915e4a8b98a5
1 name: Validate
3 # We use bash as default even in windows
4 # to try keep the workflow as uniform as possible
5 defaults:
6   run:
7     shell: bash
9 # See: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#concurrency.
10 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.
17 on:
18   push:
19     paths-ignore:
20       - 'doc/**'
21       - '**/README.md'
22       - 'CONTRIBUTING.md'
23     branches:
24       - master
25   pull_request:
26     paths-ignore:
27       - 'doc/**'
28       - '**/README.md'
29       - 'CONTRIBUTING.md'
30   release:
31     types:
32       - created
34 env:
35   # We choose a stable ghc version across all os's
36   # which will be used to do the next release
37   GHC_FOR_RELEASE: '9.2.8'
38   # Ideally we should use the version about to be released for hackage tests and benchmarks
39   GHC_FOR_SOLVER_BENCHMARKS: '9.2.8'
40   GHC_FOR_COMPLETE_HACKAGE_TESTS: '9.2.8'
41   COMMON_FLAGS: '-j 2 -v'
43 jobs:
44   validate:
45     name: Validate ${{ matrix.os }} ghc-${{ matrix.ghc }}
46     runs-on: ${{ matrix.os }}
47     outputs:
48       GHC_FOR_RELEASE: ${{ format('["{0}"]', env.GHC_FOR_RELEASE) }}
49     strategy:
50       matrix:
51         os: ["ubuntu-latest", "macos-latest", "windows-latest"]
52         ghc: ["9.6.3", "9.4.7", "9.2.8", "9.0.2", "8.10.7", "8.8.4", "8.6.5", "8.4.4"]
53         exclude:
54           # corrupts GHA cache or the fabric of reality itself, see https://github.com/haskell/cabal/issues/8356
55           - os: "windows-latest"
56             ghc: "8.10.7"
57           # lot of segfaults caused by ghc bugs
58           - os: "windows-latest"
59             ghc: "8.8.4"
60           # it also throws segfaults randomly
61           - os: "windows-latest"
62             ghc: "8.4.4"
63           # 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.)"
64           - os: "windows-latest"
65             ghc: "8.6.5"
67     steps:
69       - uses: actions/checkout@v4
71       #  See the following link for a breakdown of the following step
72       #  https://github.com/haskell/actions/issues/7#issuecomment-745697160
73       - uses: actions/cache@v3
74         with:
75           # validate.sh uses a special build dir
76           path: |
77             ${{ steps.setup-haskell.outputs.cabal-store }}
78             dist-*
79           key: ${{ runner.os }}-${{ matrix.ghc }}-${{ github.sha }}
80           restore-keys: ${{ runner.os }}-${{ matrix.ghc }}-
82       - uses: haskell-actions/setup@v2
83         id: setup-haskell
84         with:
85           ghc-version: ${{ matrix.ghc }}
86           cabal-version: '3.10.1.0'
88       - name: Work around git problem https://bugs.launchpad.net/ubuntu/+source/git/+bug/1993586 (cabal PR #8546)
89         run: |
90           git config --global protocol.file.allow always
92       # The tool is not essential to the rest of the test suite. If
93       # hackage-repo-tool is not present, any test that requires it will
94       # be skipped.
95       # We want to keep this in the loop but we don't want to fail if
96       # hackage-repo-tool breaks or fails to support a newer GHC version.
97       - name: Install hackage-repo-tool
98         continue-on-error: true
99         run: |
100           cd $(mktemp -d)
101           cabal install hackage-repo-tool
103       # Needed by cabal-testsuite/PackageTests/Configure/setup.test.hs
104       - name: Install Autotools
105         if: runner.os == 'macOS'
106         run: |
107           brew install automake
109       - name: Set validate inputs
110         run: |
111           FLAGS="${{ env.COMMON_FLAGS }}"
112           if [[ ${{ matrix.ghc }} == ${{ env.GHC_FOR_SOLVER_BENCHMARKS }} ]]; then
113             FLAGS="$FLAGS --solver-benchmarks"
114           fi
115           if [[ ${{ matrix.ghc }} == ${{ env.GHC_FOR_COMPLETE_HACKAGE_TESTS }} ]]; then
116             FLAGS="$FLAGS --complete-hackage-tests"
117           fi
118           echo "FLAGS=$FLAGS" >> $GITHUB_ENV
120       - name: Allow newer dependencies when built with latest GHC
121         if: ${{ matrix.ghc }} == '9.6.3'
122         run: |
123           echo "allow-newer: rere:base, rere:transformers" >> cabal.project.validate
125       - name: Validate print-config
126         run: sh validate.sh $FLAGS -s print-config
128       - name: Validate print-tool-versions
129         run: sh validate.sh $FLAGS -s print-tool-versions
131       - name: Validate build
132         run: sh validate.sh $FLAGS -s build
134       - name: Tar cabal head executable
135         if: matrix.ghc == env.GHC_FOR_RELEASE
136         run: |
137           CABAL_EXEC=$(cabal list-bin --builddir=dist-newstyle-validate-ghc-${{ matrix.ghc }} --project-file=cabal.project.validate cabal-install:exe:cabal)
138           # We have to tar the executable to preserve executable permissions
139           # see https://github.com/actions/upload-artifact/issues/38
140           if [[ ${{ runner.os }} == 'Windows' ]]; then
141             # `cabal list-bin` gives us a windows path but tar needs the posix one
142             CABAL_EXEC=$(cygpath $CABAL_EXEC)
143           fi
144           if [[ "${{ runner.os }}" == "macOS" ]]; then
145              # Workaround to avoid bsdtar corrupts the executable
146              # so executing it after untar throws `cannot execute binary file`
147              # see https://github.com/actions/virtual-environments/issues/2619#issuecomment-788397841
148              sudo /usr/sbin/purge
149           fi
150           export CABAL_EXEC_TAR="cabal-head-${{ runner.os }}-x86_64.tar.gz"
151           tar -czvf $CABAL_EXEC_TAR -C $(dirname "$CABAL_EXEC") $(basename "$CABAL_EXEC")
152           echo "CABAL_EXEC_TAR=$CABAL_EXEC_TAR" >> $GITHUB_ENV
154       # We upload the cabal executable built with the ghc used in the release for:
155       # - Reuse it in the dogfooding job (although we could use the cached build dir)
156       # - Make it available in the workflow to make easier testing it locally
157       - name: Upload cabal-install executable to workflow artifacts
158         if: matrix.ghc == env.GHC_FOR_RELEASE
159         uses: actions/upload-artifact@v3
160         with:
161           name: cabal-${{ runner.os }}-x86_64
162           path: ${{ env.CABAL_EXEC_TAR }}
164       - name: Validate lib-tests
165         env:
166           # `rawSystemStdInOut reports text decoding errors`
167           # test does not find ghc without the full path in windows
168           GHCPATH: ${{ steps.setup-haskell.outputs.ghc-exe }}
169         run: sh validate.sh $FLAGS -s lib-tests
171       - name: Validate lib-suite
172         # Have to disable *-suite validation:
173         # - the Windows@9.6.1 problem is tracked at https://github.com/haskell/cabal/issues/8858
174         # - but curently can't run it with GHC 9.6, tracking: https://github.com/haskell/cabal/issues/8883
175         run: sh validate.sh $FLAGS -s lib-suite
177       - name: Validate cli-tests
178         run: sh validate.sh $FLAGS -s cli-tests
180       - name: Validate cli-suite
181         # Have to disable *-suite validation, see above the comment for lib-suite
182         run: sh validate.sh $FLAGS -s cli-suite
184   validate-old-ghcs:
185     name: Validate old ghcs ${{ matrix.extra-ghc }}
186     runs-on: ubuntu-latest
187     needs: validate
188     # This job needs an older ubuntu (16.04) cause
189     # the required old ghcs using the `-dyn` flavour
190     # are not installable from ppa/hvr in newer ones
191     # see https://github.com/haskell/cabal/issues/8011
192     container:
193       image: phadej/ghc:8.8.4-xenial
195     strategy:
196       matrix:
197         # Newer ghc versions than 8.8.4 have to be installed with ghcup cause
198         # they are not available in ppa/hvr. The ghcup installation
199         # needs `sudo` which is not available in the xenial container
200         ghc: ["8.8.4"]
201         extra-ghc: ["7.10.3", "7.8.4", "7.6.3", "7.4.2", "7.2.2", "7.0.4"]
203     steps:
205       # We can't use actions/checkout with the xenial docker container
206       # cause it does not work with the git version included in it, see:
207       # https://github.com/actions/checkout/issues/170
208       # https://github.com/actions/checkout/issues/295
209       # - uses: actions/checkout@v4
210       - name: Checkout
211         run: |
212           echo $GITHUB_REF $GITHUB_SHA
213           git clone --depth 1 https://github.com/$GITHUB_REPOSITORY.git .
214           git fetch origin $GITHUB_SHA:temporary-ci-branch
215           git checkout $GITHUB_SHA || (git fetch && git checkout $GITHUB_SHA)
217       - name: Install extra compiler
218         run: |
219           apt-get update
220           apt-get install -y ghc-${{ matrix.extra-ghc }}-dyn
222       - uses: haskell-actions/setup@v2
223         id: setup-haskell
224         with:
225           ghc-version: ${{ matrix.ghc }}
226           # Make sure this bindist works in this old environment
227           cabal-version: 3.10.1.0
229       # As we are reusing the cached build dir from the previous step
230       # the generated artifacts are available here,
231       # including the cabal executable and the test suite
232       - uses: actions/cache@v3
233         with:
234           path: |
235             ${{ steps.setup-haskell.outputs.cabal-store }}
236             dist-*
237           key: ${{ runner.os }}-${{ matrix.ghc }}-${{ github.sha }}
238           restore-keys: ${{ runner.os }}-${{ matrix.ghc }}-
240       - name: Validate build
241         run: sh validate.sh ${{ env.COMMON_FLAGS }} -s build
243       - name: "Validate lib-suite-extras --extra-hc ghc-${{ matrix.extra-ghc }}"
244         env:
245           EXTRA_GHC: "/opt/ghc/${{ matrix.extra-ghc }}/bin/ghc-${{ matrix.extra-ghc }}"
246         run: sh validate.sh ${{ env.COMMON_FLAGS }} --lib-only -s lib-suite-extras --extra-hc ${{ env.EXTRA_GHC }}
248   # The previous jobs use a released version of cabal to build cabal HEAD itself
249   # This one uses the cabal HEAD generated executable in the previous step
250   # to build itself again, as sanity check
251   dogfooding:
252     name: Dogfooding ${{ matrix.os }} ghc-${{ matrix.ghc }}
253     runs-on: ${{ matrix.os }}
254     needs: validate
255     strategy:
256       matrix:
257         os: ["ubuntu-latest", "macos-latest", "windows-latest"]
258         # We only use one ghc version the used one for the next release (defined at top of the workflow)
259         # We need to build an array dynamically to inject the appropiate env var in a previous job,
260         # see https://docs.github.com/en/actions/learn-github-actions/expressions#fromjson
261         ghc: ${{ fromJSON (needs.validate.outputs.GHC_FOR_RELEASE) }}
263     steps:
264       - uses: actions/checkout@v4
266       # See https://github.com/haskell/cabal/pull/8739
267       - name: Sudo chmod to permit ghcup to update its cache
268         run: |
269           if [[ "${{ runner.os }}" == "Linux" ]]; then
270             sudo ls -lah /usr/local/.ghcup/cache
271             sudo mkdir -p /usr/local/.ghcup/cache
272             sudo ls -lah /usr/local/.ghcup/cache
273             sudo chown -R $USER /usr/local/.ghcup
274             sudo chmod -R 777 /usr/local/.ghcup
275           fi
276       - uses: haskell-actions/setup@v2
277         id: setup-haskell
278         with:
279           ghc-version: ${{ matrix.ghc }}
280           cabal-version: latest # default, we are not using it in this job
282       - name: Download cabal executable from workflow artifacts
283         uses: actions/download-artifact@v3
284         with:
285           name: cabal-${{ runner.os }}-x86_64
286           path: cabal-head
288       - name: Untar the cabal executable
289         run: tar -xzf ./cabal-head/cabal-head-${{ runner.os }}-x86_64.tar.gz -C cabal-head
291       - name: print-config using cabal HEAD
292         run: sh validate.sh ${{ env.COMMON_FLAGS }} --with-cabal ./cabal-head/cabal -s print-config
294       # We dont use cache to force a build with a fresh store dir and build dir
295       # This way we check cabal can build all its dependencies
296       - name: Build using cabal HEAD
297         run: sh validate.sh ${{ env.COMMON_FLAGS }} --with-cabal ./cabal-head/cabal -s build
299   prerelease-head:
300     name: Create a GitHub prerelease with the binary artifacts
301     runs-on: ubuntu-latest
302     if: github.ref == 'refs/heads/master'
304     # IMPORTANT! Any job added to the workflow should be added here too
305     needs: [validate, validate-old-ghcs, dogfooding]
307     steps:
308     - uses: actions/download-artifact@v3
309       with:
310         name: cabal-Windows-x86_64
312     - uses: actions/download-artifact@v3
313       with:
314         name: cabal-Linux-x86_64
316     - uses: actions/download-artifact@v3
317       with:
318         name: cabal-macOS-x86_64
320     - name: Create GitHub prerelease
321       uses: "marvinpinto/action-automatic-releases@v1.2.1"
322       with:
323         repo_token: "${{ secrets.GITHUB_TOKEN }}"
324         automatic_release_tag: "cabal-head"
325         prerelease: true
326         title: "cabal-head"
327         files: |
328           cabal-head-Windows-x86_64.tar.gz
329           cabal-head-Linux-x86_64.tar.gz
330           cabal-head-macOS-x86_64.tar.gz
332   # We use this job as a summary of the workflow
333   # It will fail if any of the previous jobs does it
334   # This way we can use it exclusively in branch protection rules
335   # and abstract away the concrete jobs of the workflow, including their names
336   validate-post-job:
337     if: always()
338     name: Validate post job
339     runs-on: ubuntu-latest
340     # IMPORTANT! Any job added to the workflow should be added here too
341     needs: [validate, validate-old-ghcs, dogfooding]
343     steps:
344       - run: |
345           echo "jobs info: ${{ toJSON(needs) }}"
346       - if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
347         run: exit 1