Bump actions/upload-artifact from 2 to 3 (#8599)
[cabal.git] / .github / workflows / validate.yml
blob21d05b6e86b53ff2e9958d7424db6ac8e0bd7913
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 on:
15   push:
16     branches:
17       - master
18   pull_request:
19   release:
20     types:
21       - created
23 env:
24   # We choose a stable ghc version across all os's
25   # which will be used to do the next release
26   GHC_FOR_RELEASE: '9.2.3'
27   # Ideally we should use the version about to be released for hackage tests and benchmarks
28   GHC_FOR_SOLVER_BENCHMARKS: '9.2.3'
29   GHC_FOR_COMPLETE_HACKAGE_TESTS: '9.2.3'
30   COMMON_FLAGS: '-j 2 -v'
32 jobs:
33   validate:
34     name: Validate ${{ matrix.os }} ghc-${{ matrix.ghc }}
35     runs-on: ${{ matrix.os }}
36     outputs:
37       GHC_FOR_RELEASE: ${{ format('["{0}"]', env.GHC_FOR_RELEASE) }}
38     strategy:
39       matrix:
40         os: ["ubuntu-latest", "macos-latest", "windows-latest"]
41         ghc: ["9.4.2", "9.2.3", "9.0.2", "8.10.7", "8.8.4", "8.6.5", "8.4.4"]
42         exclude:
43           # corrupts GHA cache or the fabric of reality itself, see https://github.com/haskell/cabal/issues/8356
44           - os: "windows-latest"
45             ghc: "8.10.7"
46           # lot of segfaults caused by ghc bugs
47           - os: "windows-latest"
48             ghc: "8.8.4"
49           # it also throws segfaults randomly
50           - os: "windows-latest"
51             ghc: "8.4.4"
52           # 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.)"
53           - os: "windows-latest"
54             ghc: "8.6.5"
56     steps:
58       - uses: actions/checkout@v2
60       - uses: haskell/actions/setup@v2
61         id: setup-haskell
62         with:
63           ghc-version: ${{ matrix.ghc }}
64           cabal-version: '3.8.1.0'
66       #  See the following link for a breakdown of the following step
67       #  https://github.com/haskell/actions/issues/7#issuecomment-745697160
68       - uses: actions/cache@v2
69         with:
70           # validate.sh uses a special build dir
71           path: |
72             ${{ steps.setup-haskell.outputs.cabal-store }}
73             dist-*
74           key: ${{ runner.os }}-${{ matrix.ghc }}-20220419-${{ github.sha }}
75           restore-keys: ${{ runner.os }}-${{ matrix.ghc }}-20220419-
77       - name: Work around git problem https://bugs.launchpad.net/ubuntu/+source/git/+bug/1993586 (cabal PR #8546)
78         run: |
79           git config --global protocol.file.allow always
81       # The '+exe' constraint below is important, otherwise cabal-install
82       # might decide to build the library but not the executable which is
83       # what we need.
84       - name: Install cabal-plan
85         run: |
86           cd $(mktemp -d)
87           cabal install cabal-plan --constraint='cabal-plan +exe'
88           echo "$HOME/.cabal/bin" >> $GITHUB_PATH
90       # The tool is not essential to the rest of the test suite. If
91       # hackage-repo-tool is not present, any test that requires it will
92       # be skipped.
93       # We want to keep this in the loop but we don't want to fail if
94       # hackage-repo-tool breaks or fails to support a newer GHC version.
95       - name: Install hackage-repo-tool
96         continue-on-error: true
97         run: |
98           cd $(mktemp -d)
99           cabal install hackage-repo-tool
101       # Needed by cabal-testsuite/PackageTests/Configure/setup.test.hs
102       - name: Install Autotools
103         if: runner.os == 'macOS'
104         run: |
105           brew install automake
107       - name: Set validate inputs
108         run: |
109           FLAGS="${{ env.COMMON_FLAGS }}"
110           if [[ "${{ matrix.cli }}" == "false" ]]; then
111             FLAGS="$FLAGS --lib-only"
112           fi
113           if [[ ${{ matrix.ghc }} == ${{ env.GHC_FOR_SOLVER_BENCHMARKS }} ]]; then
114             FLAGS="$FLAGS --solver-benchmarks"
115           fi
116           if [[ ${{ matrix.ghc }} == ${{ env.GHC_FOR_COMPLETE_HACKAGE_TESTS }} ]]; then
117             FLAGS="$FLAGS --complete-hackage-tests"
118           fi
119           echo "FLAGS=$FLAGS" >> $GITHUB_ENV
121       - name: Validate print-config
122         run: sh validate.sh $FLAGS -s print-config
124       - name: Validate print-tool-versions
125         run: sh validate.sh $FLAGS -s print-tool-versions
127       - name: Validate build
128         run: sh validate.sh $FLAGS -s build
130       - name: Tar cabal head executable
131         if: matrix.cli != 'false' && matrix.ghc == env.GHC_FOR_RELEASE
132         run: |
133           CABAL_EXEC=$(cabal-plan list-bin --builddir=dist-newstyle-validate-ghc-${{ matrix.ghc }} cabal-install:exe:cabal)
134           # We have to tar the executable to preserve executable permissions
135           # see https://github.com/actions/upload-artifact/issues/38
136           if [[ ${{ runner.os }} == 'Windows' ]]; then
137             # `cabal-plan` gives us a windows path but tar needs the posix one
138             CABAL_EXEC=$(cygpath $CABAL_EXEC)
139           fi
140           if [[ "${{ runner.os }}" == "macOS" ]]; then
141              # Workaround to avoid bsdtar corrupts the executable
142              # so executing it after untar throws `cannot execute binary file`
143              # see https://github.com/actions/virtual-environments/issues/2619#issuecomment-788397841
144              sudo /usr/sbin/purge
145           fi
146           tar -cvf cabal-head.tar -C $(dirname "$CABAL_EXEC") $(basename "$CABAL_EXEC")
147           echo "CABAL_EXEC_TAR=cabal-head.tar" >> $GITHUB_ENV
149       # We upload the cabal executable built with the ghc used in the release for:
150       # - Reuse it in the dogfooding job (although we could use the cached build dir)
151       # - Make it available in the workflow to make easier testing it locally
152       - name: Upload cabal-install executable to workflow artifacts
153         if: matrix.cli != 'false' && matrix.ghc == env.GHC_FOR_RELEASE
154         uses: actions/upload-artifact@v3
155         with:
156           name: cabal-${{ runner.os }}-${{ matrix.ghc }}
157           path: ${{ env.CABAL_EXEC_TAR }}
159       - name: Validate lib-tests
160         env:
161           # `rawSystemStdInOut reports text decoding errors`
162           # test does not find ghc without the full path in windows
163           GHCPATH: ${{ steps.setup-haskell.outputs.ghc-exe }}
164         run: sh validate.sh $FLAGS -s lib-tests
166       - name: Validate lib-suite
167         run: sh validate.sh $FLAGS -s lib-suite
169       - name: Validate cli-tests
170         if: matrix.cli != 'false'
171         run: sh validate.sh $FLAGS -s cli-tests
173       - name: Validate cli-suite
174         if: matrix.cli != 'false'
175         run: sh validate.sh $FLAGS -s cli-suite
177   validate-old-ghcs:
178     name: Validate old ghcs ${{ matrix.extra-ghc }}
179     runs-on: ubuntu-latest
180     needs: validate
181     # This job needs an older ubuntu (16.04) cause
182     # the required old ghcs using the `-dyn` flavour
183     # are not installable from ppa/hvr in newer ones
184     # see https://github.com/haskell/cabal/issues/8011
185     container:
186       image: phadej/ghc:8.8.4-xenial
188     strategy:
189       matrix:
190         # Newer ghc versions than 8.8.4 have to be installed with ghcup cause
191         # they are not available in ppa/hvr. The ghcup installation
192         # needs `sudo` which is not available in the xenial container
193         ghc: ["8.8.4"]
194         extra-ghc: ["7.10.3", "7.8.4", "7.6.3", "7.4.2", "7.2.2", "7.0.4"]
196     steps:
198       # We can't use actions/checkout with the xenial docker container
199       # cause it does not work with the git version included in it, see:
200       # https://github.com/actions/checkout/issues/170
201       # https://github.com/actions/checkout/issues/295
202       # - uses: actions/checkout@v2
203       - name: Checkout
204         run: |
205           echo $GITHUB_REF $GITHUB_SHA
206           git clone --depth 1 https://github.com/$GITHUB_REPOSITORY.git .
207           git fetch origin $GITHUB_SHA:temporary-ci-branch
208           git checkout $GITHUB_SHA || (git fetch && git checkout $GITHUB_SHA)
210       - name: Install extra compiler
211         run: |
212           apt-get update
213           apt-get install -y ghc-${{ matrix.extra-ghc }}-dyn
215       - uses: haskell/actions/setup@v2
216         id: setup-haskell
217         with:
218           ghc-version: ${{ matrix.ghc }}
219           cabal-version: '3.8.1.0'
221       # As we are reusing the cached build dir from the previous step
222       # the generated artifacts are available here,
223       # including the cabal executable and the test suite
224       - uses: actions/cache@v2
225         with:
226           path: |
227             ${{ steps.setup-haskell.outputs.cabal-store }}
228             dist-*
229           key: ${{ runner.os }}-${{ matrix.ghc }}-20220419-${{ github.sha }}
230           restore-keys: ${{ runner.os }}-${{ matrix.ghc }}-20220419-
232       - name: Install cabal-plan
233         run: |
234           cd $(mktemp -d)
235           cabal install cabal-plan --constraint='cabal-plan +exe'
236           echo "$HOME/.cabal/bin" >> $GITHUB_PATH
238       - name: Validate build
239         run: sh validate.sh ${{ env.COMMON_FLAGS }} -s build
241       - name: "Validate lib-suite-extras --extra-hc ghc-${{ matrix.extra-ghc }}"
242         env:
243           EXTRA_GHC: "/opt/ghc/${{ matrix.extra-ghc }}/bin/ghc-${{ matrix.extra-ghc }}"
244         run: sh validate.sh ${{ env.COMMON_FLAGS }} --lib-only -s lib-suite-extras --extra-hc ${{ env.EXTRA_GHC }}
246   # The previous jobs use a released version of cabal to build cabal HEAD itself
247   # This one uses the cabal HEAD generated executable in the previous step
248   # to build itself again, as sanity check
249   dogfooding:
250     name: Dogfooding ${{ matrix.os }} ghc-${{ matrix.ghc }}
251     runs-on: ${{ matrix.os }}
252     needs: validate
253     strategy:
254       matrix:
255         os: ["ubuntu-latest", "macos-latest", "windows-latest"]
256         # We only use one ghc version the used one for the next release (defined at top of the workflow)
257         # We need to build an array dynamically to inject the appropiate env var in a previous job,
258         # see https://docs.github.com/en/actions/learn-github-actions/expressions#fromjson
259         ghc: ${{ fromJSON (needs.validate.outputs.GHC_FOR_RELEASE) }}
261     steps:
262       - uses: actions/checkout@v2
264       - uses: haskell/actions/setup@v2
265         id: setup-haskell
266         with:
267           ghc-version: ${{ matrix.ghc }}
268           cabal-version: latest # default, we are not using it in this job
270       - name: Install cabal-plan
271         run: |
272           cd $(mktemp -d)
273           cabal install cabal-plan --constraint='cabal-plan +exe'
274           echo "$HOME/.cabal/bin" >> $GITHUB_PATH
276       - name: Download cabal executable from workflow artifacts
277         uses: actions/download-artifact@v2
278         with:
279           name: cabal-${{ runner.os }}-${{ matrix.ghc }}
280           path: cabal-head
282       - name: Untar the cabal executable
283         run: tar -xf ./cabal-head/cabal-head.tar -C ./cabal-head
285       - name: print-config using cabal HEAD
286         run: sh validate.sh ${{ env.COMMON_FLAGS }} --with-cabal ./cabal-head/cabal -s print-config
288       # We dont use cache to force a build with a fresh store dir and build dir
289       # This way we check cabal can build all its dependencies
290       - name: Build using cabal HEAD
291         run: sh validate.sh ${{ env.COMMON_FLAGS }} --with-cabal ./cabal-head/cabal -s build
293   # We use this job as a summary of the workflow
294   # It will fail if any of the previous jobs does it
295   # This way we can use it exclusively in branch protection rules
296   # and abstract away the concrete jobs of the workflow, including their names
297   validate-post-job:
298     if: always()
299     name: Validate post job
300     runs-on: ubuntu-latest
301     # IMPORTANT! Any job added to the workflow should be added here too
302     needs: [validate, validate-old-ghcs, dogfooding]
304     steps:
305       - run: |
306           echo "jobs info: ${{ toJSON(needs) }}"
307       - if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
308         run: exit 1