Skip to content

Commit

Permalink
Add validate-revision workflow
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
ulysses4ever committed Dec 25, 2023
1 parent 8070ab1 commit 952e08b
Showing 1 changed file with 344 additions and 0 deletions.
344 changes: 344 additions & 0 deletions .github/workflows/validate-revision.yml
Original file line number Diff line number Diff line change
@@ -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 [email protected] 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/[email protected]"
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

0 comments on commit 952e08b

Please sign in to comment.