From 952e08be7577d9f1dfb880fdb3ce3261a6764435 Mon Sep 17 00:00:00 2001 From: Artem Pelenitsyn Date: Sun, 24 Dec 2023 12:23:31 -0500 Subject: [PATCH] Add validate-revision workflow It can be started manually to check that certain version bumps build fine. It will ask to input an allow-newer line and a constraint line, which it will add to the cabal.project file. For example: the "filepath" allow-newer line and "filepath == 1.5" constraints line will make sure that the build plan will have `filepath` at version 1.5. --- .github/workflows/validate-revision.yml | 344 ++++++++++++++++++++++++ 1 file changed, 344 insertions(+) create mode 100644 .github/workflows/validate-revision.yml diff --git a/.github/workflows/validate-revision.yml b/.github/workflows/validate-revision.yml new file mode 100644 index 00000000000..eec790a59ed --- /dev/null +++ b/.github/workflows/validate-revision.yml @@ -0,0 +1,344 @@ +name: Validate Revision + +# It's almost exact copy of validate.yml and has to be maintainted in concert with it. +# The difference is in the `on` attribute and the step where we do >> cabal.project.validate + +# We use bash as default even in windows +# to try keep the workflow as uniform as possible +defaults: + run: + shell: bash + +# See: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#concurrency. +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +# Note: This workflow file contains the required job "Validate post job". We are using path filtering +# here to ignore PRs which only change documentation. This can cause a problem, see the workflow file +# "validate.skip.yml" for a description of the problem and the solution provided in that file. +on: + workflow_dispatch: + inputs: + allow-newer: + description: allow-newer line + required: true + type: string + constraints: + description: constraints line + required: true + type: string +env: + # We choose a stable ghc version across all os's + # which will be used to do the next release + GHC_FOR_RELEASE: '9.2.8' + # Ideally we should use the version about to be released for hackage tests and benchmarks + GHC_FOR_SOLVER_BENCHMARKS: '9.2.8' + GHC_FOR_COMPLETE_HACKAGE_TESTS: '9.2.8' + COMMON_FLAGS: '-j 2 -v' + ALLOWNEWER: ${{ github.event.inputs.allow-newer }} + CONSTRAINTS: ${{ github.event.inputs.constraints }} + +jobs: + validate: + name: Validate ${{ matrix.os }} ghc-${{ matrix.ghc }} + runs-on: ${{ matrix.os }} + outputs: + GHC_FOR_RELEASE: ${{ format('["{0}"]', env.GHC_FOR_RELEASE) }} + strategy: + matrix: + os: ["ubuntu-latest", "macos-latest", "windows-latest"] + 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", "8.4.4"] + exclude: + # corrupts GHA cache or the fabric of reality itself, see https://github.com/haskell/cabal/issues/8356 + - os: "windows-latest" + ghc: "8.10.7" + # lot of segfaults caused by ghc bugs + - os: "windows-latest" + ghc: "8.8.4" + # it also throws segfaults randomly + - os: "windows-latest" + ghc: "8.4.4" + # 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.)" + - os: "windows-latest" + ghc: "8.6.5" + + steps: + + - uses: actions/checkout@v4 + - run: | + echo 'allow-newer:' ${ALLOWNEWER} >> cabal.project.validate + echo 'constraints:' ${CONSTRAINTS} >> cabal.project.validate + + # See the following link for a breakdown of the following step + # https://github.com/haskell/actions/issues/7#issuecomment-745697160 + - uses: actions/cache@v3 + with: + # validate.sh uses a special build dir + path: | + ${{ steps.setup-haskell.outputs.cabal-store }} + dist-* + key: ${{ runner.os }}-${{ matrix.ghc }}-${{ github.sha }} + restore-keys: ${{ runner.os }}-${{ matrix.ghc }}- + + - uses: haskell-actions/setup@v2 + id: setup-haskell + with: + ghc-version: ${{ matrix.ghc }} + cabal-version: latest # latest is mandatory for cabal-testsuite, see https://github.com/haskell/cabal/issues/8133 + + - name: Work around git problem https://bugs.launchpad.net/ubuntu/+source/git/+bug/1993586 (cabal PR #8546) + run: | + git config --global protocol.file.allow always + + # The tool is not essential to the rest of the test suite. If + # hackage-repo-tool is not present, any test that requires it will + # be skipped. + # We want to keep this in the loop but we don't want to fail if + # hackage-repo-tool breaks or fails to support a newer GHC version. + - name: Install hackage-repo-tool + continue-on-error: true + run: | + cd $(mktemp -d) + cabal install hackage-repo-tool + + # Needed by cabal-testsuite/PackageTests/Configure/setup.test.hs + - name: Install Autotools + if: runner.os == 'macOS' + run: | + brew install automake + + - name: Set validate inputs + run: | + FLAGS="${{ env.COMMON_FLAGS }}" + if [[ ${{ matrix.ghc }} == ${{ env.GHC_FOR_SOLVER_BENCHMARKS }} ]]; then + FLAGS="$FLAGS --solver-benchmarks" + fi + if [[ ${{ matrix.ghc }} == ${{ env.GHC_FOR_COMPLETE_HACKAGE_TESTS }} ]]; then + FLAGS="$FLAGS --complete-hackage-tests" + fi + echo "FLAGS=$FLAGS" >> $GITHUB_ENV + + - name: Validate print-config + run: sh validate.sh $FLAGS -s print-config + + - name: Validate print-tool-versions + run: sh validate.sh $FLAGS -s print-tool-versions + + - name: Validate build + run: sh validate.sh $FLAGS -s build + + - name: Tar cabal head executable + if: matrix.ghc == env.GHC_FOR_RELEASE + run: | + CABAL_EXEC=$(cabal list-bin --builddir=dist-newstyle-validate-ghc-${{ matrix.ghc }} --project-file=cabal.project.validate cabal-install:exe:cabal) + # We have to tar the executable to preserve executable permissions + # see https://github.com/actions/upload-artifact/issues/38 + if [[ ${{ runner.os }} == 'Windows' ]]; then + # `cabal list-bin` gives us a windows path but tar needs the posix one + CABAL_EXEC=$(cygpath $CABAL_EXEC) + fi + if [[ "${{ runner.os }}" == "macOS" ]]; then + # Workaround to avoid bsdtar corrupts the executable + # so executing it after untar throws `cannot execute binary file` + # see https://github.com/actions/virtual-environments/issues/2619#issuecomment-788397841 + sudo /usr/sbin/purge + fi + export CABAL_EXEC_TAR="cabal-head-${{ runner.os }}-x86_64.tar.gz" + tar -czvf $CABAL_EXEC_TAR -C $(dirname "$CABAL_EXEC") $(basename "$CABAL_EXEC") + echo "CABAL_EXEC_TAR=$CABAL_EXEC_TAR" >> $GITHUB_ENV + + # We upload the cabal executable built with the ghc used in the release for: + # - Reuse it in the dogfooding job (although we could use the cached build dir) + # - Make it available in the workflow to make easier testing it locally + - name: Upload cabal-install executable to workflow artifacts + if: matrix.ghc == env.GHC_FOR_RELEASE + uses: actions/upload-artifact@v3 + with: + name: cabal-${{ runner.os }}-x86_64 + path: ${{ env.CABAL_EXEC_TAR }} + + - name: Validate lib-tests + env: + # `rawSystemStdInOut reports text decoding errors` + # test does not find ghc without the full path in windows + GHCPATH: ${{ steps.setup-haskell.outputs.ghc-exe }} + run: sh validate.sh $FLAGS -s lib-tests + + - name: Validate lib-suite + # Have to disable *-suite validation: + # - the Windows@9.6.1 problem is tracked at https://github.com/haskell/cabal/issues/8858 + # - but curently can't run it with GHC 9.6, tracking: https://github.com/haskell/cabal/issues/8883 + run: sh validate.sh $FLAGS -s lib-suite + + - name: Validate cli-tests + run: sh validate.sh $FLAGS -s cli-tests + + - name: Validate cli-suite + # Have to disable *-suite validation, see above the comment for lib-suite + run: sh validate.sh $FLAGS -s cli-suite + + validate-old-ghcs: + name: Validate old ghcs ${{ matrix.extra-ghc }} + runs-on: ubuntu-latest + needs: validate + # This job needs an older ubuntu (16.04) cause + # the required old ghcs using the `-dyn` flavour + # are not installable from ppa/hvr in newer ones + # see https://github.com/haskell/cabal/issues/8011 + container: + image: phadej/ghc:8.8.4-xenial + + strategy: + matrix: + # Newer ghc versions than 8.8.4 have to be installed with ghcup cause + # they are not available in ppa/hvr. The ghcup installation + # needs `sudo` which is not available in the xenial container + ghc: ["8.8.4"] + extra-ghc: ["7.10.3", "7.8.4", "7.6.3", "7.4.2", "7.2.2", "7.0.4"] + + steps: + + # We can't use actions/checkout with the xenial docker container + # cause it does not work with the git version included in it, see: + # https://github.com/actions/checkout/issues/170 + # https://github.com/actions/checkout/issues/295 + # - uses: actions/checkout@v4 + - name: Checkout + run: | + echo $GITHUB_REF $GITHUB_SHA + git clone --depth 1 https://github.com/$GITHUB_REPOSITORY.git . + git fetch origin $GITHUB_SHA:temporary-ci-branch + git checkout $GITHUB_SHA || (git fetch && git checkout $GITHUB_SHA) + + - name: Install extra compiler + run: | + apt-get update + apt-get install -y ghc-${{ matrix.extra-ghc }}-dyn + + - uses: haskell-actions/setup@v2 + id: setup-haskell + with: + ghc-version: ${{ matrix.ghc }} + # Make sure this bindist works in this old environment + cabal-version: 3.10.1.0 + + # As we are reusing the cached build dir from the previous step + # the generated artifacts are available here, + # including the cabal executable and the test suite + - uses: actions/cache@v3 + with: + path: | + ${{ steps.setup-haskell.outputs.cabal-store }} + dist-* + key: ${{ runner.os }}-${{ matrix.ghc }}-${{ github.sha }} + restore-keys: ${{ runner.os }}-${{ matrix.ghc }}- + + - name: Validate build + run: sh validate.sh ${{ env.COMMON_FLAGS }} -s build + + - name: "Validate lib-suite-extras --extra-hc ghc-${{ matrix.extra-ghc }}" + env: + EXTRA_GHC: "/opt/ghc/${{ matrix.extra-ghc }}/bin/ghc-${{ matrix.extra-ghc }}" + run: sh validate.sh ${{ env.COMMON_FLAGS }} --lib-only -s lib-suite-extras --extra-hc ${{ env.EXTRA_GHC }} + + # The previous jobs use a released version of cabal to build cabal HEAD itself + # This one uses the cabal HEAD generated executable in the previous step + # to build itself again, as sanity check + dogfooding: + name: Dogfooding ${{ matrix.os }} ghc-${{ matrix.ghc }} + runs-on: ${{ matrix.os }} + needs: validate + strategy: + matrix: + os: ["ubuntu-latest", "macos-latest", "windows-latest"] + # We only use one ghc version the used one for the next release (defined at top of the workflow) + # We need to build an array dynamically to inject the appropiate env var in a previous job, + # see https://docs.github.com/en/actions/learn-github-actions/expressions#fromjson + ghc: ${{ fromJSON (needs.validate.outputs.GHC_FOR_RELEASE) }} + + steps: + - uses: actions/checkout@v4 + + # See https://github.com/haskell/cabal/pull/8739 + - name: Sudo chmod to permit ghcup to update its cache + run: | + if [[ "${{ runner.os }}" == "Linux" ]]; then + sudo ls -lah /usr/local/.ghcup/cache + sudo mkdir -p /usr/local/.ghcup/cache + sudo ls -lah /usr/local/.ghcup/cache + sudo chown -R $USER /usr/local/.ghcup + sudo chmod -R 777 /usr/local/.ghcup + fi + - uses: haskell-actions/setup@v2 + id: setup-haskell + with: + ghc-version: ${{ matrix.ghc }} + cabal-version: latest # default, we are not using it in this job + + - name: Download cabal executable from workflow artifacts + uses: actions/download-artifact@v3 + with: + name: cabal-${{ runner.os }}-x86_64 + path: cabal-head + + - name: Untar the cabal executable + run: tar -xzf ./cabal-head/cabal-head-${{ runner.os }}-x86_64.tar.gz -C cabal-head + + - name: print-config using cabal HEAD + run: sh validate.sh ${{ env.COMMON_FLAGS }} --with-cabal ./cabal-head/cabal -s print-config + + # We dont use cache to force a build with a fresh store dir and build dir + # This way we check cabal can build all its dependencies + - name: Build using cabal HEAD + run: sh validate.sh ${{ env.COMMON_FLAGS }} --with-cabal ./cabal-head/cabal -s build + + prerelease-head: + name: Create a GitHub prerelease with the binary artifacts + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/master' + + # IMPORTANT! Any job added to the workflow should be added here too + needs: [validate, validate-old-ghcs, dogfooding] + + steps: + - uses: actions/download-artifact@v3 + with: + name: cabal-Windows-x86_64 + + - uses: actions/download-artifact@v3 + with: + name: cabal-Linux-x86_64 + + - uses: actions/download-artifact@v3 + with: + name: cabal-macOS-x86_64 + + - name: Create GitHub prerelease + uses: "marvinpinto/action-automatic-releases@v1.2.1" + with: + repo_token: "${{ secrets.GITHUB_TOKEN }}" + automatic_release_tag: "cabal-head" + prerelease: true + title: "cabal-head" + files: | + cabal-head-Windows-x86_64.tar.gz + cabal-head-Linux-x86_64.tar.gz + cabal-head-macOS-x86_64.tar.gz + + # We use this job as a summary of the workflow + # It will fail if any of the previous jobs does it + # This way we can use it exclusively in branch protection rules + # and abstract away the concrete jobs of the workflow, including their names + validate-post-job: + if: always() + name: Validate post job + runs-on: ubuntu-latest + # IMPORTANT! Any job added to the workflow should be added here too + needs: [validate, validate-old-ghcs, dogfooding] + + steps: + - run: | + echo "jobs info: ${{ toJSON(needs) }}" + - if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') + run: exit 1