diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.12 - 2021-03-13
+
+- Use `cabal-install-3.4`
+- Add `bash` (Bash + Docker) generator
+- Add `github` (GitHub Actions) generator
+
 ## 0.10.3 - 2020-08-10
 
 - Add GHC-8.8.4 and GHC-8.10.2
diff --git a/cli/Main.hs b/cli/Main.hs
--- a/cli/Main.hs
+++ b/cli/Main.hs
@@ -1,2 +1,5 @@
 module Main (main) where
-import HaskellCI (main)
+-- https://gitlab.haskell.org/ghc/ghc/-/issues/19397
+import qualified HaskellCI
+main :: IO ()
+main = HaskellCI.main
diff --git a/fixtures/all-versions.args b/fixtures/all-versions.args
new file mode 100644
--- /dev/null
+++ b/fixtures/all-versions.args
diff --git a/fixtures/all-versions.bash b/fixtures/all-versions.bash
new file mode 100644
--- /dev/null
+++ b/fixtures/all-versions.bash
@@ -0,0 +1,520 @@
+# SUCCESS
+# *INFO* Generating Bash script for testing for GHC versions: 7.0.1 7.0.2 7.0.3 7.0.4 7.2.1 7.2.2 7.4.1 7.4.2 7.6.1 7.6.2 7.6.3 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4 9.0.1 ghcjs-8.4
+#!/bin/bash
+# shellcheck disable=SC2086,SC2016,SC2046
+# REGENDATA ["bash","all-versions.project"]
+
+set -o pipefail
+
+# Mode
+##############################################################################
+
+if [ "$1" = "indocker" ]; then
+    INDOCKER=true
+    shift
+else
+    INDOCKER=false
+fi
+
+# Run configuration
+##############################################################################
+
+CFG_CABAL_STORE_CACHE=""
+CFG_CABAL_REPO_CACHE=""
+CFG_JOBS="9.0.1 8.10.4 8.10.3 8.10.2 8.10.1 8.8.4 8.8.3 8.8.2 8.8.1 8.6.5 8.6.4 8.6.3 8.6.2 8.6.1 8.4.4 8.4.3 8.4.2 8.4.1 8.2.2 8.2.1 8.0.2 8.0.1 7.10.3 7.10.2 7.10.1 7.8.4 7.8.3 7.8.2 7.8.1 7.6.3 7.6.2 7.6.1 7.4.2 7.4.1 7.2.2 7.2.1 7.0.4 7.0.3 7.0.2 7.0.1"
+CFG_CABAL_UPDATE=false
+
+SCRIPT_NAME=$(basename "$0")
+START_TIME="$(date +'%s')"
+
+XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config}
+
+# Job configuration
+##############################################################################
+
+GHC_VERSION="non-existing"
+CABAL_VERSION=3.2
+HEADHACKAGE=false
+
+# Locale
+##############################################################################
+
+export LC_ALL=C.UTF-8
+
+# Utilities
+##############################################################################
+
+SGR_RED='\033[1;31m'
+SGR_GREEN='\033[1;32m'
+SGR_BLUE='\033[1;34m'
+SGR_CYAN='\033[1;96m'
+SGR_RESET='\033[0m' # No Color
+
+put_info() {
+    printf "$SGR_CYAN%s$SGR_RESET\n" "### $*"
+}
+
+put_error() {
+    printf "$SGR_RED%s$SGR_RESET\n" "!!! $*"
+}
+
+run_cmd() {
+    local PRETTYCMD="$*"
+    local PROMPT
+    if $INDOCKER; then
+        PROMPT="$(pwd) >>>"
+    else
+        PROMPT=">>>"
+    fi
+
+    printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+
+    local start_time end_time cmd_duration total_duration
+    start_time=$(date +'%s')
+
+    "$@"
+    local RET=$?
+
+    end_time=$(date +'%s')
+    cmd_duration=$((end_time - start_time))
+    total_duration=$((end_time - START_TIME))
+
+    cmd_min=$((cmd_duration / 60))
+    cmd_sec=$((cmd_duration % 60))
+
+    total_min=$((total_duration / 60))
+    total_sec=$((total_duration % 60))
+
+    if [ $RET -eq 0 ]; then
+        printf "$SGR_GREEN%s$SGR_RESET (%dm%02ds; %dm%02ds)\n" "<<< $PRETTYCMD" "$cmd_min" "$cmd_sec" "$total_min" "$total_sec"
+    else
+        printf "$SGR_RED%s$SGR_RESET\n" "!!! $PRETTYCMD"
+        exit 1
+    fi
+}
+
+run_cmd_if() {
+    local COND=$1
+    shift
+
+    if [ $COND -eq 1 ]; then
+        run_cmd "$@"
+    else
+        local PRETTYCMD="$*"
+        local PROMPT
+        PROMPT="$(pwd) (skipping) >>>"
+
+        printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+    fi
+}
+
+run_cmd_unchecked() {
+    local PRETTYCMD="$*"
+    local PROMPT
+    if $INDOCKER; then
+        PROMPT="$(pwd) >>>"
+    else
+        PROMPT=">>>"
+    fi
+
+    printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+
+    local start_time end_time cmd_duration total_duration cmd_min cmd_sec total_min total_sec
+    start_time=$(date +'%s')
+
+    "$@"
+
+    end_time=$(date +'%s')
+    cmd_duration=$((end_time - start_time))
+    total_duration=$((end_time - START_TIME))
+
+    cmd_min=$((cmd_duration / 60))
+    cmd_sec=$((cmd_duration % 60))
+
+    total_min=$((total_duration / 60))
+    total_sec=$((total_duration % 60))
+
+    printf "$SGR_GREEN%s$SGR_RESET (%dm%02ds; %dm%02ds)\n" "<<< $PRETTYCMD" "$cmd_min" "$cmd_sec" "$total_min" "$total_sec"
+}
+
+change_dir() {
+    local DIR=$1
+    if [ -d "$DIR" ]; then
+        printf "$SGR_BLUE%s$SGR_RESET\n" "change directory to $DIR"
+        cd "$DIR" || exit 1
+    else
+        printf "$SGR_RED%s$SGR_RESET\n" "!!! cd $DIR"
+        exit 1
+    fi
+}
+
+change_dir_if() {
+    local COND=$1
+    local DIR=$2
+
+    if [ $COND -ne 0 ]; then
+        change_dir "$DIR"
+    fi
+}
+
+echo_to() {
+    local DEST=$1
+    local CONTENTS=$2
+
+    echo "$CONTENTS" >> "$DEST"
+}
+
+echo_if_to() {
+    local COND=$1
+    local DEST=$2
+    local CONTENTS=$3
+
+    if [ $COND -ne 0 ]; then
+        echo_to "$DEST" "$CONTENTS"
+    fi
+}
+
+install_cabalplan() {
+    put_info "installing cabal-plan"
+
+    if [ ! -e $CABAL_REPOCACHE/downloads/cabal-plan ]; then
+        curl -L https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > /tmp/cabal-plan.xz || exit 1
+        (cd /tmp && echo "de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc  cabal-plan.xz" | sha256sum -c -)|| exit 1
+        mkdir -p $CABAL_REPOCACHE/downloads
+        xz -d < /tmp/cabal-plan.xz > $CABAL_REPOCACHE/downloads/cabal-plan || exit 1
+        chmod a+x $CABAL_REPOCACHE/downloads/cabal-plan || exit 1
+    fi
+
+    mkdir -p $CABAL_DIR/bin || exit 1
+    ln -s $CABAL_REPOCACHE/downloads/cabal-plan $CABAL_DIR/bin/cabal-plan || exit 1
+}
+
+# Help
+##############################################################################
+
+show_usage() {
+cat <<EOF
+./haskell-ci.sh - build & test
+
+Usage: ./haskell-ci.sh [options]
+  A script to run automated checks locally (using Docker)
+
+Available options:
+  --jobs JOBS               Jobs to run (default: $CFG_JOBS)
+  --cabal-store-cache PATH  Directory to use for cabal-store-cache
+  --cabal-repo-cache PATH   Directory to use for cabal-repo-cache
+  --skip-cabal-update       Skip cabal update (useful with --cabal-repo-cache)
+  --no-skip-cabal-update
+  --help                    Print this message
+
+EOF
+}
+
+# getopt
+#######################################################################
+
+process_cli_options() {
+    while [ $# -gt 0 ]; do
+        arg=$1
+        case $arg in
+            --help)
+                show_usage
+                exit
+                ;;
+            --jobs)
+                CFG_JOBS=$2
+                shift
+                shift
+                ;;
+            --cabal-store-cache)
+                CFG_CABAL_STORE_CACHE=$2
+                shift
+                shift
+                ;;
+            --cabal-repo-cache)
+                CFG_CABAL_REPO_CACHE=$2
+                shift
+                shift
+                ;;
+            --skip-cabal-update)
+                CFG_CABAL_UPDATE=false
+                shift
+                ;;
+            --no-skip-cabal-update)
+                CFG_CABAL_UPDATE=true
+                shift
+                ;;
+            *)
+                echo "Unknown option $arg"
+                exit 1
+        esac
+    done
+}
+
+process_indocker_options () {
+    while [ $# -gt 0 ]; do
+        arg=$1
+
+        case $arg in
+            --ghc-version)
+                GHC_VERSION=$2
+                shift
+                shift
+                ;;
+            --cabal-version)
+                CABAL_VERSION=$2
+                shift
+                shift
+                ;;
+            --start-time)
+                START_TIME=$2
+                shift
+                shift
+                ;;
+            --cabal-update)
+                CABAL_UPDATE=$2
+                shift
+                shift
+                ;;
+            *)
+                echo "Unknown option $arg"
+                exit 1
+        esac
+    done
+}
+
+if $INDOCKER; then
+    process_indocker_options "$@"
+
+else
+    if [ -f "$XDG_CONFIG_HOME/haskell-ci/bash.config" ]; then
+        process_cli_options $(cat "$XDG_CONFIG_HOME/haskell-ci/bash.config")
+    fi
+
+    process_cli_options "$@"
+
+    put_info "jobs:              $CFG_JOBS"
+    put_info "cabal-store-cache: $CFG_CABAL_STORE_CACHE"
+    put_info "cabal-repo-cache:  $CFG_CABAL_REPO_CACHE"
+    put_info "cabal-update:      $CFG_CABAL_UPDATE"
+fi
+
+# Constants
+##############################################################################
+
+SRCDIR=/hsci/src
+BUILDDIR=/hsci/build
+CABAL_DIR="$BUILDDIR/cabal"
+CABAL_REPOCACHE=/hsci/cabal-repocache
+CABAL_STOREDIR=/hsci/store
+
+# Docker invoke
+##############################################################################
+
+# if cache directory is specified, use it.
+# Otherwise use another tmpfs host
+if [ -z "$CFG_CABAL_STORE_CACHE" ]; then
+    CABALSTOREARG="--tmpfs $CABAL_STOREDIR:exec"
+else
+    CABALSTOREARG="--volume $CFG_CABAL_STORE_CACHE:$CABAL_STOREDIR"
+fi
+
+if [ -z "$CFG_CABAL_REPO_CACHE" ]; then
+    CABALREPOARG="--tmpfs $CABAL_REPOCACHE:exec"
+else
+    CABALREPOARG="--volume $CFG_CABAL_REPO_CACHE:$CABAL_REPOCACHE"
+fi
+
+echo_docker_cmd() {
+    local GHCVER=$1
+
+    # TODO: mount /hsci/src:ro (readonly)
+    echo docker run \
+        --tty \
+        --interactive \
+        --rm \
+        --label haskell-ci \
+        --volume "$(pwd):/hsci/src" \
+        $CABALSTOREARG \
+        $CABALREPOARG \
+        --tmpfs /tmp:exec \
+        --tmpfs /hsci/build:exec \
+        --workdir /hsci/build \
+        "phadej/ghc:$GHCVER-bionic" \
+        "/bin/bash" "/hsci/src/$SCRIPT_NAME" indocker \
+        --ghc-version "$GHCVER" \
+        --cabal-update "$CFG_CABAL_UPDATE" \
+        --start-time "$START_TIME"
+}
+
+# if we are not in docker, loop through jobs
+if ! $INDOCKER; then
+    for JOB in $CFG_JOBS; do
+        put_info "Running in docker: $JOB"
+        run_cmd $(echo_docker_cmd "$JOB")
+    done
+
+    run_cmd echo "ALL OK"
+    exit 0
+fi
+
+# Otherwise we are in docker, and the rest of script executes
+put_info "In docker"
+
+# Environment
+##############################################################################
+
+GHCDIR=/opt/ghc/$GHC_VERSION
+
+HC=$GHCDIR/bin/ghc
+HCPKG=$GHCDIR/bin/ghc-pkg
+HADDOCK=$GHCDIR/bin/haddock
+
+CABAL=/opt/cabal/$CABAL_VERSION/bin/cabal
+
+CABAL="$CABAL -vnormal+nowrap"
+
+export CABAL_DIR
+export CABAL_CONFIG="$BUILDDIR/cabal/config"
+
+PATH="$CABAL_DIR/bin:$PATH"
+
+# HCNUMVER
+HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
+GHCJSARITH=0
+
+put_info "HCNUMVER: $HCNUMVER"
+
+# Args for shorter/nicer commands
+if [ $((GHCJSARITH || ! GHCJSARITH)) -ne 0 ] ; then ARG_TESTS=--enable-tests; else ARG_TESTS=--disable-tests; fi
+if [ $((GHCJSARITH || ! GHCJSARITH)) -ne 0 ] ; then ARG_BENCH=--enable-benchmarks; else ARG_BENCH=--disable-benchmarks; fi
+ARG_COMPILER="--ghc --with-compiler=$HC"
+
+put_info "tests/benchmarks: $ARG_TESTS $ARG_BENCH"
+
+# Apt dependencies
+##############################################################################
+
+
+# Cabal config
+##############################################################################
+
+mkdir -p $BUILDDIR/cabal
+
+cat > $BUILDDIR/cabal/config <<EOF
+remote-build-reporting: anonymous
+write-ghc-environment-files: always
+remote-repo-cache: $CABAL_REPOCACHE
+logs-dir:          $CABAL_DIR/logs
+world-file:        $CABAL_DIR/world
+extra-prog-path:   $CABAL_DIR/bin
+symlink-bindir:    $CABAL_DIR/bin
+installdir:        $CABAL_DIR/bin
+build-summary:     $CABAL_DIR/logs/build.log
+store-dir:         $CABAL_STOREDIR
+install-dirs user
+  prefix: $CABAL_DIR
+repository hackage.haskell.org
+  url: http://hackage.haskell.org/
+EOF
+
+if $HEADHACKAGE; then
+    put_error "head.hackage is not implemented"
+    exit 1
+fi
+
+run_cmd cat "$BUILDDIR/cabal/config"
+
+# Version
+##############################################################################
+
+put_info "Versions"
+run_cmd $HC --version
+run_cmd_unchecked $HC --print-project-git-commit-id
+run_cmd $CABAL --version
+
+# Build script
+##############################################################################
+
+# update cabal index
+if $CABAL_UPDATE; then
+    put_info "Updating Hackage index"
+    run_cmd $CABAL v2-update -v
+fi
+
+# install cabal-plan
+install_cabalplan
+run_cmd cabal-plan --version
+
+# initial cabal.project for sdist
+put_info "initial cabal.project for sdist"
+change_dir "$BUILDDIR"
+run_cmd touch cabal.project
+echo_to cabal.project "packages: $SRCDIR/splitmix"
+run_cmd cat cabal.project
+
+# sdist
+put_info "sdist"
+run_cmd mkdir -p "$BUILDDIR/sdist"
+run_cmd $CABAL sdist all --output-dir "$BUILDDIR/sdist"
+
+# unpack
+put_info "unpack"
+change_dir "$BUILDDIR"
+run_cmd mkdir -p "$BUILDDIR/unpacked"
+run_cmd find "$BUILDDIR/sdist" -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C "$BUILDDIR/unpacked" -xzvf {} \;
+
+# generate cabal.project
+put_info "generate cabal.project"
+PKGDIR_splitmix="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/splitmix-[0-9.]*')"
+run_cmd touch cabal.project
+run_cmd touch cabal.project.local
+echo_to cabal.project "packages: ${PKGDIR_splitmix}"
+echo_if_to $((GHCJSARITH || ! GHCJSARITH && HCNUMVER >= 80200)) cabal.project "package splitmix"
+echo_if_to $((GHCJSARITH || ! GHCJSARITH && HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+cat >> cabal.project <<EOF
+EOF
+$HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(splitmix)$/; }' >> cabal.project.local
+run_cmd cat cabal.project
+run_cmd cat cabal.project.local
+
+# dump install plan
+put_info "dump install plan"
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
+run_cmd cabal-plan
+
+# install dependencies
+put_info "install dependencies"
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j all
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j all
+
+# build w/o tests
+put_info "build w/o tests"
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+
+# build
+put_info "build"
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all
+
+# tests
+put_info "tests"
+run_cmd_if $((! GHCJSARITH)) $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
+
+# cabal check
+put_info "cabal check"
+change_dir "${PKGDIR_splitmix}"
+run_cmd ${CABAL} -vnormal check
+change_dir "$BUILDDIR"
+
+# haddock
+put_info "haddock"
+run_cmd_if $((! GHCJSARITH)) $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
+
+# unconstrained build
+put_info "unconstrained build"
+run_cmd rm -f cabal.project.local
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+
+
+# Done
+run_cmd echo OK
diff --git a/fixtures/all-versions.github b/fixtures/all-versions.github
new file mode 100644
--- /dev/null
+++ b/fixtures/all-versions.github
@@ -0,0 +1,264 @@
+# SUCCESS
+# *INFO* Generating GitHub config for testing for GHC versions: 7.0.1 7.0.2 7.0.3 7.0.4 7.2.1 7.2.2 7.4.1 7.4.2 7.6.1 7.6.2 7.6.3 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4 9.0.1 ghcjs-8.4
+# This GitHub workflow config has been generated by a script via
+#
+#   haskell-ci 'github' 'all-versions.project'
+#
+# To regenerate the script (for example after adjusting tested-with) run
+#
+#   haskell-ci regenerate
+#
+# For more information, see https://github.com/haskell-CI/haskell-ci
+#
+# REGENDATA ["github","all-versions.project"]
+#
+name: Haskell-CI
+on:
+  - push
+  - pull_request
+jobs:
+  linux:
+    name: Haskell-CI - Linux - ${{ matrix.compiler }}
+    runs-on: ubuntu-18.04
+    container:
+      image: buildpack-deps:bionic
+    continue-on-error: ${{ matrix.allow-failure }}
+    strategy:
+      matrix:
+        include:
+          - compiler: ghcjs-8.4
+            allow-failure: false
+          - compiler: ghc-9.0.1
+            allow-failure: false
+          - compiler: ghc-8.10.4
+            allow-failure: false
+          - compiler: ghc-8.10.3
+            allow-failure: false
+          - compiler: ghc-8.10.2
+            allow-failure: false
+          - compiler: ghc-8.10.1
+            allow-failure: false
+          - compiler: ghc-8.8.4
+            allow-failure: false
+          - compiler: ghc-8.8.3
+            allow-failure: false
+          - compiler: ghc-8.8.2
+            allow-failure: false
+          - compiler: ghc-8.8.1
+            allow-failure: false
+          - compiler: ghc-8.6.5
+            allow-failure: false
+          - compiler: ghc-8.6.4
+            allow-failure: false
+          - compiler: ghc-8.6.3
+            allow-failure: false
+          - compiler: ghc-8.6.2
+            allow-failure: false
+          - compiler: ghc-8.6.1
+            allow-failure: false
+          - compiler: ghc-8.4.4
+            allow-failure: false
+          - compiler: ghc-8.4.3
+            allow-failure: false
+          - compiler: ghc-8.4.2
+            allow-failure: false
+          - compiler: ghc-8.4.1
+            allow-failure: false
+          - compiler: ghc-8.2.2
+            allow-failure: false
+          - compiler: ghc-8.2.1
+            allow-failure: false
+          - compiler: ghc-8.0.2
+            allow-failure: false
+          - compiler: ghc-8.0.1
+            allow-failure: false
+          - compiler: ghc-7.10.3
+            allow-failure: false
+          - compiler: ghc-7.10.2
+            allow-failure: false
+          - compiler: ghc-7.10.1
+            allow-failure: false
+          - compiler: ghc-7.8.4
+            allow-failure: false
+          - compiler: ghc-7.8.3
+            allow-failure: false
+          - compiler: ghc-7.8.2
+            allow-failure: false
+          - compiler: ghc-7.8.1
+            allow-failure: false
+          - compiler: ghc-7.6.3
+            allow-failure: false
+          - compiler: ghc-7.6.2
+            allow-failure: false
+          - compiler: ghc-7.6.1
+            allow-failure: false
+          - compiler: ghc-7.4.2
+            allow-failure: false
+          - compiler: ghc-7.4.1
+            allow-failure: false
+          - compiler: ghc-7.2.2
+            allow-failure: false
+          - compiler: ghc-7.2.1
+            allow-failure: false
+          - compiler: ghc-7.0.4
+            allow-failure: false
+          - compiler: ghc-7.0.3
+            allow-failure: false
+          - compiler: ghc-7.0.2
+            allow-failure: false
+          - compiler: ghc-7.0.1
+            allow-failure: false
+      fail-fast: false
+    steps:
+      - name: Set GHCJS environment variables
+        run: |
+          if echo $CC | grep -q ghcjs; then
+          echo "GHCJS=true" >> $GITHUB_ENV
+          echo "GHCJSARITH=1" >> $GITHUB_ENV
+          else
+          echo "GHCJS=false" >> $GITHUB_ENV
+          echo "GHCJSARITH=0" >> $GITHUB_ENV
+          fi
+        env:
+          CC: ${{ matrix.compiler }}
+      - name: apt
+        run: |
+          apt-get update
+          apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common
+          apt-add-repository -y 'ppa:hvr/ghc'
+          if [ $((GHCJSARITH)) -ne 0 ] ; then apt-add-repository -y 'ppa:hvr/ghcjs' ; fi
+          if [ $((GHCJSARITH)) -ne 0 ] ; then curl -sSL "https://deb.nodesource.com/gpgkey/nodesource.gpg.key" | apt-key add - ; fi
+          if [ $((GHCJSARITH)) -ne 0 ] ; then apt-add-repository -y 'deb https://deb.nodesource.com/node_10.x bionic main' ; fi
+          apt-get update
+          if [ $((GHCJSARITH)) -ne 0 ] ; then apt-get install -y $CC cabal-install-3.4 ghc-8.4.4 nodejs ; else apt-get install -y $CC cabal-install-3.4 ; fi
+        env:
+          CC: ${{ matrix.compiler }}
+      - name: Set PATH and environment variables
+        run: |
+          echo "$HOME/.cabal/bin" >> $GITHUB_PATH
+          if [ $((GHCJSARITH)) -ne 0 ] ; then echo "/opt/ghc/8.4.4/bin" >> $GITHUB_PATH ; fi
+          echo "LANG=C.UTF-8" >> $GITHUB_ENV
+          echo "CABAL_DIR=$HOME/.cabal" >> $GITHUB_ENV
+          echo "CABAL_CONFIG=$HOME/.cabal/config" >> $GITHUB_ENV
+          HCDIR=$(echo "/opt/$CC" | sed 's/-/\//')
+          if [ $((GHCJSARITH)) -ne 0 ] ; then HCNAME=ghcjs ; else HCNAME=ghc ; fi
+          HC=$HCDIR/bin/$HCNAME
+          echo "HC=$HC" >> $GITHUB_ENV
+          echo "HCPKG=$HCDIR/bin/$HCNAME-pkg" >> $GITHUB_ENV
+          echo "HADDOCK=$HCDIR/bin/haddock" >> $GITHUB_ENV
+          echo "CABAL=/opt/cabal/3.4/bin/cabal -vnormal+nowrap" >> $GITHUB_ENV
+          HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
+          echo "HCNUMVER=$HCNUMVER" >> $GITHUB_ENV
+          echo "ARG_TESTS=--enable-tests" >> $GITHUB_ENV
+          echo "ARG_BENCH=--enable-benchmarks" >> $GITHUB_ENV
+          echo "HEADHACKAGE=false" >> $GITHUB_ENV
+          echo "ARG_COMPILER=--$HCNAME --with-compiler=$HC" >> $GITHUB_ENV
+        env:
+          CC: ${{ matrix.compiler }}
+      - name: env
+        run: |
+          env
+      - name: write cabal config
+        run: |
+          mkdir -p $CABAL_DIR
+          cat >> $CABAL_CONFIG <<EOF
+          remote-build-reporting: anonymous
+          write-ghc-environment-files: never
+          remote-repo-cache: $CABAL_DIR/packages
+          logs-dir:          $CABAL_DIR/logs
+          world-file:        $CABAL_DIR/world
+          extra-prog-path:   $CABAL_DIR/bin
+          symlink-bindir:    $CABAL_DIR/bin
+          installdir:        $CABAL_DIR/bin
+          build-summary:     $CABAL_DIR/logs/build.log
+          store-dir:         $CABAL_DIR/store
+          install-dirs user
+            prefix: $CABAL_DIR
+          repository hackage.haskell.org
+            url: http://hackage.haskell.org/
+          EOF
+          cat $CABAL_CONFIG
+      - name: versions
+        run: |
+          $HC --version || true
+          $HC --print-project-git-commit-id || true
+          $CABAL --version || true
+          if [ $((GHCJSARITH)) -ne 0 ] ; then node --version ; fi
+          if [ $((GHCJSARITH)) -ne 0 ] ; then echo $GHCJS ; fi
+      - name: update cabal index
+        run: |
+          $CABAL v2-update -v
+      - name: install cabal-plan
+        run: |
+          mkdir -p $HOME/.cabal/bin
+          curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > cabal-plan.xz
+          echo 'de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc  cabal-plan.xz' | sha256sum -c -
+          xz -d < cabal-plan.xz > $HOME/.cabal/bin/cabal-plan
+          rm -f cabal-plan.xz
+          chmod a+x $HOME/.cabal/bin/cabal-plan
+          cabal-plan --version
+      - name: checkout
+        uses: actions/checkout@v2
+        with:
+          path: source
+      - name: initial cabal.project for sdist
+        run: |
+          touch cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/splitmix" >> cabal.project
+          cat cabal.project
+      - name: sdist
+        run: |
+          mkdir -p sdist
+          $CABAL sdist all --output-dir $GITHUB_WORKSPACE/sdist
+      - name: unpack
+        run: |
+          mkdir -p unpacked
+          find sdist -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C $GITHUB_WORKSPACE/unpacked -xzvf {} \;
+      - name: generate cabal.project
+        run: |
+          PKGDIR_splitmix="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/splitmix-[0-9.]*')"
+          echo "PKGDIR_splitmix=${PKGDIR_splitmix}" >> $GITHUB_ENV
+          touch cabal.project
+          touch cabal.project.local
+          echo "packages: ${PKGDIR_splitmix}" >> cabal.project
+          if [ $((GHCJSARITH || ! GHCJSARITH && HCNUMVER >= 80200)) -ne 0 ] ; then echo "package splitmix" >> cabal.project ; fi
+          if [ $((GHCJSARITH || ! GHCJSARITH && HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          cat >> cabal.project <<EOF
+          EOF
+          $HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(splitmix)$/; }' >> cabal.project.local
+          cat cabal.project
+          cat cabal.project.local
+      - name: dump install plan
+        run: |
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
+          cabal-plan
+      - name: cache
+        uses: actions/cache@v2
+        with:
+          key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
+          path: ~/.cabal/store
+          restore-keys: ${{ runner.os }}-${{ matrix.compiler }}-
+      - name: install dependencies
+        run: |
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j2 all
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j2 all
+      - name: build w/o tests
+        run: |
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+      - name: build
+        run: |
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --write-ghc-environment-files=always
+      - name: tests
+        run: |
+          if [ $((! GHCJSARITH)) -ne 0 ] ; then $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct ; fi
+      - name: cabal check
+        run: |
+          cd ${PKGDIR_splitmix} || false
+          ${CABAL} -vnormal check
+      - name: haddock
+        run: |
+          if [ $((! GHCJSARITH)) -ne 0 ] ; then $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all ; fi
+      - name: unconstrained build
+        run: |
+          rm -f cabal.project.local
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
diff --git a/fixtures/all-versions.project b/fixtures/all-versions.project
new file mode 100644
--- /dev/null
+++ b/fixtures/all-versions.project
@@ -0,0 +1,1 @@
+packages: splitmix
diff --git a/fixtures/all-versions.travis b/fixtures/all-versions.travis
new file mode 100644
--- /dev/null
+++ b/fixtures/all-versions.travis
@@ -0,0 +1,268 @@
+# SUCCESS
+# *INFO* Generating Travis-CI config for testing for GHC versions: 7.0.1 7.0.2 7.0.3 7.0.4 7.2.1 7.2.2 7.4.1 7.4.2 7.6.1 7.6.2 7.6.3 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4 9.0.1 ghcjs-8.4
+# This Travis job script has been generated by a script via
+#
+#   haskell-ci 'travis' 'all-versions.project'
+#
+# To regenerate the script (for example after adjusting tested-with) run
+#
+#   haskell-ci regenerate
+#
+# For more information, see https://github.com/haskell-CI/haskell-ci
+#
+version: ~> 1.0
+language: c
+os: linux
+dist: xenial
+git:
+  # whether to recursively clone submodules
+  submodules: false
+cache:
+  directories:
+    - $HOME/.cabal/packages
+    - $HOME/.cabal/store
+    - $HOME/.hlint
+before_cache:
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log
+  # remove files that are regenerated by 'cabal update'
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx
+  - rm -rfv $CABALHOME/packages/head.hackage
+jobs:
+  include:
+    - compiler: ghcjs-8.4
+      addons: {"apt":{"packages":["ghcjs-8.4","cabal-install-3.4","ghc-8.4.4","nodejs"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"},{"sourceline":"deb http://ppa.launchpad.net/hvr/ghcjs/ubuntu xenial main"},{"key_url":"https://deb.nodesource.com/gpgkey/nodesource.gpg.key","sourceline":"deb https://deb.nodesource.com/node_10.x xenial main"}]}}
+      os: linux
+    - compiler: ghc-9.0.1
+      addons: {"apt":{"packages":["ghc-9.0.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.4
+      addons: {"apt":{"packages":["ghc-8.10.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.3
+      addons: {"apt":{"packages":["ghc-8.10.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.2
+      addons: {"apt":{"packages":["ghc-8.10.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.1
+      addons: {"apt":{"packages":["ghc-8.10.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.4
+      addons: {"apt":{"packages":["ghc-8.8.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.3
+      addons: {"apt":{"packages":["ghc-8.8.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.2
+      addons: {"apt":{"packages":["ghc-8.8.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.1
+      addons: {"apt":{"packages":["ghc-8.8.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.5
+      addons: {"apt":{"packages":["ghc-8.6.5","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.4
+      addons: {"apt":{"packages":["ghc-8.6.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.3
+      addons: {"apt":{"packages":["ghc-8.6.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.2
+      addons: {"apt":{"packages":["ghc-8.6.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.1
+      addons: {"apt":{"packages":["ghc-8.6.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.4
+      addons: {"apt":{"packages":["ghc-8.4.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.3
+      addons: {"apt":{"packages":["ghc-8.4.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.2
+      addons: {"apt":{"packages":["ghc-8.4.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.1
+      addons: {"apt":{"packages":["ghc-8.4.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.2.2
+      addons: {"apt":{"packages":["ghc-8.2.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.2.1
+      addons: {"apt":{"packages":["ghc-8.2.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.0.2
+      addons: {"apt":{"packages":["ghc-8.0.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.0.1
+      addons: {"apt":{"packages":["ghc-8.0.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.3
+      addons: {"apt":{"packages":["ghc-7.10.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.2
+      addons: {"apt":{"packages":["ghc-7.10.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.1
+      addons: {"apt":{"packages":["ghc-7.10.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.4
+      addons: {"apt":{"packages":["ghc-7.8.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.3
+      addons: {"apt":{"packages":["ghc-7.8.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.2
+      addons: {"apt":{"packages":["ghc-7.8.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.1
+      addons: {"apt":{"packages":["ghc-7.8.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.6.3
+      addons: {"apt":{"packages":["ghc-7.6.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.6.2
+      addons: {"apt":{"packages":["ghc-7.6.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.6.1
+      addons: {"apt":{"packages":["ghc-7.6.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.4.2
+      addons: {"apt":{"packages":["ghc-7.4.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.4.1
+      addons: {"apt":{"packages":["ghc-7.4.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.2.2
+      addons: {"apt":{"packages":["ghc-7.2.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.2.1
+      addons: {"apt":{"packages":["ghc-7.2.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.0.4
+      addons: {"apt":{"packages":["ghc-7.0.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.0.3
+      addons: {"apt":{"packages":["ghc-7.0.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.0.2
+      addons: {"apt":{"packages":["ghc-7.0.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.0.1
+      addons: {"apt":{"packages":["ghc-7.0.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+before_install:
+  - |
+    if echo $CC | grep -q ghcjs; then
+        GHCJS=true; GHCJSARITH=1;
+    else
+        GHCJS=false; GHCJSARITH=0;
+    fi
+  - HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//')
+  - WITHCOMPILER="-w $HC"
+  - if [ $((GHCJSARITH)) -ne 0 ] ; then HC=${HC}js ; fi
+  - if [ $((GHCJSARITH)) -ne 0 ] ; then WITHCOMPILER="--ghcjs ${WITHCOMPILER}js" ; fi
+  - HADDOCK=$(echo "/opt/$CC/bin/haddock" | sed 's/-/\//')
+  - if [ $((GHCJSARITH)) -ne 0 ] ; then PATH="/opt/ghc/8.4.4/bin:$PATH" ; fi
+  - HCPKG="$HC-pkg"
+  - unset CC
+  - CABAL=/opt/ghc/bin/cabal
+  - CABALHOME=$HOME/.cabal
+  - export PATH="$CABALHOME/bin:$PATH"
+  - TOP=$(pwd)
+  - "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')"
+  - echo $HCNUMVER
+  - CABAL="$CABAL -vnormal+nowrap"
+  - set -o pipefail
+  - TEST=--enable-tests
+  - BENCH=--enable-benchmarks
+  - HEADHACKAGE=false
+  - rm -f $CABALHOME/config
+  - |
+    echo "verbose: normal +nowrap +markoutput"          >> $CABALHOME/config
+    echo "remote-build-reporting: anonymous"            >> $CABALHOME/config
+    echo "write-ghc-environment-files: never"           >> $CABALHOME/config
+    echo "remote-repo-cache: $CABALHOME/packages"       >> $CABALHOME/config
+    echo "logs-dir:          $CABALHOME/logs"           >> $CABALHOME/config
+    echo "world-file:        $CABALHOME/world"          >> $CABALHOME/config
+    echo "extra-prog-path:   $CABALHOME/bin"            >> $CABALHOME/config
+    echo "symlink-bindir:    $CABALHOME/bin"            >> $CABALHOME/config
+    echo "installdir:        $CABALHOME/bin"            >> $CABALHOME/config
+    echo "build-summary:     $CABALHOME/logs/build.log" >> $CABALHOME/config
+    echo "store-dir:         $CABALHOME/store"          >> $CABALHOME/config
+    echo "install-dirs user"                            >> $CABALHOME/config
+    echo "  prefix: $CABALHOME"                         >> $CABALHOME/config
+    echo "repository hackage.haskell.org"               >> $CABALHOME/config
+    echo "  url: http://hackage.haskell.org/"           >> $CABALHOME/config
+install:
+  - ${CABAL} --version
+  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
+  - node --version
+  - echo $GHCJS
+  - |
+    echo "program-default-options"                >> $CABALHOME/config
+    echo "  ghc-options: $GHCJOBS +RTS -M6G -RTS" >> $CABALHOME/config
+  - cat $CABALHOME/config
+  - rm -fv cabal.project cabal.project.local cabal.project.freeze
+  - travis_retry ${CABAL} v2-update -v
+  # Generate cabal.project
+  - rm -rf cabal.project cabal.project.local cabal.project.freeze
+  - touch cabal.project
+  - |
+    echo "packages: splitmix" >> cabal.project
+  - if [ $((GHCJSARITH || ! GHCJSARITH && HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package splitmix' >> cabal.project ; fi
+  - "if [ $((GHCJSARITH || ! GHCJSARITH && HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - |
+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(splitmix)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
+  - cat cabal.project || true
+  - cat cabal.project.local || true
+  - if [ -f "splitmix/configure.ac" ]; then (cd "splitmix" && autoreconf -i); fi
+  - ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH}
+  - "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
+  - rm  cabal.project.freeze
+  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} --dep -j2 all
+  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --dep -j2 all
+script:
+  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
+  # Packaging...
+  - ${CABAL} v2-sdist all
+  # Unpacking...
+  - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
+  - cd ${DISTDIR} || false
+  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \;
+  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm       '{}' \;
+  - PKGDIR_splitmix="$(find . -maxdepth 1 -type d -regex '.*/splitmix-[0-9.]*')"
+  # Generate cabal.project
+  - rm -rf cabal.project cabal.project.local cabal.project.freeze
+  - touch cabal.project
+  - |
+    echo "packages: ${PKGDIR_splitmix}" >> cabal.project
+  - if [ $((GHCJSARITH || ! GHCJSARITH && HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package splitmix' >> cabal.project ; fi
+  - "if [ $((GHCJSARITH || ! GHCJSARITH && HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - |
+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(splitmix)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
+  - cat cabal.project || true
+  - cat cabal.project.local || true
+  # Building...
+  # this builds all libraries and executables (without tests/benchmarks)
+  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
+  # Building with tests and benchmarks...
+  # build & run tests, build benchmarks
+  - ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} all --write-ghc-environment-files=always
+  # Testing...
+  - if [ $((! GHCJSARITH)) -ne 0 ] ; then ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all --test-show-details=direct ; fi
+  # cabal check...
+  - (cd ${PKGDIR_splitmix} && ${CABAL} -vnormal check)
+  # haddock...
+  - if [ $((! GHCJSARITH)) -ne 0 ] ; then ${CABAL} v2-haddock $WITHCOMPILER --with-haddock $HADDOCK ${TEST} ${BENCH} all ; fi
+  # Building without installed constraints for packages in global-db...
+  - rm -f cabal.project.local
+  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
+
+# REGENDATA ["travis","all-versions.project"]
+# EOF
diff --git a/fixtures/cabal.project.copy-fields.all b/fixtures/cabal.project.copy-fields.all
deleted file mode 100644
--- a/fixtures/cabal.project.copy-fields.all
+++ /dev/null
@@ -1,20 +0,0 @@
-packages:
-  servant/
-  servant-client/
-  servant-docs/
-  servant-server/
-
-package servant
-  tests: False
-
-constraints: foundation >= 0.14
-
-allow-newer:
-  servant-js:servant
-allow-newer:
-  servant-js:servant-foreign
-
-source-repository-package
-  type: git
-  location: https://github.com/haskell-servant/servant-auth
-  tag: 4a134c3db79293d28f8b74a02863047e41fbaf56
diff --git a/fixtures/cabal.project.copy-fields.all.stderr b/fixtures/cabal.project.copy-fields.all.stderr
deleted file mode 100644
--- a/fixtures/cabal.project.copy-fields.all.stderr
+++ /dev/null
@@ -1,1 +0,0 @@
-*INFO* Generating Travis-CI config for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2
diff --git a/fixtures/cabal.project.copy-fields.all.travis.yml b/fixtures/cabal.project.copy-fields.all.travis.yml
deleted file mode 100644
--- a/fixtures/cabal.project.copy-fields.all.travis.yml
+++ /dev/null
@@ -1,259 +0,0 @@
-# This Travis job script has been generated by a script via
-#
-#   haskell-ci '-o' 'cabal.project.empty-line.travis.yml' '--config=cabal.project.haskell-ci' '--copy-fields=all' 'cabal.project.empty-line'
-#
-# To regenerate the script (for example after adjusting tested-with) run
-#
-#   haskell-ci regenerate
-#
-# For more information, see https://github.com/haskell-CI/haskell-ci
-#
-version: ~> 1.0
-language: c
-os: linux
-dist: xenial
-git:
-  # whether to recursively clone submodules
-  submodules: false
-cache:
-  directories:
-    - $HOME/.cabal/packages
-    - $HOME/.cabal/store
-    - $HOME/.hlint
-before_cache:
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log
-  # remove files that are regenerated by 'cabal update'
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx
-  - rm -rfv $CABALHOME/packages/head.hackage
-jobs:
-  include:
-    - compiler: ghc-8.10.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.10.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.10.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.10.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.8.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.4","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.8.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.8.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.8.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.5
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.5","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.4","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.4.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.4","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.4.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.4.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.4.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.2.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.2.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.2.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.2.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.0.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.0.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.0.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.0.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.10.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.10.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.10.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.10.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.10.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.10.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.8.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.4","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.8.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.8.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.8.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.1","cabal-install-3.2"]}}
-      os: linux
-before_install:
-  - HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//')
-  - WITHCOMPILER="-w $HC"
-  - HADDOCK=$(echo "/opt/$CC/bin/haddock" | sed 's/-/\//')
-  - HCPKG="$HC-pkg"
-  - unset CC
-  - CABAL=/opt/ghc/bin/cabal
-  - CABALHOME=$HOME/.cabal
-  - export PATH="$CABALHOME/bin:$PATH"
-  - TOP=$(pwd)
-  - "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')"
-  - echo $HCNUMVER
-  - CABAL="$CABAL -vnormal+nowrap"
-  - set -o pipefail
-  - TEST=--enable-tests
-  - BENCH=--enable-benchmarks
-  - HEADHACKAGE=false
-  - rm -f $CABALHOME/config
-  - |
-    echo "verbose: normal +nowrap +markoutput"          >> $CABALHOME/config
-    echo "remote-build-reporting: anonymous"            >> $CABALHOME/config
-    echo "write-ghc-environment-files: always"          >> $CABALHOME/config
-    echo "remote-repo-cache: $CABALHOME/packages"       >> $CABALHOME/config
-    echo "logs-dir:          $CABALHOME/logs"           >> $CABALHOME/config
-    echo "world-file:        $CABALHOME/world"          >> $CABALHOME/config
-    echo "extra-prog-path:   $CABALHOME/bin"            >> $CABALHOME/config
-    echo "symlink-bindir:    $CABALHOME/bin"            >> $CABALHOME/config
-    echo "installdir:        $CABALHOME/bin"            >> $CABALHOME/config
-    echo "build-summary:     $CABALHOME/logs/build.log" >> $CABALHOME/config
-    echo "store-dir:         $CABALHOME/store"          >> $CABALHOME/config
-    echo "install-dirs user"                            >> $CABALHOME/config
-    echo "  prefix: $CABALHOME"                         >> $CABALHOME/config
-    echo "repository hackage.haskell.org"               >> $CABALHOME/config
-    echo "  url: http://hackage.haskell.org/"           >> $CABALHOME/config
-install:
-  - ${CABAL} --version
-  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
-  - |
-    echo "program-default-options"                >> $CABALHOME/config
-    echo "  ghc-options: $GHCJOBS +RTS -M6G -RTS" >> $CABALHOME/config
-  - cat $CABALHOME/config
-  - rm -fv cabal.project cabal.project.local cabal.project.freeze
-  - travis_retry ${CABAL} v2-update -v
-  # Generate cabal.project
-  - rm -rf cabal.project cabal.project.local cabal.project.freeze
-  - touch cabal.project
-  - |
-    echo "packages: servant" >> cabal.project
-    echo "packages: servant-client" >> cabal.project
-    echo "packages: servant-docs" >> cabal.project
-    echo "packages: servant-server" >> cabal.project
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-client' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-docs' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-server' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - |
-    echo "constraints: foundation >= 0.14"                             >> cabal.project
-    echo "allow-newer: servant-js:servant"                             >> cabal.project
-    echo "allow-newer: servant-js:servant-foreign"                     >> cabal.project
-    echo ""                                                            >> cabal.project
-    echo "source-repository-package"                                   >> cabal.project
-    echo "  type:     git"                                             >> cabal.project
-    echo "  location: https://github.com/haskell-servant/servant-auth" >> cabal.project
-    echo "  tag:      4a134c3db79293d28f8b74a02863047e41fbaf56"        >> cabal.project
-    echo ""                                                            >> cabal.project
-    echo "package servant"                                             >> cabal.project
-    echo "  tests: False"                                              >> cabal.project
-  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
-  - cat cabal.project || true
-  - cat cabal.project.local || true
-  - if [ -f "servant/configure.ac" ]; then (cd "servant" && autoreconf -i); fi
-  - if [ -f "servant-client/configure.ac" ]; then (cd "servant-client" && autoreconf -i); fi
-  - if [ -f "servant-docs/configure.ac" ]; then (cd "servant-docs" && autoreconf -i); fi
-  - if [ -f "servant-server/configure.ac" ]; then (cd "servant-server" && autoreconf -i); fi
-  - ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH}
-  - "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
-  - rm  cabal.project.freeze
-  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} --dep -j2 all
-  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --dep -j2 all
-script:
-  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
-  # Packaging...
-  - ${CABAL} v2-sdist all
-  # Unpacking...
-  - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
-  - cd ${DISTDIR} || false
-  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \;
-  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm       '{}' \;
-  - PKGDIR_servant="$(find . -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
-  - PKGDIR_servant_client="$(find . -maxdepth 1 -type d -regex '.*/servant-client-[0-9.]*')"
-  - PKGDIR_servant_docs="$(find . -maxdepth 1 -type d -regex '.*/servant-docs-[0-9.]*')"
-  - PKGDIR_servant_server="$(find . -maxdepth 1 -type d -regex '.*/servant-server-[0-9.]*')"
-  # Generate cabal.project
-  - rm -rf cabal.project cabal.project.local cabal.project.freeze
-  - touch cabal.project
-  - |
-    echo "packages: ${PKGDIR_servant}" >> cabal.project
-    echo "packages: ${PKGDIR_servant_client}" >> cabal.project
-    echo "packages: ${PKGDIR_servant_docs}" >> cabal.project
-    echo "packages: ${PKGDIR_servant_server}" >> cabal.project
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-client' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-docs' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-server' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - |
-    echo "constraints: foundation >= 0.14"                             >> cabal.project
-    echo "allow-newer: servant-js:servant"                             >> cabal.project
-    echo "allow-newer: servant-js:servant-foreign"                     >> cabal.project
-    echo ""                                                            >> cabal.project
-    echo "source-repository-package"                                   >> cabal.project
-    echo "  type:     git"                                             >> cabal.project
-    echo "  location: https://github.com/haskell-servant/servant-auth" >> cabal.project
-    echo "  tag:      4a134c3db79293d28f8b74a02863047e41fbaf56"        >> cabal.project
-    echo ""                                                            >> cabal.project
-    echo "package servant"                                             >> cabal.project
-    echo "  tests: False"                                              >> cabal.project
-  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
-  - cat cabal.project || true
-  - cat cabal.project.local || true
-  # Building...
-  # this builds all libraries and executables (without tests/benchmarks)
-  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
-  # Building with tests and benchmarks...
-  # build & run tests, build benchmarks
-  - ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} all
-  # Testing...
-  - ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all
-  # cabal check...
-  - (cd ${PKGDIR_servant} && ${CABAL} -vnormal check)
-  - (cd ${PKGDIR_servant_client} && ${CABAL} -vnormal check)
-  - (cd ${PKGDIR_servant_docs} && ${CABAL} -vnormal check)
-  - (cd ${PKGDIR_servant_server} && ${CABAL} -vnormal check)
-  # haddock...
-  - ${CABAL} v2-haddock $WITHCOMPILER --with-haddock $HADDOCK ${TEST} ${BENCH} all
-  # Building without installed constraints for packages in global-db...
-  - rm -f cabal.project.local
-  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
-
-# REGENDATA ["-o","cabal.project.empty-line.travis.yml","--config=cabal.project.haskell-ci","--copy-fields=all","cabal.project.empty-line"]
-# EOF
diff --git a/fixtures/cabal.project.copy-fields.none b/fixtures/cabal.project.copy-fields.none
deleted file mode 100644
--- a/fixtures/cabal.project.copy-fields.none
+++ /dev/null
@@ -1,15 +0,0 @@
-packages:
-  servant/
-  servant-client/
-  servant-docs/
-  servant-server/
-
-package servant
-  tests: False
-
-constraints: foundation >= 0.14
-
-allow-newer:
-  servant-js:servant
-allow-newer:
-  servant-js:servant-foreign
diff --git a/fixtures/cabal.project.copy-fields.none.stderr b/fixtures/cabal.project.copy-fields.none.stderr
deleted file mode 100644
--- a/fixtures/cabal.project.copy-fields.none.stderr
+++ /dev/null
@@ -1,1 +0,0 @@
-*INFO* Generating Travis-CI config for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2
diff --git a/fixtures/cabal.project.copy-fields.none.travis.yml b/fixtures/cabal.project.copy-fields.none.travis.yml
deleted file mode 100644
--- a/fixtures/cabal.project.copy-fields.none.travis.yml
+++ /dev/null
@@ -1,237 +0,0 @@
-# This Travis job script has been generated by a script via
-#
-#   haskell-ci '-o' 'cabal.project.empty-line.travis.yml' '--config=cabal.project.haskell-ci' '--copy-fields=none' 'cabal.project.empty-line'
-#
-# To regenerate the script (for example after adjusting tested-with) run
-#
-#   haskell-ci regenerate
-#
-# For more information, see https://github.com/haskell-CI/haskell-ci
-#
-version: ~> 1.0
-language: c
-os: linux
-dist: xenial
-git:
-  # whether to recursively clone submodules
-  submodules: false
-cache:
-  directories:
-    - $HOME/.cabal/packages
-    - $HOME/.cabal/store
-    - $HOME/.hlint
-before_cache:
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log
-  # remove files that are regenerated by 'cabal update'
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx
-  - rm -rfv $CABALHOME/packages/head.hackage
-jobs:
-  include:
-    - compiler: ghc-8.10.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.10.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.10.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.10.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.8.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.4","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.8.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.8.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.8.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.5
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.5","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.4","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.4.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.4","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.4.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.4.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.4.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.2.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.2.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.2.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.2.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.0.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.0.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.0.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.0.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.10.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.10.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.10.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.10.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.10.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.10.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.8.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.4","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.8.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.8.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.8.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.1","cabal-install-3.2"]}}
-      os: linux
-before_install:
-  - HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//')
-  - WITHCOMPILER="-w $HC"
-  - HADDOCK=$(echo "/opt/$CC/bin/haddock" | sed 's/-/\//')
-  - HCPKG="$HC-pkg"
-  - unset CC
-  - CABAL=/opt/ghc/bin/cabal
-  - CABALHOME=$HOME/.cabal
-  - export PATH="$CABALHOME/bin:$PATH"
-  - TOP=$(pwd)
-  - "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')"
-  - echo $HCNUMVER
-  - CABAL="$CABAL -vnormal+nowrap"
-  - set -o pipefail
-  - TEST=--enable-tests
-  - BENCH=--enable-benchmarks
-  - HEADHACKAGE=false
-  - rm -f $CABALHOME/config
-  - |
-    echo "verbose: normal +nowrap +markoutput"          >> $CABALHOME/config
-    echo "remote-build-reporting: anonymous"            >> $CABALHOME/config
-    echo "write-ghc-environment-files: always"          >> $CABALHOME/config
-    echo "remote-repo-cache: $CABALHOME/packages"       >> $CABALHOME/config
-    echo "logs-dir:          $CABALHOME/logs"           >> $CABALHOME/config
-    echo "world-file:        $CABALHOME/world"          >> $CABALHOME/config
-    echo "extra-prog-path:   $CABALHOME/bin"            >> $CABALHOME/config
-    echo "symlink-bindir:    $CABALHOME/bin"            >> $CABALHOME/config
-    echo "installdir:        $CABALHOME/bin"            >> $CABALHOME/config
-    echo "build-summary:     $CABALHOME/logs/build.log" >> $CABALHOME/config
-    echo "store-dir:         $CABALHOME/store"          >> $CABALHOME/config
-    echo "install-dirs user"                            >> $CABALHOME/config
-    echo "  prefix: $CABALHOME"                         >> $CABALHOME/config
-    echo "repository hackage.haskell.org"               >> $CABALHOME/config
-    echo "  url: http://hackage.haskell.org/"           >> $CABALHOME/config
-install:
-  - ${CABAL} --version
-  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
-  - |
-    echo "program-default-options"                >> $CABALHOME/config
-    echo "  ghc-options: $GHCJOBS +RTS -M6G -RTS" >> $CABALHOME/config
-  - cat $CABALHOME/config
-  - rm -fv cabal.project cabal.project.local cabal.project.freeze
-  - travis_retry ${CABAL} v2-update -v
-  # Generate cabal.project
-  - rm -rf cabal.project cabal.project.local cabal.project.freeze
-  - touch cabal.project
-  - |
-    echo "packages: servant" >> cabal.project
-    echo "packages: servant-client" >> cabal.project
-    echo "packages: servant-docs" >> cabal.project
-    echo "packages: servant-server" >> cabal.project
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-client' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-docs' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-server' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - |
-  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
-  - cat cabal.project || true
-  - cat cabal.project.local || true
-  - if [ -f "servant/configure.ac" ]; then (cd "servant" && autoreconf -i); fi
-  - if [ -f "servant-client/configure.ac" ]; then (cd "servant-client" && autoreconf -i); fi
-  - if [ -f "servant-docs/configure.ac" ]; then (cd "servant-docs" && autoreconf -i); fi
-  - if [ -f "servant-server/configure.ac" ]; then (cd "servant-server" && autoreconf -i); fi
-  - ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH}
-  - "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
-  - rm  cabal.project.freeze
-  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} --dep -j2 all
-  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --dep -j2 all
-script:
-  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
-  # Packaging...
-  - ${CABAL} v2-sdist all
-  # Unpacking...
-  - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
-  - cd ${DISTDIR} || false
-  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \;
-  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm       '{}' \;
-  - PKGDIR_servant="$(find . -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
-  - PKGDIR_servant_client="$(find . -maxdepth 1 -type d -regex '.*/servant-client-[0-9.]*')"
-  - PKGDIR_servant_docs="$(find . -maxdepth 1 -type d -regex '.*/servant-docs-[0-9.]*')"
-  - PKGDIR_servant_server="$(find . -maxdepth 1 -type d -regex '.*/servant-server-[0-9.]*')"
-  # Generate cabal.project
-  - rm -rf cabal.project cabal.project.local cabal.project.freeze
-  - touch cabal.project
-  - |
-    echo "packages: ${PKGDIR_servant}" >> cabal.project
-    echo "packages: ${PKGDIR_servant_client}" >> cabal.project
-    echo "packages: ${PKGDIR_servant_docs}" >> cabal.project
-    echo "packages: ${PKGDIR_servant_server}" >> cabal.project
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-client' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-docs' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-server' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - |
-  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
-  - cat cabal.project || true
-  - cat cabal.project.local || true
-  # Building...
-  # this builds all libraries and executables (without tests/benchmarks)
-  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
-  # Building with tests and benchmarks...
-  # build & run tests, build benchmarks
-  - ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} all
-  # Testing...
-  - ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all
-  # cabal check...
-  - (cd ${PKGDIR_servant} && ${CABAL} -vnormal check)
-  - (cd ${PKGDIR_servant_client} && ${CABAL} -vnormal check)
-  - (cd ${PKGDIR_servant_docs} && ${CABAL} -vnormal check)
-  - (cd ${PKGDIR_servant_server} && ${CABAL} -vnormal check)
-  # haddock...
-  - ${CABAL} v2-haddock $WITHCOMPILER --with-haddock $HADDOCK ${TEST} ${BENCH} all
-  # Building without installed constraints for packages in global-db...
-  - rm -f cabal.project.local
-  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
-
-# REGENDATA ["-o","cabal.project.empty-line.travis.yml","--config=cabal.project.haskell-ci","--copy-fields=none","cabal.project.empty-line"]
-# EOF
diff --git a/fixtures/cabal.project.copy-fields.some b/fixtures/cabal.project.copy-fields.some
deleted file mode 100644
--- a/fixtures/cabal.project.copy-fields.some
+++ /dev/null
@@ -1,15 +0,0 @@
-packages:
-  servant/
-  servant-client/
-  servant-docs/
-  servant-server/
-
-package servant
-  tests: False
-
-constraints: foundation >= 0.14
-
-allow-newer:
-  servant-js:servant
-allow-newer:
-  servant-js:servant-foreign
diff --git a/fixtures/cabal.project.copy-fields.some.stderr b/fixtures/cabal.project.copy-fields.some.stderr
deleted file mode 100644
--- a/fixtures/cabal.project.copy-fields.some.stderr
+++ /dev/null
@@ -1,1 +0,0 @@
-*INFO* Generating Travis-CI config for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2
diff --git a/fixtures/cabal.project.copy-fields.some.travis.yml b/fixtures/cabal.project.copy-fields.some.travis.yml
deleted file mode 100644
--- a/fixtures/cabal.project.copy-fields.some.travis.yml
+++ /dev/null
@@ -1,243 +0,0 @@
-# This Travis job script has been generated by a script via
-#
-#   haskell-ci '-o' 'cabal.project.empty-line.travis.yml' '--config=cabal.project.haskell-ci' '--copy-fields=some' 'cabal.project.empty-line'
-#
-# To regenerate the script (for example after adjusting tested-with) run
-#
-#   haskell-ci regenerate
-#
-# For more information, see https://github.com/haskell-CI/haskell-ci
-#
-version: ~> 1.0
-language: c
-os: linux
-dist: xenial
-git:
-  # whether to recursively clone submodules
-  submodules: false
-cache:
-  directories:
-    - $HOME/.cabal/packages
-    - $HOME/.cabal/store
-    - $HOME/.hlint
-before_cache:
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log
-  # remove files that are regenerated by 'cabal update'
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx
-  - rm -rfv $CABALHOME/packages/head.hackage
-jobs:
-  include:
-    - compiler: ghc-8.10.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.10.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.10.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.10.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.8.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.4","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.8.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.8.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.8.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.5
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.5","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.4","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.4.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.4","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.4.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.4.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.4.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.2.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.2.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.2.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.2.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.0.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.0.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.0.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.0.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.10.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.10.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.10.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.10.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.10.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.10.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.8.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.4","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.8.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.8.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.8.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.1","cabal-install-3.2"]}}
-      os: linux
-before_install:
-  - HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//')
-  - WITHCOMPILER="-w $HC"
-  - HADDOCK=$(echo "/opt/$CC/bin/haddock" | sed 's/-/\//')
-  - HCPKG="$HC-pkg"
-  - unset CC
-  - CABAL=/opt/ghc/bin/cabal
-  - CABALHOME=$HOME/.cabal
-  - export PATH="$CABALHOME/bin:$PATH"
-  - TOP=$(pwd)
-  - "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')"
-  - echo $HCNUMVER
-  - CABAL="$CABAL -vnormal+nowrap"
-  - set -o pipefail
-  - TEST=--enable-tests
-  - BENCH=--enable-benchmarks
-  - HEADHACKAGE=false
-  - rm -f $CABALHOME/config
-  - |
-    echo "verbose: normal +nowrap +markoutput"          >> $CABALHOME/config
-    echo "remote-build-reporting: anonymous"            >> $CABALHOME/config
-    echo "write-ghc-environment-files: always"          >> $CABALHOME/config
-    echo "remote-repo-cache: $CABALHOME/packages"       >> $CABALHOME/config
-    echo "logs-dir:          $CABALHOME/logs"           >> $CABALHOME/config
-    echo "world-file:        $CABALHOME/world"          >> $CABALHOME/config
-    echo "extra-prog-path:   $CABALHOME/bin"            >> $CABALHOME/config
-    echo "symlink-bindir:    $CABALHOME/bin"            >> $CABALHOME/config
-    echo "installdir:        $CABALHOME/bin"            >> $CABALHOME/config
-    echo "build-summary:     $CABALHOME/logs/build.log" >> $CABALHOME/config
-    echo "store-dir:         $CABALHOME/store"          >> $CABALHOME/config
-    echo "install-dirs user"                            >> $CABALHOME/config
-    echo "  prefix: $CABALHOME"                         >> $CABALHOME/config
-    echo "repository hackage.haskell.org"               >> $CABALHOME/config
-    echo "  url: http://hackage.haskell.org/"           >> $CABALHOME/config
-install:
-  - ${CABAL} --version
-  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
-  - |
-    echo "program-default-options"                >> $CABALHOME/config
-    echo "  ghc-options: $GHCJOBS +RTS -M6G -RTS" >> $CABALHOME/config
-  - cat $CABALHOME/config
-  - rm -fv cabal.project cabal.project.local cabal.project.freeze
-  - travis_retry ${CABAL} v2-update -v
-  # Generate cabal.project
-  - rm -rf cabal.project cabal.project.local cabal.project.freeze
-  - touch cabal.project
-  - |
-    echo "packages: servant" >> cabal.project
-    echo "packages: servant-client" >> cabal.project
-    echo "packages: servant-docs" >> cabal.project
-    echo "packages: servant-server" >> cabal.project
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-client' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-docs' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-server' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - |
-    echo "constraints: foundation >= 0.14"         >> cabal.project
-    echo "allow-newer: servant-js:servant"         >> cabal.project
-    echo "allow-newer: servant-js:servant-foreign" >> cabal.project
-  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
-  - cat cabal.project || true
-  - cat cabal.project.local || true
-  - if [ -f "servant/configure.ac" ]; then (cd "servant" && autoreconf -i); fi
-  - if [ -f "servant-client/configure.ac" ]; then (cd "servant-client" && autoreconf -i); fi
-  - if [ -f "servant-docs/configure.ac" ]; then (cd "servant-docs" && autoreconf -i); fi
-  - if [ -f "servant-server/configure.ac" ]; then (cd "servant-server" && autoreconf -i); fi
-  - ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH}
-  - "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
-  - rm  cabal.project.freeze
-  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} --dep -j2 all
-  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --dep -j2 all
-script:
-  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
-  # Packaging...
-  - ${CABAL} v2-sdist all
-  # Unpacking...
-  - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
-  - cd ${DISTDIR} || false
-  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \;
-  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm       '{}' \;
-  - PKGDIR_servant="$(find . -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
-  - PKGDIR_servant_client="$(find . -maxdepth 1 -type d -regex '.*/servant-client-[0-9.]*')"
-  - PKGDIR_servant_docs="$(find . -maxdepth 1 -type d -regex '.*/servant-docs-[0-9.]*')"
-  - PKGDIR_servant_server="$(find . -maxdepth 1 -type d -regex '.*/servant-server-[0-9.]*')"
-  # Generate cabal.project
-  - rm -rf cabal.project cabal.project.local cabal.project.freeze
-  - touch cabal.project
-  - |
-    echo "packages: ${PKGDIR_servant}" >> cabal.project
-    echo "packages: ${PKGDIR_servant_client}" >> cabal.project
-    echo "packages: ${PKGDIR_servant_docs}" >> cabal.project
-    echo "packages: ${PKGDIR_servant_server}" >> cabal.project
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-client' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-docs' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-server' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - |
-    echo "constraints: foundation >= 0.14"         >> cabal.project
-    echo "allow-newer: servant-js:servant"         >> cabal.project
-    echo "allow-newer: servant-js:servant-foreign" >> cabal.project
-  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
-  - cat cabal.project || true
-  - cat cabal.project.local || true
-  # Building...
-  # this builds all libraries and executables (without tests/benchmarks)
-  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
-  # Building with tests and benchmarks...
-  # build & run tests, build benchmarks
-  - ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} all
-  # Testing...
-  - ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all
-  # cabal check...
-  - (cd ${PKGDIR_servant} && ${CABAL} -vnormal check)
-  - (cd ${PKGDIR_servant_client} && ${CABAL} -vnormal check)
-  - (cd ${PKGDIR_servant_docs} && ${CABAL} -vnormal check)
-  - (cd ${PKGDIR_servant_server} && ${CABAL} -vnormal check)
-  # haddock...
-  - ${CABAL} v2-haddock $WITHCOMPILER --with-haddock $HADDOCK ${TEST} ${BENCH} all
-  # Building without installed constraints for packages in global-db...
-  - rm -f cabal.project.local
-  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
-
-# REGENDATA ["-o","cabal.project.empty-line.travis.yml","--config=cabal.project.haskell-ci","--copy-fields=some","cabal.project.empty-line"]
-# EOF
diff --git a/fixtures/cabal.project.empty-line b/fixtures/cabal.project.empty-line
deleted file mode 100644
--- a/fixtures/cabal.project.empty-line
+++ /dev/null
@@ -1,12 +0,0 @@
-packages:
-  servant/
-  servant-client/
-  servant-docs/
-  servant-server/
-
-constraints: foundatiion >= 0.14
-allow-newer:
-  servant-js:servant
-allow-newer:
-  servant-js:servant-foreign
-allow-newer:
diff --git a/fixtures/cabal.project.empty-line.stderr b/fixtures/cabal.project.empty-line.stderr
deleted file mode 100644
--- a/fixtures/cabal.project.empty-line.stderr
+++ /dev/null
@@ -1,1 +0,0 @@
-*INFO* Generating Travis-CI config for testing for GHC versions: ghc-head 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2
diff --git a/fixtures/cabal.project.empty-line.travis.yml b/fixtures/cabal.project.empty-line.travis.yml
deleted file mode 100644
--- a/fixtures/cabal.project.empty-line.travis.yml
+++ /dev/null
@@ -1,260 +0,0 @@
-# This Travis job script has been generated by a script via
-#
-#   haskell-ci '-o' 'cabal.project.empty-line.travis.yml' '--config=cabal.project.haskell-ci' '--ghc-head' 'cabal.project.empty-line'
-#
-# To regenerate the script (for example after adjusting tested-with) run
-#
-#   haskell-ci regenerate
-#
-# For more information, see https://github.com/haskell-CI/haskell-ci
-#
-version: ~> 1.0
-language: c
-os: linux
-dist: xenial
-git:
-  # whether to recursively clone submodules
-  submodules: false
-cache:
-  directories:
-    - $HOME/.cabal/packages
-    - $HOME/.cabal/store
-    - $HOME/.hlint
-before_cache:
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log
-  # remove files that are regenerated by 'cabal update'
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx
-  - rm -rfv $CABALHOME/packages/head.hackage
-jobs:
-  include:
-    - compiler: ghc-8.10.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.10.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.10.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.10.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.8.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.4","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.8.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.8.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.8.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.5
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.5","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.4","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.4.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.4","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.4.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.4.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.4.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.2.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.2.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.2.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.2.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.0.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.0.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.0.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.0.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.10.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.10.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.10.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.10.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.10.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.10.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.8.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.4","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.8.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.8.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.8.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-head
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-head","cabal-install-head"]}}
-      os: linux
-  allow_failures:
-    - compiler: ghc-head
-before_install:
-  - HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//')
-  - WITHCOMPILER="-w $HC"
-  - HADDOCK=$(echo "/opt/$CC/bin/haddock" | sed 's/-/\//')
-  - HCPKG="$HC-pkg"
-  - unset CC
-  - CABAL=/opt/ghc/bin/cabal
-  - CABALHOME=$HOME/.cabal
-  - export PATH="$CABALHOME/bin:$PATH"
-  - TOP=$(pwd)
-  - "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')"
-  - echo $HCNUMVER
-  - CABAL="$CABAL -vnormal+nowrap"
-  - set -o pipefail
-  - TEST=--enable-tests
-  - BENCH=--enable-benchmarks
-  - HEADHACKAGE=false
-  - if [ $HCNUMVER -gt 81002 ] ; then HEADHACKAGE=true ; fi
-  - rm -f $CABALHOME/config
-  - |
-    echo "verbose: normal +nowrap +markoutput"          >> $CABALHOME/config
-    echo "remote-build-reporting: anonymous"            >> $CABALHOME/config
-    echo "write-ghc-environment-files: always"          >> $CABALHOME/config
-    echo "remote-repo-cache: $CABALHOME/packages"       >> $CABALHOME/config
-    echo "logs-dir:          $CABALHOME/logs"           >> $CABALHOME/config
-    echo "world-file:        $CABALHOME/world"          >> $CABALHOME/config
-    echo "extra-prog-path:   $CABALHOME/bin"            >> $CABALHOME/config
-    echo "symlink-bindir:    $CABALHOME/bin"            >> $CABALHOME/config
-    echo "installdir:        $CABALHOME/bin"            >> $CABALHOME/config
-    echo "build-summary:     $CABALHOME/logs/build.log" >> $CABALHOME/config
-    echo "store-dir:         $CABALHOME/store"          >> $CABALHOME/config
-    echo "install-dirs user"                            >> $CABALHOME/config
-    echo "  prefix: $CABALHOME"                         >> $CABALHOME/config
-    echo "repository hackage.haskell.org"               >> $CABALHOME/config
-    echo "  url: http://hackage.haskell.org/"           >> $CABALHOME/config
-  - |
-    if $HEADHACKAGE; then
-    echo "allow-newer: $($HCPKG list --simple-output | sed -E 's/([a-zA-Z-]+)-[0-9.]+/*:\1/g')" >> $CABALHOME/config
-    echo "repository head.hackage.ghc.haskell.org"                                        >> $CABALHOME/config
-    echo "   url: https://ghc.gitlab.haskell.org/head.hackage/"                           >> $CABALHOME/config
-    echo "   secure: True"                                                                >> $CABALHOME/config
-    echo "   root-keys: 7541f32a4ccca4f97aea3b22f5e593ba2c0267546016b992dfadcd2fe944e55d" >> $CABALHOME/config
-    echo "              26021a13b401500c8eb2761ca95c61f2d625bfef951b939a8124ed12ecf07329" >> $CABALHOME/config
-    echo "              f76d08be13e9a61a377a85e2fb63f4c5435d40f8feb3e12eb05905edb8cdea89" >> $CABALHOME/config
-    echo "   key-threshold: 3"                                                            >> $CABALHOME/config
-    fi
-install:
-  - ${CABAL} --version
-  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
-  - |
-    echo "program-default-options"                >> $CABALHOME/config
-    echo "  ghc-options: $GHCJOBS +RTS -M6G -RTS" >> $CABALHOME/config
-  - cat $CABALHOME/config
-  - rm -fv cabal.project cabal.project.local cabal.project.freeze
-  - travis_retry ${CABAL} v2-update -v
-  # Generate cabal.project
-  - rm -rf cabal.project cabal.project.local cabal.project.freeze
-  - touch cabal.project
-  - |
-    echo "packages: servant" >> cabal.project
-    echo "packages: servant-client" >> cabal.project
-    echo "packages: servant-docs" >> cabal.project
-    echo "packages: servant-server" >> cabal.project
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-client' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-docs' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-server' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - |
-    echo "constraints: foundatiion >= 0.14"        >> cabal.project
-    echo "allow-newer: servant-js:servant"         >> cabal.project
-    echo "allow-newer: servant-js:servant-foreign" >> cabal.project
-  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
-  - cat cabal.project || true
-  - cat cabal.project.local || true
-  - if [ -f "servant/configure.ac" ]; then (cd "servant" && autoreconf -i); fi
-  - if [ -f "servant-client/configure.ac" ]; then (cd "servant-client" && autoreconf -i); fi
-  - if [ -f "servant-docs/configure.ac" ]; then (cd "servant-docs" && autoreconf -i); fi
-  - if [ -f "servant-server/configure.ac" ]; then (cd "servant-server" && autoreconf -i); fi
-  - ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH}
-  - "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
-  - rm  cabal.project.freeze
-  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} --dep -j2 all
-  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --dep -j2 all
-script:
-  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
-  # Packaging...
-  - ${CABAL} v2-sdist all
-  # Unpacking...
-  - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
-  - cd ${DISTDIR} || false
-  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \;
-  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm       '{}' \;
-  - PKGDIR_servant="$(find . -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
-  - PKGDIR_servant_client="$(find . -maxdepth 1 -type d -regex '.*/servant-client-[0-9.]*')"
-  - PKGDIR_servant_docs="$(find . -maxdepth 1 -type d -regex '.*/servant-docs-[0-9.]*')"
-  - PKGDIR_servant_server="$(find . -maxdepth 1 -type d -regex '.*/servant-server-[0-9.]*')"
-  # Generate cabal.project
-  - rm -rf cabal.project cabal.project.local cabal.project.freeze
-  - touch cabal.project
-  - |
-    echo "packages: ${PKGDIR_servant}" >> cabal.project
-    echo "packages: ${PKGDIR_servant_client}" >> cabal.project
-    echo "packages: ${PKGDIR_servant_docs}" >> cabal.project
-    echo "packages: ${PKGDIR_servant_server}" >> cabal.project
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-client' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-docs' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-server' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - |
-    echo "constraints: foundatiion >= 0.14"        >> cabal.project
-    echo "allow-newer: servant-js:servant"         >> cabal.project
-    echo "allow-newer: servant-js:servant-foreign" >> cabal.project
-  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
-  - cat cabal.project || true
-  - cat cabal.project.local || true
-  # Building...
-  # this builds all libraries and executables (without tests/benchmarks)
-  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
-  # Building with tests and benchmarks...
-  # build & run tests, build benchmarks
-  - ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} all
-  # Testing...
-  - ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all
-  # cabal check...
-  - (cd ${PKGDIR_servant} && ${CABAL} -vnormal check)
-  - (cd ${PKGDIR_servant_client} && ${CABAL} -vnormal check)
-  - (cd ${PKGDIR_servant_docs} && ${CABAL} -vnormal check)
-  - (cd ${PKGDIR_servant_server} && ${CABAL} -vnormal check)
-  # haddock...
-  - ${CABAL} v2-haddock $WITHCOMPILER --with-haddock $HADDOCK ${TEST} ${BENCH} all
-  # Building without installed constraints for packages in global-db...
-  - rm -f cabal.project.local
-  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
-
-# REGENDATA ["-o","cabal.project.empty-line.travis.yml","--config=cabal.project.haskell-ci","--ghc-head","cabal.project.empty-line"]
-# EOF
diff --git a/fixtures/cabal.project.fail-versions b/fixtures/cabal.project.fail-versions
deleted file mode 100644
--- a/fixtures/cabal.project.fail-versions
+++ /dev/null
@@ -1,7 +0,0 @@
-packages: servant/
-  servant-client/
-  servant-client-core/
-  servant-docs/
-  servant-foreign/
-  servant-server/
-  doc/tutorial/
diff --git a/fixtures/cabal.project.fail-versions.stderr b/fixtures/cabal.project.fail-versions.stderr
deleted file mode 100644
--- a/fixtures/cabal.project.fail-versions.stderr
+++ /dev/null
@@ -1,3 +0,0 @@
-*ERROR* servant-client-core is missing tested-with annotations for: ghc-7.8.1,ghc-7.8.2,ghc-7.8.3,ghc-7.8.4
-*ERROR* servant-foreign is missing tested-with annotations for: ghc-7.8.1,ghc-7.8.2,ghc-7.8.3,ghc-7.8.4
-*ERROR* tutorial is missing tested-with annotations for: ghc-7.8.1,ghc-7.8.2,ghc-7.8.3,ghc-7.8.4
diff --git a/fixtures/cabal.project.haskell-ci b/fixtures/cabal.project.haskell-ci
deleted file mode 100644
--- a/fixtures/cabal.project.haskell-ci
+++ /dev/null
@@ -1,2 +0,0 @@
--- Common configuration options for .travis.yml files in fixtures/
-insert-version: False
diff --git a/fixtures/cabal.project.messy b/fixtures/cabal.project.messy
deleted file mode 100644
--- a/fixtures/cabal.project.messy
+++ /dev/null
@@ -1,6 +0,0 @@
-packages: servant/,
-
-  servant-client/
- 
- ,
-     servant-docs/,servant-server/
diff --git a/fixtures/cabal.project.messy.stderr b/fixtures/cabal.project.messy.stderr
deleted file mode 100644
--- a/fixtures/cabal.project.messy.stderr
+++ /dev/null
@@ -1,1 +0,0 @@
-*INFO* Generating Travis-CI config for testing for GHC versions: ghc-head 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2
diff --git a/fixtures/cabal.project.messy.travis.yml b/fixtures/cabal.project.messy.travis.yml
deleted file mode 100644
--- a/fixtures/cabal.project.messy.travis.yml
+++ /dev/null
@@ -1,254 +0,0 @@
-# This Travis job script has been generated by a script via
-#
-#   haskell-ci '-o' 'cabal.project.messy.travis.yml' '--config=cabal.project.haskell-ci' '--ghc-head' '--apt=fftw3-dev' '--installed=-all +deepseq' 'cabal.project.messy'
-#
-# To regenerate the script (for example after adjusting tested-with) run
-#
-#   haskell-ci regenerate
-#
-# For more information, see https://github.com/haskell-CI/haskell-ci
-#
-version: ~> 1.0
-language: c
-os: linux
-dist: xenial
-git:
-  # whether to recursively clone submodules
-  submodules: false
-cache:
-  directories:
-    - $HOME/.cabal/packages
-    - $HOME/.cabal/store
-    - $HOME/.hlint
-before_cache:
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log
-  # remove files that are regenerated by 'cabal update'
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx
-  - rm -rfv $CABALHOME/packages/head.hackage
-jobs:
-  include:
-    - compiler: ghc-8.10.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.10.2","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-8.10.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.10.1","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-8.8.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.4","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-8.8.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.3","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-8.8.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.2","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-8.8.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.1","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-8.6.5
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.5","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-8.6.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.4","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-8.6.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.3","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-8.6.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.2","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-8.6.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.1","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-8.4.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.4","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-8.4.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.3","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-8.4.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.2","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-8.4.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.1","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-8.2.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.2.2","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-8.2.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.2.1","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-8.0.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.0.2","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-8.0.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.0.1","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-7.10.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.10.3","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-7.10.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.10.2","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-7.10.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.10.1","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-7.8.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.4","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-7.8.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.3","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-7.8.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.2","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-7.8.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.1","cabal-install-3.2","fftw3-dev"]}}
-      os: linux
-    - compiler: ghc-head
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-head","cabal-install-head","fftw3-dev"]}}
-      os: linux
-  allow_failures:
-    - compiler: ghc-head
-before_install:
-  - HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//')
-  - WITHCOMPILER="-w $HC"
-  - HADDOCK=$(echo "/opt/$CC/bin/haddock" | sed 's/-/\//')
-  - HCPKG="$HC-pkg"
-  - unset CC
-  - CABAL=/opt/ghc/bin/cabal
-  - CABALHOME=$HOME/.cabal
-  - export PATH="$CABALHOME/bin:$PATH"
-  - TOP=$(pwd)
-  - "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')"
-  - echo $HCNUMVER
-  - CABAL="$CABAL -vnormal+nowrap"
-  - set -o pipefail
-  - TEST=--enable-tests
-  - BENCH=--enable-benchmarks
-  - HEADHACKAGE=false
-  - if [ $HCNUMVER -gt 81002 ] ; then HEADHACKAGE=true ; fi
-  - rm -f $CABALHOME/config
-  - |
-    echo "verbose: normal +nowrap +markoutput"          >> $CABALHOME/config
-    echo "remote-build-reporting: anonymous"            >> $CABALHOME/config
-    echo "write-ghc-environment-files: always"          >> $CABALHOME/config
-    echo "remote-repo-cache: $CABALHOME/packages"       >> $CABALHOME/config
-    echo "logs-dir:          $CABALHOME/logs"           >> $CABALHOME/config
-    echo "world-file:        $CABALHOME/world"          >> $CABALHOME/config
-    echo "extra-prog-path:   $CABALHOME/bin"            >> $CABALHOME/config
-    echo "symlink-bindir:    $CABALHOME/bin"            >> $CABALHOME/config
-    echo "installdir:        $CABALHOME/bin"            >> $CABALHOME/config
-    echo "build-summary:     $CABALHOME/logs/build.log" >> $CABALHOME/config
-    echo "store-dir:         $CABALHOME/store"          >> $CABALHOME/config
-    echo "install-dirs user"                            >> $CABALHOME/config
-    echo "  prefix: $CABALHOME"                         >> $CABALHOME/config
-    echo "repository hackage.haskell.org"               >> $CABALHOME/config
-    echo "  url: http://hackage.haskell.org/"           >> $CABALHOME/config
-  - |
-    if $HEADHACKAGE; then
-    echo "allow-newer: $($HCPKG list --simple-output | sed -E 's/([a-zA-Z-]+)-[0-9.]+/*:\1/g')" >> $CABALHOME/config
-    echo "repository head.hackage.ghc.haskell.org"                                        >> $CABALHOME/config
-    echo "   url: https://ghc.gitlab.haskell.org/head.hackage/"                           >> $CABALHOME/config
-    echo "   secure: True"                                                                >> $CABALHOME/config
-    echo "   root-keys: 7541f32a4ccca4f97aea3b22f5e593ba2c0267546016b992dfadcd2fe944e55d" >> $CABALHOME/config
-    echo "              26021a13b401500c8eb2761ca95c61f2d625bfef951b939a8124ed12ecf07329" >> $CABALHOME/config
-    echo "              f76d08be13e9a61a377a85e2fb63f4c5435d40f8feb3e12eb05905edb8cdea89" >> $CABALHOME/config
-    echo "   key-threshold: 3"                                                            >> $CABALHOME/config
-    fi
-install:
-  - ${CABAL} --version
-  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
-  - |
-    echo "program-default-options"                >> $CABALHOME/config
-    echo "  ghc-options: $GHCJOBS +RTS -M6G -RTS" >> $CABALHOME/config
-  - cat $CABALHOME/config
-  - rm -fv cabal.project cabal.project.local cabal.project.freeze
-  - travis_retry ${CABAL} v2-update -v
-  # Generate cabal.project
-  - rm -rf cabal.project cabal.project.local cabal.project.freeze
-  - touch cabal.project
-  - |
-    echo "packages: servant" >> cabal.project
-    echo "packages: servant-client" >> cabal.project
-    echo "packages: servant-docs" >> cabal.project
-    echo "packages: servant-server" >> cabal.project
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-client' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-docs' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-server' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - |
-  - "for pkg in deepseq; do echo \"constraints: $pkg installed\" >> cabal.project.local; done"
-  - cat cabal.project || true
-  - cat cabal.project.local || true
-  - if [ -f "servant/configure.ac" ]; then (cd "servant" && autoreconf -i); fi
-  - if [ -f "servant-client/configure.ac" ]; then (cd "servant-client" && autoreconf -i); fi
-  - if [ -f "servant-docs/configure.ac" ]; then (cd "servant-docs" && autoreconf -i); fi
-  - if [ -f "servant-server/configure.ac" ]; then (cd "servant-server" && autoreconf -i); fi
-  - ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH}
-  - "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
-  - rm  cabal.project.freeze
-  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} --dep -j2 all
-  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --dep -j2 all
-script:
-  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
-  # Packaging...
-  - ${CABAL} v2-sdist all
-  # Unpacking...
-  - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
-  - cd ${DISTDIR} || false
-  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \;
-  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm       '{}' \;
-  - PKGDIR_servant="$(find . -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
-  - PKGDIR_servant_client="$(find . -maxdepth 1 -type d -regex '.*/servant-client-[0-9.]*')"
-  - PKGDIR_servant_docs="$(find . -maxdepth 1 -type d -regex '.*/servant-docs-[0-9.]*')"
-  - PKGDIR_servant_server="$(find . -maxdepth 1 -type d -regex '.*/servant-server-[0-9.]*')"
-  # Generate cabal.project
-  - rm -rf cabal.project cabal.project.local cabal.project.freeze
-  - touch cabal.project
-  - |
-    echo "packages: ${PKGDIR_servant}" >> cabal.project
-    echo "packages: ${PKGDIR_servant_client}" >> cabal.project
-    echo "packages: ${PKGDIR_servant_docs}" >> cabal.project
-    echo "packages: ${PKGDIR_servant_server}" >> cabal.project
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-client' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-docs' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-server' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - |
-  - "for pkg in deepseq; do echo \"constraints: $pkg installed\" >> cabal.project.local; done"
-  - cat cabal.project || true
-  - cat cabal.project.local || true
-  # Building...
-  # this builds all libraries and executables (without tests/benchmarks)
-  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
-  # Building with tests and benchmarks...
-  # build & run tests, build benchmarks
-  - ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} all
-  # Testing...
-  - ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all
-  # cabal check...
-  - (cd ${PKGDIR_servant} && ${CABAL} -vnormal check)
-  - (cd ${PKGDIR_servant_client} && ${CABAL} -vnormal check)
-  - (cd ${PKGDIR_servant_docs} && ${CABAL} -vnormal check)
-  - (cd ${PKGDIR_servant_server} && ${CABAL} -vnormal check)
-  # haddock...
-  - ${CABAL} v2-haddock $WITHCOMPILER --with-haddock $HADDOCK ${TEST} ${BENCH} all
-  # Building without installed constraints for packages in global-db...
-  - rm -f cabal.project.local
-  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
-
-# REGENDATA ["-o","cabal.project.messy.travis.yml","--config=cabal.project.haskell-ci","--ghc-head","--apt=fftw3-dev","--installed=-all +deepseq","cabal.project.messy"]
-# EOF
diff --git a/fixtures/cabal.project.travis-patch b/fixtures/cabal.project.travis-patch
deleted file mode 100644
--- a/fixtures/cabal.project.travis-patch
+++ /dev/null
@@ -1,1 +0,0 @@
-packages: servant
diff --git a/fixtures/cabal.project.travis-patch.patch b/fixtures/cabal.project.travis-patch.patch
deleted file mode 100644
--- a/fixtures/cabal.project.travis-patch.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/fixtures/cabal.project.travis-patch.travis.yml b/fixtures/cabal.project.travis-patch.travis.yml
-index 9a725c1..0554fed 100644
---- a/fixtures/cabal.project.travis-patch.travis.yml
-+++ b/fixtures/cabal.project.travis-patch.travis.yml
-@@ -8,7 +8,7 @@
- #
- language: c
- dist: xenial
--git:
-+ git:
-   # whether to recursively clone submodules
-   submodules: false
- cache:
diff --git a/fixtures/cabal.project.travis-patch.stderr b/fixtures/cabal.project.travis-patch.stderr
deleted file mode 100644
--- a/fixtures/cabal.project.travis-patch.stderr
+++ /dev/null
@@ -1,1 +0,0 @@
-*INFO* Generating Travis-CI config for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2
diff --git a/fixtures/cabal.project.travis-patch.travis.yml b/fixtures/cabal.project.travis-patch.travis.yml
deleted file mode 100644
--- a/fixtures/cabal.project.travis-patch.travis.yml
+++ /dev/null
@@ -1,210 +0,0 @@
-# This Travis job script has been generated by a script via
-#
-#   haskell-ci '--config=cabal.project.haskell-ci' '--travis-patches=cabal.project.travis-patch.patch' 'cabal.project.travis-patch'
-#
-# To regenerate the script (for example after adjusting tested-with) run
-#
-#   haskell-ci regenerate
-#
-# For more information, see https://github.com/haskell-CI/haskell-ci
-#
-version: ~> 1.0
-language: c
-os: linux
-dist: xenial
- git:
-  # whether to recursively clone submodules
-  submodules: false
-cache:
-  directories:
-    - $HOME/.cabal/packages
-    - $HOME/.cabal/store
-    - $HOME/.hlint
-before_cache:
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log
-  # remove files that are regenerated by 'cabal update'
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar
-  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx
-  - rm -rfv $CABALHOME/packages/head.hackage
-jobs:
-  include:
-    - compiler: ghc-8.10.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.10.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.10.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.10.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.8.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.4","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.8.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.8.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.8.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.5
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.5","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.4","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.6.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.4.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.4","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.4.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.4.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.4.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.2.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.2.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.2.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.2.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.0.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.0.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-8.0.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.0.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.10.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.10.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.10.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.10.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.10.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.10.1","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.8.4
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.4","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.8.3
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.3","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.8.2
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.2","cabal-install-3.2"]}}
-      os: linux
-    - compiler: ghc-7.8.1
-      addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.1","cabal-install-3.2"]}}
-      os: linux
-before_install:
-  - HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//')
-  - WITHCOMPILER="-w $HC"
-  - HADDOCK=$(echo "/opt/$CC/bin/haddock" | sed 's/-/\//')
-  - HCPKG="$HC-pkg"
-  - unset CC
-  - CABAL=/opt/ghc/bin/cabal
-  - CABALHOME=$HOME/.cabal
-  - export PATH="$CABALHOME/bin:$PATH"
-  - TOP=$(pwd)
-  - "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')"
-  - echo $HCNUMVER
-  - CABAL="$CABAL -vnormal+nowrap"
-  - set -o pipefail
-  - TEST=--enable-tests
-  - BENCH=--enable-benchmarks
-  - HEADHACKAGE=false
-  - rm -f $CABALHOME/config
-  - |
-    echo "verbose: normal +nowrap +markoutput"          >> $CABALHOME/config
-    echo "remote-build-reporting: anonymous"            >> $CABALHOME/config
-    echo "write-ghc-environment-files: always"          >> $CABALHOME/config
-    echo "remote-repo-cache: $CABALHOME/packages"       >> $CABALHOME/config
-    echo "logs-dir:          $CABALHOME/logs"           >> $CABALHOME/config
-    echo "world-file:        $CABALHOME/world"          >> $CABALHOME/config
-    echo "extra-prog-path:   $CABALHOME/bin"            >> $CABALHOME/config
-    echo "symlink-bindir:    $CABALHOME/bin"            >> $CABALHOME/config
-    echo "installdir:        $CABALHOME/bin"            >> $CABALHOME/config
-    echo "build-summary:     $CABALHOME/logs/build.log" >> $CABALHOME/config
-    echo "store-dir:         $CABALHOME/store"          >> $CABALHOME/config
-    echo "install-dirs user"                            >> $CABALHOME/config
-    echo "  prefix: $CABALHOME"                         >> $CABALHOME/config
-    echo "repository hackage.haskell.org"               >> $CABALHOME/config
-    echo "  url: http://hackage.haskell.org/"           >> $CABALHOME/config
-install:
-  - ${CABAL} --version
-  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
-  - |
-    echo "program-default-options"                >> $CABALHOME/config
-    echo "  ghc-options: $GHCJOBS +RTS -M6G -RTS" >> $CABALHOME/config
-  - cat $CABALHOME/config
-  - rm -fv cabal.project cabal.project.local cabal.project.freeze
-  - travis_retry ${CABAL} v2-update -v
-  # Generate cabal.project
-  - rm -rf cabal.project cabal.project.local cabal.project.freeze
-  - touch cabal.project
-  - |
-    echo "packages: servant" >> cabal.project
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - |
-  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
-  - cat cabal.project || true
-  - cat cabal.project.local || true
-  - if [ -f "servant/configure.ac" ]; then (cd "servant" && autoreconf -i); fi
-  - ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH}
-  - "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
-  - rm  cabal.project.freeze
-  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} --dep -j2 all
-  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --dep -j2 all
-script:
-  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
-  # Packaging...
-  - ${CABAL} v2-sdist all
-  # Unpacking...
-  - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
-  - cd ${DISTDIR} || false
-  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \;
-  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm       '{}' \;
-  - PKGDIR_servant="$(find . -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
-  # Generate cabal.project
-  - rm -rf cabal.project cabal.project.local cabal.project.freeze
-  - touch cabal.project
-  - |
-    echo "packages: ${PKGDIR_servant}" >> cabal.project
-  - if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant' >> cabal.project ; fi
-  - "if [ $HCNUMVER -ge 80200 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
-  - |
-  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
-  - cat cabal.project || true
-  - cat cabal.project.local || true
-  # Building...
-  # this builds all libraries and executables (without tests/benchmarks)
-  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
-  # Building with tests and benchmarks...
-  # build & run tests, build benchmarks
-  - ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} all
-  # Testing...
-  - ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all
-  # cabal check...
-  - (cd ${PKGDIR_servant} && ${CABAL} -vnormal check)
-  # haddock...
-  - ${CABAL} v2-haddock $WITHCOMPILER --with-haddock $HADDOCK ${TEST} ${BENCH} all
-  # Building without installed constraints for packages in global-db...
-  - rm -f cabal.project.local
-  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
-
-# REGENDATA ["--config=cabal.project.haskell-ci","--travis-patches=cabal.project.travis-patch.patch","cabal.project.travis-patch"]
-# EOF
diff --git a/fixtures/copy-fields-all.args b/fixtures/copy-fields-all.args
new file mode 100644
--- /dev/null
+++ b/fixtures/copy-fields-all.args
@@ -0,0 +1,1 @@
+--copy-fields=all
diff --git a/fixtures/copy-fields-all.bash b/fixtures/copy-fields-all.bash
new file mode 100644
--- /dev/null
+++ b/fixtures/copy-fields-all.bash
@@ -0,0 +1,552 @@
+# SUCCESS
+# *INFO* Generating Bash script for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+#!/bin/bash
+# shellcheck disable=SC2086,SC2016,SC2046
+# REGENDATA ["--copy-fields=all","bash","copy-fields-all.project"]
+
+set -o pipefail
+
+# Mode
+##############################################################################
+
+if [ "$1" = "indocker" ]; then
+    INDOCKER=true
+    shift
+else
+    INDOCKER=false
+fi
+
+# Run configuration
+##############################################################################
+
+CFG_CABAL_STORE_CACHE=""
+CFG_CABAL_REPO_CACHE=""
+CFG_JOBS="8.10.4 8.10.3 8.10.2 8.10.1 8.8.4 8.8.3 8.8.2 8.8.1 8.6.5 8.6.4 8.6.3 8.6.2 8.6.1 8.4.4 8.4.3 8.4.2 8.4.1 8.2.2 8.2.1 8.0.2 8.0.1 7.10.3 7.10.2 7.10.1 7.8.4 7.8.3 7.8.2 7.8.1"
+CFG_CABAL_UPDATE=false
+
+SCRIPT_NAME=$(basename "$0")
+START_TIME="$(date +'%s')"
+
+XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config}
+
+# Job configuration
+##############################################################################
+
+GHC_VERSION="non-existing"
+CABAL_VERSION=3.2
+HEADHACKAGE=false
+
+# Locale
+##############################################################################
+
+export LC_ALL=C.UTF-8
+
+# Utilities
+##############################################################################
+
+SGR_RED='\033[1;31m'
+SGR_GREEN='\033[1;32m'
+SGR_BLUE='\033[1;34m'
+SGR_CYAN='\033[1;96m'
+SGR_RESET='\033[0m' # No Color
+
+put_info() {
+    printf "$SGR_CYAN%s$SGR_RESET\n" "### $*"
+}
+
+put_error() {
+    printf "$SGR_RED%s$SGR_RESET\n" "!!! $*"
+}
+
+run_cmd() {
+    local PRETTYCMD="$*"
+    local PROMPT
+    if $INDOCKER; then
+        PROMPT="$(pwd) >>>"
+    else
+        PROMPT=">>>"
+    fi
+
+    printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+
+    local start_time end_time cmd_duration total_duration
+    start_time=$(date +'%s')
+
+    "$@"
+    local RET=$?
+
+    end_time=$(date +'%s')
+    cmd_duration=$((end_time - start_time))
+    total_duration=$((end_time - START_TIME))
+
+    cmd_min=$((cmd_duration / 60))
+    cmd_sec=$((cmd_duration % 60))
+
+    total_min=$((total_duration / 60))
+    total_sec=$((total_duration % 60))
+
+    if [ $RET -eq 0 ]; then
+        printf "$SGR_GREEN%s$SGR_RESET (%dm%02ds; %dm%02ds)\n" "<<< $PRETTYCMD" "$cmd_min" "$cmd_sec" "$total_min" "$total_sec"
+    else
+        printf "$SGR_RED%s$SGR_RESET\n" "!!! $PRETTYCMD"
+        exit 1
+    fi
+}
+
+run_cmd_if() {
+    local COND=$1
+    shift
+
+    if [ $COND -eq 1 ]; then
+        run_cmd "$@"
+    else
+        local PRETTYCMD="$*"
+        local PROMPT
+        PROMPT="$(pwd) (skipping) >>>"
+
+        printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+    fi
+}
+
+run_cmd_unchecked() {
+    local PRETTYCMD="$*"
+    local PROMPT
+    if $INDOCKER; then
+        PROMPT="$(pwd) >>>"
+    else
+        PROMPT=">>>"
+    fi
+
+    printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+
+    local start_time end_time cmd_duration total_duration cmd_min cmd_sec total_min total_sec
+    start_time=$(date +'%s')
+
+    "$@"
+
+    end_time=$(date +'%s')
+    cmd_duration=$((end_time - start_time))
+    total_duration=$((end_time - START_TIME))
+
+    cmd_min=$((cmd_duration / 60))
+    cmd_sec=$((cmd_duration % 60))
+
+    total_min=$((total_duration / 60))
+    total_sec=$((total_duration % 60))
+
+    printf "$SGR_GREEN%s$SGR_RESET (%dm%02ds; %dm%02ds)\n" "<<< $PRETTYCMD" "$cmd_min" "$cmd_sec" "$total_min" "$total_sec"
+}
+
+change_dir() {
+    local DIR=$1
+    if [ -d "$DIR" ]; then
+        printf "$SGR_BLUE%s$SGR_RESET\n" "change directory to $DIR"
+        cd "$DIR" || exit 1
+    else
+        printf "$SGR_RED%s$SGR_RESET\n" "!!! cd $DIR"
+        exit 1
+    fi
+}
+
+change_dir_if() {
+    local COND=$1
+    local DIR=$2
+
+    if [ $COND -ne 0 ]; then
+        change_dir "$DIR"
+    fi
+}
+
+echo_to() {
+    local DEST=$1
+    local CONTENTS=$2
+
+    echo "$CONTENTS" >> "$DEST"
+}
+
+echo_if_to() {
+    local COND=$1
+    local DEST=$2
+    local CONTENTS=$3
+
+    if [ $COND -ne 0 ]; then
+        echo_to "$DEST" "$CONTENTS"
+    fi
+}
+
+install_cabalplan() {
+    put_info "installing cabal-plan"
+
+    if [ ! -e $CABAL_REPOCACHE/downloads/cabal-plan ]; then
+        curl -L https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > /tmp/cabal-plan.xz || exit 1
+        (cd /tmp && echo "de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc  cabal-plan.xz" | sha256sum -c -)|| exit 1
+        mkdir -p $CABAL_REPOCACHE/downloads
+        xz -d < /tmp/cabal-plan.xz > $CABAL_REPOCACHE/downloads/cabal-plan || exit 1
+        chmod a+x $CABAL_REPOCACHE/downloads/cabal-plan || exit 1
+    fi
+
+    mkdir -p $CABAL_DIR/bin || exit 1
+    ln -s $CABAL_REPOCACHE/downloads/cabal-plan $CABAL_DIR/bin/cabal-plan || exit 1
+}
+
+# Help
+##############################################################################
+
+show_usage() {
+cat <<EOF
+./haskell-ci.sh - build & test
+
+Usage: ./haskell-ci.sh [options]
+  A script to run automated checks locally (using Docker)
+
+Available options:
+  --jobs JOBS               Jobs to run (default: $CFG_JOBS)
+  --cabal-store-cache PATH  Directory to use for cabal-store-cache
+  --cabal-repo-cache PATH   Directory to use for cabal-repo-cache
+  --skip-cabal-update       Skip cabal update (useful with --cabal-repo-cache)
+  --no-skip-cabal-update
+  --help                    Print this message
+
+EOF
+}
+
+# getopt
+#######################################################################
+
+process_cli_options() {
+    while [ $# -gt 0 ]; do
+        arg=$1
+        case $arg in
+            --help)
+                show_usage
+                exit
+                ;;
+            --jobs)
+                CFG_JOBS=$2
+                shift
+                shift
+                ;;
+            --cabal-store-cache)
+                CFG_CABAL_STORE_CACHE=$2
+                shift
+                shift
+                ;;
+            --cabal-repo-cache)
+                CFG_CABAL_REPO_CACHE=$2
+                shift
+                shift
+                ;;
+            --skip-cabal-update)
+                CFG_CABAL_UPDATE=false
+                shift
+                ;;
+            --no-skip-cabal-update)
+                CFG_CABAL_UPDATE=true
+                shift
+                ;;
+            *)
+                echo "Unknown option $arg"
+                exit 1
+        esac
+    done
+}
+
+process_indocker_options () {
+    while [ $# -gt 0 ]; do
+        arg=$1
+
+        case $arg in
+            --ghc-version)
+                GHC_VERSION=$2
+                shift
+                shift
+                ;;
+            --cabal-version)
+                CABAL_VERSION=$2
+                shift
+                shift
+                ;;
+            --start-time)
+                START_TIME=$2
+                shift
+                shift
+                ;;
+            --cabal-update)
+                CABAL_UPDATE=$2
+                shift
+                shift
+                ;;
+            *)
+                echo "Unknown option $arg"
+                exit 1
+        esac
+    done
+}
+
+if $INDOCKER; then
+    process_indocker_options "$@"
+
+else
+    if [ -f "$XDG_CONFIG_HOME/haskell-ci/bash.config" ]; then
+        process_cli_options $(cat "$XDG_CONFIG_HOME/haskell-ci/bash.config")
+    fi
+
+    process_cli_options "$@"
+
+    put_info "jobs:              $CFG_JOBS"
+    put_info "cabal-store-cache: $CFG_CABAL_STORE_CACHE"
+    put_info "cabal-repo-cache:  $CFG_CABAL_REPO_CACHE"
+    put_info "cabal-update:      $CFG_CABAL_UPDATE"
+fi
+
+# Constants
+##############################################################################
+
+SRCDIR=/hsci/src
+BUILDDIR=/hsci/build
+CABAL_DIR="$BUILDDIR/cabal"
+CABAL_REPOCACHE=/hsci/cabal-repocache
+CABAL_STOREDIR=/hsci/store
+
+# Docker invoke
+##############################################################################
+
+# if cache directory is specified, use it.
+# Otherwise use another tmpfs host
+if [ -z "$CFG_CABAL_STORE_CACHE" ]; then
+    CABALSTOREARG="--tmpfs $CABAL_STOREDIR:exec"
+else
+    CABALSTOREARG="--volume $CFG_CABAL_STORE_CACHE:$CABAL_STOREDIR"
+fi
+
+if [ -z "$CFG_CABAL_REPO_CACHE" ]; then
+    CABALREPOARG="--tmpfs $CABAL_REPOCACHE:exec"
+else
+    CABALREPOARG="--volume $CFG_CABAL_REPO_CACHE:$CABAL_REPOCACHE"
+fi
+
+echo_docker_cmd() {
+    local GHCVER=$1
+
+    # TODO: mount /hsci/src:ro (readonly)
+    echo docker run \
+        --tty \
+        --interactive \
+        --rm \
+        --label haskell-ci \
+        --volume "$(pwd):/hsci/src" \
+        $CABALSTOREARG \
+        $CABALREPOARG \
+        --tmpfs /tmp:exec \
+        --tmpfs /hsci/build:exec \
+        --workdir /hsci/build \
+        "phadej/ghc:$GHCVER-bionic" \
+        "/bin/bash" "/hsci/src/$SCRIPT_NAME" indocker \
+        --ghc-version "$GHCVER" \
+        --cabal-update "$CFG_CABAL_UPDATE" \
+        --start-time "$START_TIME"
+}
+
+# if we are not in docker, loop through jobs
+if ! $INDOCKER; then
+    for JOB in $CFG_JOBS; do
+        put_info "Running in docker: $JOB"
+        run_cmd $(echo_docker_cmd "$JOB")
+    done
+
+    run_cmd echo "ALL OK"
+    exit 0
+fi
+
+# Otherwise we are in docker, and the rest of script executes
+put_info "In docker"
+
+# Environment
+##############################################################################
+
+GHCDIR=/opt/ghc/$GHC_VERSION
+
+HC=$GHCDIR/bin/ghc
+HCPKG=$GHCDIR/bin/ghc-pkg
+HADDOCK=$GHCDIR/bin/haddock
+
+CABAL=/opt/cabal/$CABAL_VERSION/bin/cabal
+
+CABAL="$CABAL -vnormal+nowrap"
+
+export CABAL_DIR
+export CABAL_CONFIG="$BUILDDIR/cabal/config"
+
+PATH="$CABAL_DIR/bin:$PATH"
+
+# HCNUMVER
+HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
+GHCJSARITH=0
+
+put_info "HCNUMVER: $HCNUMVER"
+
+# Args for shorter/nicer commands
+if [ 1 -ne 0 ] ; then ARG_TESTS=--enable-tests; else ARG_TESTS=--disable-tests; fi
+if [ 1 -ne 0 ] ; then ARG_BENCH=--enable-benchmarks; else ARG_BENCH=--disable-benchmarks; fi
+ARG_COMPILER="--ghc --with-compiler=$HC"
+
+put_info "tests/benchmarks: $ARG_TESTS $ARG_BENCH"
+
+# Apt dependencies
+##############################################################################
+
+
+# Cabal config
+##############################################################################
+
+mkdir -p $BUILDDIR/cabal
+
+cat > $BUILDDIR/cabal/config <<EOF
+remote-build-reporting: anonymous
+write-ghc-environment-files: always
+remote-repo-cache: $CABAL_REPOCACHE
+logs-dir:          $CABAL_DIR/logs
+world-file:        $CABAL_DIR/world
+extra-prog-path:   $CABAL_DIR/bin
+symlink-bindir:    $CABAL_DIR/bin
+installdir:        $CABAL_DIR/bin
+build-summary:     $CABAL_DIR/logs/build.log
+store-dir:         $CABAL_STOREDIR
+install-dirs user
+  prefix: $CABAL_DIR
+repository hackage.haskell.org
+  url: http://hackage.haskell.org/
+EOF
+
+if $HEADHACKAGE; then
+    put_error "head.hackage is not implemented"
+    exit 1
+fi
+
+run_cmd cat "$BUILDDIR/cabal/config"
+
+# Version
+##############################################################################
+
+put_info "Versions"
+run_cmd $HC --version
+run_cmd_unchecked $HC --print-project-git-commit-id
+run_cmd $CABAL --version
+
+# Build script
+##############################################################################
+
+# update cabal index
+if $CABAL_UPDATE; then
+    put_info "Updating Hackage index"
+    run_cmd $CABAL v2-update -v
+fi
+
+# install cabal-plan
+install_cabalplan
+run_cmd cabal-plan --version
+
+# initial cabal.project for sdist
+put_info "initial cabal.project for sdist"
+change_dir "$BUILDDIR"
+run_cmd touch cabal.project
+echo_to cabal.project "packages: $SRCDIR/servant"
+echo_to cabal.project "packages: $SRCDIR/servant-client"
+echo_to cabal.project "packages: $SRCDIR/servant-docs"
+echo_to cabal.project "packages: $SRCDIR/servant-server"
+run_cmd cat cabal.project
+
+# sdist
+put_info "sdist"
+run_cmd mkdir -p "$BUILDDIR/sdist"
+run_cmd $CABAL sdist all --output-dir "$BUILDDIR/sdist"
+
+# unpack
+put_info "unpack"
+change_dir "$BUILDDIR"
+run_cmd mkdir -p "$BUILDDIR/unpacked"
+run_cmd find "$BUILDDIR/sdist" -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C "$BUILDDIR/unpacked" -xzvf {} \;
+
+# generate cabal.project
+put_info "generate cabal.project"
+PKGDIR_servant="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+PKGDIR_servant_client="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-client-[0-9.]*')"
+PKGDIR_servant_docs="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-docs-[0-9.]*')"
+PKGDIR_servant_server="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-server-[0-9.]*')"
+run_cmd touch cabal.project
+run_cmd touch cabal.project.local
+echo_to cabal.project "packages: ${PKGDIR_servant}"
+echo_to cabal.project "packages: ${PKGDIR_servant_client}"
+echo_to cabal.project "packages: ${PKGDIR_servant_docs}"
+echo_to cabal.project "packages: ${PKGDIR_servant_server}"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant-client"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant-docs"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant-server"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+cat >> cabal.project <<EOF
+constraints: foundation >= 0.14
+allow-newer: servant-js:servant
+allow-newer: servant-js:servant-foreign
+
+source-repository-package
+  type:     git
+  location: https://github.com/haskell-servant/servant-auth
+  tag:      4a134c3db79293d28f8b74a02863047e41fbaf56
+
+package servant
+  tests: False
+EOF
+$HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(servant|servant-client|servant-docs|servant-server)$/; }' >> cabal.project.local
+run_cmd cat cabal.project
+run_cmd cat cabal.project.local
+
+# dump install plan
+put_info "dump install plan"
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
+run_cmd cabal-plan
+
+# install dependencies
+put_info "install dependencies"
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j all
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j all
+
+# build w/o tests
+put_info "build w/o tests"
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+
+# build
+put_info "build"
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all
+
+# tests
+put_info "tests"
+run_cmd $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
+
+# cabal check
+put_info "cabal check"
+change_dir "${PKGDIR_servant}"
+run_cmd ${CABAL} -vnormal check
+change_dir "${PKGDIR_servant_client}"
+run_cmd ${CABAL} -vnormal check
+change_dir "${PKGDIR_servant_docs}"
+run_cmd ${CABAL} -vnormal check
+change_dir "${PKGDIR_servant_server}"
+run_cmd ${CABAL} -vnormal check
+change_dir "$BUILDDIR"
+
+# haddock
+put_info "haddock"
+run_cmd $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
+
+# unconstrained build
+put_info "unconstrained build"
+run_cmd rm -f cabal.project.local
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+
+
+# Done
+run_cmd echo OK
diff --git a/fixtures/copy-fields-all.github b/fixtures/copy-fields-all.github
new file mode 100644
--- /dev/null
+++ b/fixtures/copy-fields-all.github
@@ -0,0 +1,257 @@
+# SUCCESS
+# *INFO* Generating GitHub config for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+# This GitHub workflow config has been generated by a script via
+#
+#   haskell-ci '--copy-fields=all' 'github' 'copy-fields-all.project'
+#
+# To regenerate the script (for example after adjusting tested-with) run
+#
+#   haskell-ci regenerate
+#
+# For more information, see https://github.com/haskell-CI/haskell-ci
+#
+# REGENDATA ["--copy-fields=all","github","copy-fields-all.project"]
+#
+name: Haskell-CI
+on:
+  - push
+  - pull_request
+jobs:
+  linux:
+    name: Haskell-CI - Linux - ${{ matrix.compiler }}
+    runs-on: ubuntu-18.04
+    container:
+      image: buildpack-deps:bionic
+    continue-on-error: ${{ matrix.allow-failure }}
+    strategy:
+      matrix:
+        include:
+          - compiler: ghc-8.10.4
+            allow-failure: false
+          - compiler: ghc-8.10.3
+            allow-failure: false
+          - compiler: ghc-8.10.2
+            allow-failure: false
+          - compiler: ghc-8.10.1
+            allow-failure: false
+          - compiler: ghc-8.8.4
+            allow-failure: false
+          - compiler: ghc-8.8.3
+            allow-failure: false
+          - compiler: ghc-8.8.2
+            allow-failure: false
+          - compiler: ghc-8.8.1
+            allow-failure: false
+          - compiler: ghc-8.6.5
+            allow-failure: false
+          - compiler: ghc-8.6.4
+            allow-failure: false
+          - compiler: ghc-8.6.3
+            allow-failure: false
+          - compiler: ghc-8.6.2
+            allow-failure: false
+          - compiler: ghc-8.6.1
+            allow-failure: false
+          - compiler: ghc-8.4.4
+            allow-failure: false
+          - compiler: ghc-8.4.3
+            allow-failure: false
+          - compiler: ghc-8.4.2
+            allow-failure: false
+          - compiler: ghc-8.4.1
+            allow-failure: false
+          - compiler: ghc-8.2.2
+            allow-failure: false
+          - compiler: ghc-8.2.1
+            allow-failure: false
+          - compiler: ghc-8.0.2
+            allow-failure: false
+          - compiler: ghc-8.0.1
+            allow-failure: false
+          - compiler: ghc-7.10.3
+            allow-failure: false
+          - compiler: ghc-7.10.2
+            allow-failure: false
+          - compiler: ghc-7.10.1
+            allow-failure: false
+          - compiler: ghc-7.8.4
+            allow-failure: false
+          - compiler: ghc-7.8.3
+            allow-failure: false
+          - compiler: ghc-7.8.2
+            allow-failure: false
+          - compiler: ghc-7.8.1
+            allow-failure: false
+      fail-fast: false
+    steps:
+      - name: apt
+        run: |
+          apt-get update
+          apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common
+          apt-add-repository -y 'ppa:hvr/ghc'
+          apt-get update
+          apt-get install -y $CC cabal-install-3.4
+        env:
+          CC: ${{ matrix.compiler }}
+      - name: Set PATH and environment variables
+        run: |
+          echo "$HOME/.cabal/bin" >> $GITHUB_PATH
+          echo "LANG=C.UTF-8" >> $GITHUB_ENV
+          echo "CABAL_DIR=$HOME/.cabal" >> $GITHUB_ENV
+          echo "CABAL_CONFIG=$HOME/.cabal/config" >> $GITHUB_ENV
+          HCDIR=$(echo "/opt/$CC" | sed 's/-/\//')
+          HCNAME=ghc
+          HC=$HCDIR/bin/$HCNAME
+          echo "HC=$HC" >> $GITHUB_ENV
+          echo "HCPKG=$HCDIR/bin/$HCNAME-pkg" >> $GITHUB_ENV
+          echo "HADDOCK=$HCDIR/bin/haddock" >> $GITHUB_ENV
+          echo "CABAL=/opt/cabal/3.4/bin/cabal -vnormal+nowrap" >> $GITHUB_ENV
+          HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
+          echo "HCNUMVER=$HCNUMVER" >> $GITHUB_ENV
+          echo "ARG_TESTS=--enable-tests" >> $GITHUB_ENV
+          echo "ARG_BENCH=--enable-benchmarks" >> $GITHUB_ENV
+          echo "HEADHACKAGE=false" >> $GITHUB_ENV
+          echo "ARG_COMPILER=--$HCNAME --with-compiler=$HC" >> $GITHUB_ENV
+          echo "GHCJSARITH=0" >> $GITHUB_ENV
+        env:
+          CC: ${{ matrix.compiler }}
+      - name: env
+        run: |
+          env
+      - name: write cabal config
+        run: |
+          mkdir -p $CABAL_DIR
+          cat >> $CABAL_CONFIG <<EOF
+          remote-build-reporting: anonymous
+          write-ghc-environment-files: never
+          remote-repo-cache: $CABAL_DIR/packages
+          logs-dir:          $CABAL_DIR/logs
+          world-file:        $CABAL_DIR/world
+          extra-prog-path:   $CABAL_DIR/bin
+          symlink-bindir:    $CABAL_DIR/bin
+          installdir:        $CABAL_DIR/bin
+          build-summary:     $CABAL_DIR/logs/build.log
+          store-dir:         $CABAL_DIR/store
+          install-dirs user
+            prefix: $CABAL_DIR
+          repository hackage.haskell.org
+            url: http://hackage.haskell.org/
+          EOF
+          cat $CABAL_CONFIG
+      - name: versions
+        run: |
+          $HC --version || true
+          $HC --print-project-git-commit-id || true
+          $CABAL --version || true
+      - name: update cabal index
+        run: |
+          $CABAL v2-update -v
+      - name: install cabal-plan
+        run: |
+          mkdir -p $HOME/.cabal/bin
+          curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > cabal-plan.xz
+          echo 'de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc  cabal-plan.xz' | sha256sum -c -
+          xz -d < cabal-plan.xz > $HOME/.cabal/bin/cabal-plan
+          rm -f cabal-plan.xz
+          chmod a+x $HOME/.cabal/bin/cabal-plan
+          cabal-plan --version
+      - name: checkout
+        uses: actions/checkout@v2
+        with:
+          path: source
+      - name: initial cabal.project for sdist
+        run: |
+          touch cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant" >> cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant-client" >> cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant-docs" >> cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant-server" >> cabal.project
+          cat cabal.project
+      - name: sdist
+        run: |
+          mkdir -p sdist
+          $CABAL sdist all --output-dir $GITHUB_WORKSPACE/sdist
+      - name: unpack
+        run: |
+          mkdir -p unpacked
+          find sdist -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C $GITHUB_WORKSPACE/unpacked -xzvf {} \;
+      - name: generate cabal.project
+        run: |
+          PKGDIR_servant="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+          echo "PKGDIR_servant=${PKGDIR_servant}" >> $GITHUB_ENV
+          PKGDIR_servant_client="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-client-[0-9.]*')"
+          echo "PKGDIR_servant_client=${PKGDIR_servant_client}" >> $GITHUB_ENV
+          PKGDIR_servant_docs="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-docs-[0-9.]*')"
+          echo "PKGDIR_servant_docs=${PKGDIR_servant_docs}" >> $GITHUB_ENV
+          PKGDIR_servant_server="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-server-[0-9.]*')"
+          echo "PKGDIR_servant_server=${PKGDIR_servant_server}" >> $GITHUB_ENV
+          touch cabal.project
+          touch cabal.project.local
+          echo "packages: ${PKGDIR_servant}" >> cabal.project
+          echo "packages: ${PKGDIR_servant_client}" >> cabal.project
+          echo "packages: ${PKGDIR_servant_docs}" >> cabal.project
+          echo "packages: ${PKGDIR_servant_server}" >> cabal.project
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant-client" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant-docs" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant-server" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          cat >> cabal.project <<EOF
+          constraints: foundation >= 0.14
+          allow-newer: servant-js:servant
+          allow-newer: servant-js:servant-foreign
+
+          source-repository-package
+            type:     git
+            location: https://github.com/haskell-servant/servant-auth
+            tag:      4a134c3db79293d28f8b74a02863047e41fbaf56
+
+          package servant
+            tests: False
+          EOF
+          $HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(servant|servant-client|servant-docs|servant-server)$/; }' >> cabal.project.local
+          cat cabal.project
+          cat cabal.project.local
+      - name: dump install plan
+        run: |
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
+          cabal-plan
+      - name: cache
+        uses: actions/cache@v2
+        with:
+          key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
+          path: ~/.cabal/store
+          restore-keys: ${{ runner.os }}-${{ matrix.compiler }}-
+      - name: install dependencies
+        run: |
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j2 all
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j2 all
+      - name: build w/o tests
+        run: |
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+      - name: build
+        run: |
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --write-ghc-environment-files=always
+      - name: tests
+        run: |
+          $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
+      - name: cabal check
+        run: |
+          cd ${PKGDIR_servant} || false
+          ${CABAL} -vnormal check
+          cd ${PKGDIR_servant_client} || false
+          ${CABAL} -vnormal check
+          cd ${PKGDIR_servant_docs} || false
+          ${CABAL} -vnormal check
+          cd ${PKGDIR_servant_server} || false
+          ${CABAL} -vnormal check
+      - name: haddock
+        run: |
+          $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
+      - name: unconstrained build
+        run: |
+          rm -f cabal.project.local
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
diff --git a/fixtures/copy-fields-all.project b/fixtures/copy-fields-all.project
new file mode 100644
--- /dev/null
+++ b/fixtures/copy-fields-all.project
@@ -0,0 +1,20 @@
+packages:
+  servant/
+  servant-client/
+  servant-docs/
+  servant-server/
+
+package servant
+  tests: False
+
+constraints: foundation >= 0.14
+
+allow-newer:
+  servant-js:servant
+allow-newer:
+  servant-js:servant-foreign
+
+source-repository-package
+  type: git
+  location: https://github.com/haskell-servant/servant-auth
+  tag: 4a134c3db79293d28f8b74a02863047e41fbaf56
diff --git a/fixtures/copy-fields-all.travis b/fixtures/copy-fields-all.travis
new file mode 100644
--- /dev/null
+++ b/fixtures/copy-fields-all.travis
@@ -0,0 +1,267 @@
+# SUCCESS
+# *INFO* Generating Travis-CI config for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+# This Travis job script has been generated by a script via
+#
+#   haskell-ci '--copy-fields=all' 'travis' 'copy-fields-all.project'
+#
+# To regenerate the script (for example after adjusting tested-with) run
+#
+#   haskell-ci regenerate
+#
+# For more information, see https://github.com/haskell-CI/haskell-ci
+#
+version: ~> 1.0
+language: c
+os: linux
+dist: xenial
+git:
+  # whether to recursively clone submodules
+  submodules: false
+cache:
+  directories:
+    - $HOME/.cabal/packages
+    - $HOME/.cabal/store
+    - $HOME/.hlint
+before_cache:
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log
+  # remove files that are regenerated by 'cabal update'
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx
+  - rm -rfv $CABALHOME/packages/head.hackage
+jobs:
+  include:
+    - compiler: ghc-8.10.4
+      addons: {"apt":{"packages":["ghc-8.10.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.3
+      addons: {"apt":{"packages":["ghc-8.10.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.2
+      addons: {"apt":{"packages":["ghc-8.10.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.1
+      addons: {"apt":{"packages":["ghc-8.10.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.4
+      addons: {"apt":{"packages":["ghc-8.8.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.3
+      addons: {"apt":{"packages":["ghc-8.8.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.2
+      addons: {"apt":{"packages":["ghc-8.8.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.1
+      addons: {"apt":{"packages":["ghc-8.8.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.5
+      addons: {"apt":{"packages":["ghc-8.6.5","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.4
+      addons: {"apt":{"packages":["ghc-8.6.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.3
+      addons: {"apt":{"packages":["ghc-8.6.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.2
+      addons: {"apt":{"packages":["ghc-8.6.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.1
+      addons: {"apt":{"packages":["ghc-8.6.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.4
+      addons: {"apt":{"packages":["ghc-8.4.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.3
+      addons: {"apt":{"packages":["ghc-8.4.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.2
+      addons: {"apt":{"packages":["ghc-8.4.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.1
+      addons: {"apt":{"packages":["ghc-8.4.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.2.2
+      addons: {"apt":{"packages":["ghc-8.2.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.2.1
+      addons: {"apt":{"packages":["ghc-8.2.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.0.2
+      addons: {"apt":{"packages":["ghc-8.0.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.0.1
+      addons: {"apt":{"packages":["ghc-8.0.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.3
+      addons: {"apt":{"packages":["ghc-7.10.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.2
+      addons: {"apt":{"packages":["ghc-7.10.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.1
+      addons: {"apt":{"packages":["ghc-7.10.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.4
+      addons: {"apt":{"packages":["ghc-7.8.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.3
+      addons: {"apt":{"packages":["ghc-7.8.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.2
+      addons: {"apt":{"packages":["ghc-7.8.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.1
+      addons: {"apt":{"packages":["ghc-7.8.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+before_install:
+  - HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//')
+  - WITHCOMPILER="-w $HC"
+  - HADDOCK=$(echo "/opt/$CC/bin/haddock" | sed 's/-/\//')
+  - HCPKG="$HC-pkg"
+  - unset CC
+  - CABAL=/opt/ghc/bin/cabal
+  - CABALHOME=$HOME/.cabal
+  - export PATH="$CABALHOME/bin:$PATH"
+  - TOP=$(pwd)
+  - "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')"
+  - echo $HCNUMVER
+  - CABAL="$CABAL -vnormal+nowrap"
+  - set -o pipefail
+  - TEST=--enable-tests
+  - BENCH=--enable-benchmarks
+  - HEADHACKAGE=false
+  - rm -f $CABALHOME/config
+  - |
+    echo "verbose: normal +nowrap +markoutput"          >> $CABALHOME/config
+    echo "remote-build-reporting: anonymous"            >> $CABALHOME/config
+    echo "write-ghc-environment-files: never"           >> $CABALHOME/config
+    echo "remote-repo-cache: $CABALHOME/packages"       >> $CABALHOME/config
+    echo "logs-dir:          $CABALHOME/logs"           >> $CABALHOME/config
+    echo "world-file:        $CABALHOME/world"          >> $CABALHOME/config
+    echo "extra-prog-path:   $CABALHOME/bin"            >> $CABALHOME/config
+    echo "symlink-bindir:    $CABALHOME/bin"            >> $CABALHOME/config
+    echo "installdir:        $CABALHOME/bin"            >> $CABALHOME/config
+    echo "build-summary:     $CABALHOME/logs/build.log" >> $CABALHOME/config
+    echo "store-dir:         $CABALHOME/store"          >> $CABALHOME/config
+    echo "install-dirs user"                            >> $CABALHOME/config
+    echo "  prefix: $CABALHOME"                         >> $CABALHOME/config
+    echo "repository hackage.haskell.org"               >> $CABALHOME/config
+    echo "  url: http://hackage.haskell.org/"           >> $CABALHOME/config
+install:
+  - ${CABAL} --version
+  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
+  - |
+    echo "program-default-options"                >> $CABALHOME/config
+    echo "  ghc-options: $GHCJOBS +RTS -M6G -RTS" >> $CABALHOME/config
+  - cat $CABALHOME/config
+  - rm -fv cabal.project cabal.project.local cabal.project.freeze
+  - travis_retry ${CABAL} v2-update -v
+  # Generate cabal.project
+  - rm -rf cabal.project cabal.project.local cabal.project.freeze
+  - touch cabal.project
+  - |
+    echo "packages: servant" >> cabal.project
+    echo "packages: servant-client" >> cabal.project
+    echo "packages: servant-docs" >> cabal.project
+    echo "packages: servant-server" >> cabal.project
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-client' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-docs' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-server' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - |
+    echo "constraints: foundation >= 0.14"                             >> cabal.project
+    echo "allow-newer: servant-js:servant"                             >> cabal.project
+    echo "allow-newer: servant-js:servant-foreign"                     >> cabal.project
+    echo ""                                                            >> cabal.project
+    echo "source-repository-package"                                   >> cabal.project
+    echo "  type:     git"                                             >> cabal.project
+    echo "  location: https://github.com/haskell-servant/servant-auth" >> cabal.project
+    echo "  tag:      4a134c3db79293d28f8b74a02863047e41fbaf56"        >> cabal.project
+    echo ""                                                            >> cabal.project
+    echo "package servant"                                             >> cabal.project
+    echo "  tests: False"                                              >> cabal.project
+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
+  - cat cabal.project || true
+  - cat cabal.project.local || true
+  - if [ -f "servant/configure.ac" ]; then (cd "servant" && autoreconf -i); fi
+  - if [ -f "servant-client/configure.ac" ]; then (cd "servant-client" && autoreconf -i); fi
+  - if [ -f "servant-docs/configure.ac" ]; then (cd "servant-docs" && autoreconf -i); fi
+  - if [ -f "servant-server/configure.ac" ]; then (cd "servant-server" && autoreconf -i); fi
+  - ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH}
+  - "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
+  - rm  cabal.project.freeze
+  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} --dep -j2 all
+  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --dep -j2 all
+script:
+  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
+  # Packaging...
+  - ${CABAL} v2-sdist all
+  # Unpacking...
+  - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
+  - cd ${DISTDIR} || false
+  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \;
+  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm       '{}' \;
+  - PKGDIR_servant="$(find . -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+  - PKGDIR_servant_client="$(find . -maxdepth 1 -type d -regex '.*/servant-client-[0-9.]*')"
+  - PKGDIR_servant_docs="$(find . -maxdepth 1 -type d -regex '.*/servant-docs-[0-9.]*')"
+  - PKGDIR_servant_server="$(find . -maxdepth 1 -type d -regex '.*/servant-server-[0-9.]*')"
+  # Generate cabal.project
+  - rm -rf cabal.project cabal.project.local cabal.project.freeze
+  - touch cabal.project
+  - |
+    echo "packages: ${PKGDIR_servant}" >> cabal.project
+    echo "packages: ${PKGDIR_servant_client}" >> cabal.project
+    echo "packages: ${PKGDIR_servant_docs}" >> cabal.project
+    echo "packages: ${PKGDIR_servant_server}" >> cabal.project
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-client' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-docs' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-server' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - |
+    echo "constraints: foundation >= 0.14"                             >> cabal.project
+    echo "allow-newer: servant-js:servant"                             >> cabal.project
+    echo "allow-newer: servant-js:servant-foreign"                     >> cabal.project
+    echo ""                                                            >> cabal.project
+    echo "source-repository-package"                                   >> cabal.project
+    echo "  type:     git"                                             >> cabal.project
+    echo "  location: https://github.com/haskell-servant/servant-auth" >> cabal.project
+    echo "  tag:      4a134c3db79293d28f8b74a02863047e41fbaf56"        >> cabal.project
+    echo ""                                                            >> cabal.project
+    echo "package servant"                                             >> cabal.project
+    echo "  tests: False"                                              >> cabal.project
+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
+  - cat cabal.project || true
+  - cat cabal.project.local || true
+  # Building...
+  # this builds all libraries and executables (without tests/benchmarks)
+  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
+  # Building with tests and benchmarks...
+  # build & run tests, build benchmarks
+  - ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} all --write-ghc-environment-files=always
+  # Testing...
+  - ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all --test-show-details=direct
+  # cabal check...
+  - (cd ${PKGDIR_servant} && ${CABAL} -vnormal check)
+  - (cd ${PKGDIR_servant_client} && ${CABAL} -vnormal check)
+  - (cd ${PKGDIR_servant_docs} && ${CABAL} -vnormal check)
+  - (cd ${PKGDIR_servant_server} && ${CABAL} -vnormal check)
+  # haddock...
+  - ${CABAL} v2-haddock $WITHCOMPILER --with-haddock $HADDOCK ${TEST} ${BENCH} all
+  # Building without installed constraints for packages in global-db...
+  - rm -f cabal.project.local
+  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
+
+# REGENDATA ["--copy-fields=all","travis","copy-fields-all.project"]
+# EOF
diff --git a/fixtures/copy-fields-none.args b/fixtures/copy-fields-none.args
new file mode 100644
--- /dev/null
+++ b/fixtures/copy-fields-none.args
@@ -0,0 +1,1 @@
+--copy-fields=none
diff --git a/fixtures/copy-fields-none.bash b/fixtures/copy-fields-none.bash
new file mode 100644
--- /dev/null
+++ b/fixtures/copy-fields-none.bash
@@ -0,0 +1,541 @@
+# SUCCESS
+# *INFO* Generating Bash script for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+#!/bin/bash
+# shellcheck disable=SC2086,SC2016,SC2046
+# REGENDATA ["--copy-fields=none","bash","copy-fields-none.project"]
+
+set -o pipefail
+
+# Mode
+##############################################################################
+
+if [ "$1" = "indocker" ]; then
+    INDOCKER=true
+    shift
+else
+    INDOCKER=false
+fi
+
+# Run configuration
+##############################################################################
+
+CFG_CABAL_STORE_CACHE=""
+CFG_CABAL_REPO_CACHE=""
+CFG_JOBS="8.10.4 8.10.3 8.10.2 8.10.1 8.8.4 8.8.3 8.8.2 8.8.1 8.6.5 8.6.4 8.6.3 8.6.2 8.6.1 8.4.4 8.4.3 8.4.2 8.4.1 8.2.2 8.2.1 8.0.2 8.0.1 7.10.3 7.10.2 7.10.1 7.8.4 7.8.3 7.8.2 7.8.1"
+CFG_CABAL_UPDATE=false
+
+SCRIPT_NAME=$(basename "$0")
+START_TIME="$(date +'%s')"
+
+XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config}
+
+# Job configuration
+##############################################################################
+
+GHC_VERSION="non-existing"
+CABAL_VERSION=3.2
+HEADHACKAGE=false
+
+# Locale
+##############################################################################
+
+export LC_ALL=C.UTF-8
+
+# Utilities
+##############################################################################
+
+SGR_RED='\033[1;31m'
+SGR_GREEN='\033[1;32m'
+SGR_BLUE='\033[1;34m'
+SGR_CYAN='\033[1;96m'
+SGR_RESET='\033[0m' # No Color
+
+put_info() {
+    printf "$SGR_CYAN%s$SGR_RESET\n" "### $*"
+}
+
+put_error() {
+    printf "$SGR_RED%s$SGR_RESET\n" "!!! $*"
+}
+
+run_cmd() {
+    local PRETTYCMD="$*"
+    local PROMPT
+    if $INDOCKER; then
+        PROMPT="$(pwd) >>>"
+    else
+        PROMPT=">>>"
+    fi
+
+    printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+
+    local start_time end_time cmd_duration total_duration
+    start_time=$(date +'%s')
+
+    "$@"
+    local RET=$?
+
+    end_time=$(date +'%s')
+    cmd_duration=$((end_time - start_time))
+    total_duration=$((end_time - START_TIME))
+
+    cmd_min=$((cmd_duration / 60))
+    cmd_sec=$((cmd_duration % 60))
+
+    total_min=$((total_duration / 60))
+    total_sec=$((total_duration % 60))
+
+    if [ $RET -eq 0 ]; then
+        printf "$SGR_GREEN%s$SGR_RESET (%dm%02ds; %dm%02ds)\n" "<<< $PRETTYCMD" "$cmd_min" "$cmd_sec" "$total_min" "$total_sec"
+    else
+        printf "$SGR_RED%s$SGR_RESET\n" "!!! $PRETTYCMD"
+        exit 1
+    fi
+}
+
+run_cmd_if() {
+    local COND=$1
+    shift
+
+    if [ $COND -eq 1 ]; then
+        run_cmd "$@"
+    else
+        local PRETTYCMD="$*"
+        local PROMPT
+        PROMPT="$(pwd) (skipping) >>>"
+
+        printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+    fi
+}
+
+run_cmd_unchecked() {
+    local PRETTYCMD="$*"
+    local PROMPT
+    if $INDOCKER; then
+        PROMPT="$(pwd) >>>"
+    else
+        PROMPT=">>>"
+    fi
+
+    printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+
+    local start_time end_time cmd_duration total_duration cmd_min cmd_sec total_min total_sec
+    start_time=$(date +'%s')
+
+    "$@"
+
+    end_time=$(date +'%s')
+    cmd_duration=$((end_time - start_time))
+    total_duration=$((end_time - START_TIME))
+
+    cmd_min=$((cmd_duration / 60))
+    cmd_sec=$((cmd_duration % 60))
+
+    total_min=$((total_duration / 60))
+    total_sec=$((total_duration % 60))
+
+    printf "$SGR_GREEN%s$SGR_RESET (%dm%02ds; %dm%02ds)\n" "<<< $PRETTYCMD" "$cmd_min" "$cmd_sec" "$total_min" "$total_sec"
+}
+
+change_dir() {
+    local DIR=$1
+    if [ -d "$DIR" ]; then
+        printf "$SGR_BLUE%s$SGR_RESET\n" "change directory to $DIR"
+        cd "$DIR" || exit 1
+    else
+        printf "$SGR_RED%s$SGR_RESET\n" "!!! cd $DIR"
+        exit 1
+    fi
+}
+
+change_dir_if() {
+    local COND=$1
+    local DIR=$2
+
+    if [ $COND -ne 0 ]; then
+        change_dir "$DIR"
+    fi
+}
+
+echo_to() {
+    local DEST=$1
+    local CONTENTS=$2
+
+    echo "$CONTENTS" >> "$DEST"
+}
+
+echo_if_to() {
+    local COND=$1
+    local DEST=$2
+    local CONTENTS=$3
+
+    if [ $COND -ne 0 ]; then
+        echo_to "$DEST" "$CONTENTS"
+    fi
+}
+
+install_cabalplan() {
+    put_info "installing cabal-plan"
+
+    if [ ! -e $CABAL_REPOCACHE/downloads/cabal-plan ]; then
+        curl -L https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > /tmp/cabal-plan.xz || exit 1
+        (cd /tmp && echo "de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc  cabal-plan.xz" | sha256sum -c -)|| exit 1
+        mkdir -p $CABAL_REPOCACHE/downloads
+        xz -d < /tmp/cabal-plan.xz > $CABAL_REPOCACHE/downloads/cabal-plan || exit 1
+        chmod a+x $CABAL_REPOCACHE/downloads/cabal-plan || exit 1
+    fi
+
+    mkdir -p $CABAL_DIR/bin || exit 1
+    ln -s $CABAL_REPOCACHE/downloads/cabal-plan $CABAL_DIR/bin/cabal-plan || exit 1
+}
+
+# Help
+##############################################################################
+
+show_usage() {
+cat <<EOF
+./haskell-ci.sh - build & test
+
+Usage: ./haskell-ci.sh [options]
+  A script to run automated checks locally (using Docker)
+
+Available options:
+  --jobs JOBS               Jobs to run (default: $CFG_JOBS)
+  --cabal-store-cache PATH  Directory to use for cabal-store-cache
+  --cabal-repo-cache PATH   Directory to use for cabal-repo-cache
+  --skip-cabal-update       Skip cabal update (useful with --cabal-repo-cache)
+  --no-skip-cabal-update
+  --help                    Print this message
+
+EOF
+}
+
+# getopt
+#######################################################################
+
+process_cli_options() {
+    while [ $# -gt 0 ]; do
+        arg=$1
+        case $arg in
+            --help)
+                show_usage
+                exit
+                ;;
+            --jobs)
+                CFG_JOBS=$2
+                shift
+                shift
+                ;;
+            --cabal-store-cache)
+                CFG_CABAL_STORE_CACHE=$2
+                shift
+                shift
+                ;;
+            --cabal-repo-cache)
+                CFG_CABAL_REPO_CACHE=$2
+                shift
+                shift
+                ;;
+            --skip-cabal-update)
+                CFG_CABAL_UPDATE=false
+                shift
+                ;;
+            --no-skip-cabal-update)
+                CFG_CABAL_UPDATE=true
+                shift
+                ;;
+            *)
+                echo "Unknown option $arg"
+                exit 1
+        esac
+    done
+}
+
+process_indocker_options () {
+    while [ $# -gt 0 ]; do
+        arg=$1
+
+        case $arg in
+            --ghc-version)
+                GHC_VERSION=$2
+                shift
+                shift
+                ;;
+            --cabal-version)
+                CABAL_VERSION=$2
+                shift
+                shift
+                ;;
+            --start-time)
+                START_TIME=$2
+                shift
+                shift
+                ;;
+            --cabal-update)
+                CABAL_UPDATE=$2
+                shift
+                shift
+                ;;
+            *)
+                echo "Unknown option $arg"
+                exit 1
+        esac
+    done
+}
+
+if $INDOCKER; then
+    process_indocker_options "$@"
+
+else
+    if [ -f "$XDG_CONFIG_HOME/haskell-ci/bash.config" ]; then
+        process_cli_options $(cat "$XDG_CONFIG_HOME/haskell-ci/bash.config")
+    fi
+
+    process_cli_options "$@"
+
+    put_info "jobs:              $CFG_JOBS"
+    put_info "cabal-store-cache: $CFG_CABAL_STORE_CACHE"
+    put_info "cabal-repo-cache:  $CFG_CABAL_REPO_CACHE"
+    put_info "cabal-update:      $CFG_CABAL_UPDATE"
+fi
+
+# Constants
+##############################################################################
+
+SRCDIR=/hsci/src
+BUILDDIR=/hsci/build
+CABAL_DIR="$BUILDDIR/cabal"
+CABAL_REPOCACHE=/hsci/cabal-repocache
+CABAL_STOREDIR=/hsci/store
+
+# Docker invoke
+##############################################################################
+
+# if cache directory is specified, use it.
+# Otherwise use another tmpfs host
+if [ -z "$CFG_CABAL_STORE_CACHE" ]; then
+    CABALSTOREARG="--tmpfs $CABAL_STOREDIR:exec"
+else
+    CABALSTOREARG="--volume $CFG_CABAL_STORE_CACHE:$CABAL_STOREDIR"
+fi
+
+if [ -z "$CFG_CABAL_REPO_CACHE" ]; then
+    CABALREPOARG="--tmpfs $CABAL_REPOCACHE:exec"
+else
+    CABALREPOARG="--volume $CFG_CABAL_REPO_CACHE:$CABAL_REPOCACHE"
+fi
+
+echo_docker_cmd() {
+    local GHCVER=$1
+
+    # TODO: mount /hsci/src:ro (readonly)
+    echo docker run \
+        --tty \
+        --interactive \
+        --rm \
+        --label haskell-ci \
+        --volume "$(pwd):/hsci/src" \
+        $CABALSTOREARG \
+        $CABALREPOARG \
+        --tmpfs /tmp:exec \
+        --tmpfs /hsci/build:exec \
+        --workdir /hsci/build \
+        "phadej/ghc:$GHCVER-bionic" \
+        "/bin/bash" "/hsci/src/$SCRIPT_NAME" indocker \
+        --ghc-version "$GHCVER" \
+        --cabal-update "$CFG_CABAL_UPDATE" \
+        --start-time "$START_TIME"
+}
+
+# if we are not in docker, loop through jobs
+if ! $INDOCKER; then
+    for JOB in $CFG_JOBS; do
+        put_info "Running in docker: $JOB"
+        run_cmd $(echo_docker_cmd "$JOB")
+    done
+
+    run_cmd echo "ALL OK"
+    exit 0
+fi
+
+# Otherwise we are in docker, and the rest of script executes
+put_info "In docker"
+
+# Environment
+##############################################################################
+
+GHCDIR=/opt/ghc/$GHC_VERSION
+
+HC=$GHCDIR/bin/ghc
+HCPKG=$GHCDIR/bin/ghc-pkg
+HADDOCK=$GHCDIR/bin/haddock
+
+CABAL=/opt/cabal/$CABAL_VERSION/bin/cabal
+
+CABAL="$CABAL -vnormal+nowrap"
+
+export CABAL_DIR
+export CABAL_CONFIG="$BUILDDIR/cabal/config"
+
+PATH="$CABAL_DIR/bin:$PATH"
+
+# HCNUMVER
+HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
+GHCJSARITH=0
+
+put_info "HCNUMVER: $HCNUMVER"
+
+# Args for shorter/nicer commands
+if [ 1 -ne 0 ] ; then ARG_TESTS=--enable-tests; else ARG_TESTS=--disable-tests; fi
+if [ 1 -ne 0 ] ; then ARG_BENCH=--enable-benchmarks; else ARG_BENCH=--disable-benchmarks; fi
+ARG_COMPILER="--ghc --with-compiler=$HC"
+
+put_info "tests/benchmarks: $ARG_TESTS $ARG_BENCH"
+
+# Apt dependencies
+##############################################################################
+
+
+# Cabal config
+##############################################################################
+
+mkdir -p $BUILDDIR/cabal
+
+cat > $BUILDDIR/cabal/config <<EOF
+remote-build-reporting: anonymous
+write-ghc-environment-files: always
+remote-repo-cache: $CABAL_REPOCACHE
+logs-dir:          $CABAL_DIR/logs
+world-file:        $CABAL_DIR/world
+extra-prog-path:   $CABAL_DIR/bin
+symlink-bindir:    $CABAL_DIR/bin
+installdir:        $CABAL_DIR/bin
+build-summary:     $CABAL_DIR/logs/build.log
+store-dir:         $CABAL_STOREDIR
+install-dirs user
+  prefix: $CABAL_DIR
+repository hackage.haskell.org
+  url: http://hackage.haskell.org/
+EOF
+
+if $HEADHACKAGE; then
+    put_error "head.hackage is not implemented"
+    exit 1
+fi
+
+run_cmd cat "$BUILDDIR/cabal/config"
+
+# Version
+##############################################################################
+
+put_info "Versions"
+run_cmd $HC --version
+run_cmd_unchecked $HC --print-project-git-commit-id
+run_cmd $CABAL --version
+
+# Build script
+##############################################################################
+
+# update cabal index
+if $CABAL_UPDATE; then
+    put_info "Updating Hackage index"
+    run_cmd $CABAL v2-update -v
+fi
+
+# install cabal-plan
+install_cabalplan
+run_cmd cabal-plan --version
+
+# initial cabal.project for sdist
+put_info "initial cabal.project for sdist"
+change_dir "$BUILDDIR"
+run_cmd touch cabal.project
+echo_to cabal.project "packages: $SRCDIR/servant"
+echo_to cabal.project "packages: $SRCDIR/servant-client"
+echo_to cabal.project "packages: $SRCDIR/servant-docs"
+echo_to cabal.project "packages: $SRCDIR/servant-server"
+run_cmd cat cabal.project
+
+# sdist
+put_info "sdist"
+run_cmd mkdir -p "$BUILDDIR/sdist"
+run_cmd $CABAL sdist all --output-dir "$BUILDDIR/sdist"
+
+# unpack
+put_info "unpack"
+change_dir "$BUILDDIR"
+run_cmd mkdir -p "$BUILDDIR/unpacked"
+run_cmd find "$BUILDDIR/sdist" -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C "$BUILDDIR/unpacked" -xzvf {} \;
+
+# generate cabal.project
+put_info "generate cabal.project"
+PKGDIR_servant="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+PKGDIR_servant_client="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-client-[0-9.]*')"
+PKGDIR_servant_docs="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-docs-[0-9.]*')"
+PKGDIR_servant_server="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-server-[0-9.]*')"
+run_cmd touch cabal.project
+run_cmd touch cabal.project.local
+echo_to cabal.project "packages: ${PKGDIR_servant}"
+echo_to cabal.project "packages: ${PKGDIR_servant_client}"
+echo_to cabal.project "packages: ${PKGDIR_servant_docs}"
+echo_to cabal.project "packages: ${PKGDIR_servant_server}"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant-client"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant-docs"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant-server"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+cat >> cabal.project <<EOF
+EOF
+$HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(servant|servant-client|servant-docs|servant-server)$/; }' >> cabal.project.local
+run_cmd cat cabal.project
+run_cmd cat cabal.project.local
+
+# dump install plan
+put_info "dump install plan"
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
+run_cmd cabal-plan
+
+# install dependencies
+put_info "install dependencies"
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j all
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j all
+
+# build w/o tests
+put_info "build w/o tests"
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+
+# build
+put_info "build"
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all
+
+# tests
+put_info "tests"
+run_cmd $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
+
+# cabal check
+put_info "cabal check"
+change_dir "${PKGDIR_servant}"
+run_cmd ${CABAL} -vnormal check
+change_dir "${PKGDIR_servant_client}"
+run_cmd ${CABAL} -vnormal check
+change_dir "${PKGDIR_servant_docs}"
+run_cmd ${CABAL} -vnormal check
+change_dir "${PKGDIR_servant_server}"
+run_cmd ${CABAL} -vnormal check
+change_dir "$BUILDDIR"
+
+# haddock
+put_info "haddock"
+run_cmd $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
+
+# unconstrained build
+put_info "unconstrained build"
+run_cmd rm -f cabal.project.local
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+
+
+# Done
+run_cmd echo OK
diff --git a/fixtures/copy-fields-none.github b/fixtures/copy-fields-none.github
new file mode 100644
--- /dev/null
+++ b/fixtures/copy-fields-none.github
@@ -0,0 +1,246 @@
+# SUCCESS
+# *INFO* Generating GitHub config for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+# This GitHub workflow config has been generated by a script via
+#
+#   haskell-ci '--copy-fields=none' 'github' 'copy-fields-none.project'
+#
+# To regenerate the script (for example after adjusting tested-with) run
+#
+#   haskell-ci regenerate
+#
+# For more information, see https://github.com/haskell-CI/haskell-ci
+#
+# REGENDATA ["--copy-fields=none","github","copy-fields-none.project"]
+#
+name: Haskell-CI
+on:
+  - push
+  - pull_request
+jobs:
+  linux:
+    name: Haskell-CI - Linux - ${{ matrix.compiler }}
+    runs-on: ubuntu-18.04
+    container:
+      image: buildpack-deps:bionic
+    continue-on-error: ${{ matrix.allow-failure }}
+    strategy:
+      matrix:
+        include:
+          - compiler: ghc-8.10.4
+            allow-failure: false
+          - compiler: ghc-8.10.3
+            allow-failure: false
+          - compiler: ghc-8.10.2
+            allow-failure: false
+          - compiler: ghc-8.10.1
+            allow-failure: false
+          - compiler: ghc-8.8.4
+            allow-failure: false
+          - compiler: ghc-8.8.3
+            allow-failure: false
+          - compiler: ghc-8.8.2
+            allow-failure: false
+          - compiler: ghc-8.8.1
+            allow-failure: false
+          - compiler: ghc-8.6.5
+            allow-failure: false
+          - compiler: ghc-8.6.4
+            allow-failure: false
+          - compiler: ghc-8.6.3
+            allow-failure: false
+          - compiler: ghc-8.6.2
+            allow-failure: false
+          - compiler: ghc-8.6.1
+            allow-failure: false
+          - compiler: ghc-8.4.4
+            allow-failure: false
+          - compiler: ghc-8.4.3
+            allow-failure: false
+          - compiler: ghc-8.4.2
+            allow-failure: false
+          - compiler: ghc-8.4.1
+            allow-failure: false
+          - compiler: ghc-8.2.2
+            allow-failure: false
+          - compiler: ghc-8.2.1
+            allow-failure: false
+          - compiler: ghc-8.0.2
+            allow-failure: false
+          - compiler: ghc-8.0.1
+            allow-failure: false
+          - compiler: ghc-7.10.3
+            allow-failure: false
+          - compiler: ghc-7.10.2
+            allow-failure: false
+          - compiler: ghc-7.10.1
+            allow-failure: false
+          - compiler: ghc-7.8.4
+            allow-failure: false
+          - compiler: ghc-7.8.3
+            allow-failure: false
+          - compiler: ghc-7.8.2
+            allow-failure: false
+          - compiler: ghc-7.8.1
+            allow-failure: false
+      fail-fast: false
+    steps:
+      - name: apt
+        run: |
+          apt-get update
+          apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common
+          apt-add-repository -y 'ppa:hvr/ghc'
+          apt-get update
+          apt-get install -y $CC cabal-install-3.4
+        env:
+          CC: ${{ matrix.compiler }}
+      - name: Set PATH and environment variables
+        run: |
+          echo "$HOME/.cabal/bin" >> $GITHUB_PATH
+          echo "LANG=C.UTF-8" >> $GITHUB_ENV
+          echo "CABAL_DIR=$HOME/.cabal" >> $GITHUB_ENV
+          echo "CABAL_CONFIG=$HOME/.cabal/config" >> $GITHUB_ENV
+          HCDIR=$(echo "/opt/$CC" | sed 's/-/\//')
+          HCNAME=ghc
+          HC=$HCDIR/bin/$HCNAME
+          echo "HC=$HC" >> $GITHUB_ENV
+          echo "HCPKG=$HCDIR/bin/$HCNAME-pkg" >> $GITHUB_ENV
+          echo "HADDOCK=$HCDIR/bin/haddock" >> $GITHUB_ENV
+          echo "CABAL=/opt/cabal/3.4/bin/cabal -vnormal+nowrap" >> $GITHUB_ENV
+          HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
+          echo "HCNUMVER=$HCNUMVER" >> $GITHUB_ENV
+          echo "ARG_TESTS=--enable-tests" >> $GITHUB_ENV
+          echo "ARG_BENCH=--enable-benchmarks" >> $GITHUB_ENV
+          echo "HEADHACKAGE=false" >> $GITHUB_ENV
+          echo "ARG_COMPILER=--$HCNAME --with-compiler=$HC" >> $GITHUB_ENV
+          echo "GHCJSARITH=0" >> $GITHUB_ENV
+        env:
+          CC: ${{ matrix.compiler }}
+      - name: env
+        run: |
+          env
+      - name: write cabal config
+        run: |
+          mkdir -p $CABAL_DIR
+          cat >> $CABAL_CONFIG <<EOF
+          remote-build-reporting: anonymous
+          write-ghc-environment-files: never
+          remote-repo-cache: $CABAL_DIR/packages
+          logs-dir:          $CABAL_DIR/logs
+          world-file:        $CABAL_DIR/world
+          extra-prog-path:   $CABAL_DIR/bin
+          symlink-bindir:    $CABAL_DIR/bin
+          installdir:        $CABAL_DIR/bin
+          build-summary:     $CABAL_DIR/logs/build.log
+          store-dir:         $CABAL_DIR/store
+          install-dirs user
+            prefix: $CABAL_DIR
+          repository hackage.haskell.org
+            url: http://hackage.haskell.org/
+          EOF
+          cat $CABAL_CONFIG
+      - name: versions
+        run: |
+          $HC --version || true
+          $HC --print-project-git-commit-id || true
+          $CABAL --version || true
+      - name: update cabal index
+        run: |
+          $CABAL v2-update -v
+      - name: install cabal-plan
+        run: |
+          mkdir -p $HOME/.cabal/bin
+          curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > cabal-plan.xz
+          echo 'de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc  cabal-plan.xz' | sha256sum -c -
+          xz -d < cabal-plan.xz > $HOME/.cabal/bin/cabal-plan
+          rm -f cabal-plan.xz
+          chmod a+x $HOME/.cabal/bin/cabal-plan
+          cabal-plan --version
+      - name: checkout
+        uses: actions/checkout@v2
+        with:
+          path: source
+      - name: initial cabal.project for sdist
+        run: |
+          touch cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant" >> cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant-client" >> cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant-docs" >> cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant-server" >> cabal.project
+          cat cabal.project
+      - name: sdist
+        run: |
+          mkdir -p sdist
+          $CABAL sdist all --output-dir $GITHUB_WORKSPACE/sdist
+      - name: unpack
+        run: |
+          mkdir -p unpacked
+          find sdist -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C $GITHUB_WORKSPACE/unpacked -xzvf {} \;
+      - name: generate cabal.project
+        run: |
+          PKGDIR_servant="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+          echo "PKGDIR_servant=${PKGDIR_servant}" >> $GITHUB_ENV
+          PKGDIR_servant_client="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-client-[0-9.]*')"
+          echo "PKGDIR_servant_client=${PKGDIR_servant_client}" >> $GITHUB_ENV
+          PKGDIR_servant_docs="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-docs-[0-9.]*')"
+          echo "PKGDIR_servant_docs=${PKGDIR_servant_docs}" >> $GITHUB_ENV
+          PKGDIR_servant_server="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-server-[0-9.]*')"
+          echo "PKGDIR_servant_server=${PKGDIR_servant_server}" >> $GITHUB_ENV
+          touch cabal.project
+          touch cabal.project.local
+          echo "packages: ${PKGDIR_servant}" >> cabal.project
+          echo "packages: ${PKGDIR_servant_client}" >> cabal.project
+          echo "packages: ${PKGDIR_servant_docs}" >> cabal.project
+          echo "packages: ${PKGDIR_servant_server}" >> cabal.project
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant-client" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant-docs" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant-server" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          cat >> cabal.project <<EOF
+          EOF
+          $HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(servant|servant-client|servant-docs|servant-server)$/; }' >> cabal.project.local
+          cat cabal.project
+          cat cabal.project.local
+      - name: dump install plan
+        run: |
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
+          cabal-plan
+      - name: cache
+        uses: actions/cache@v2
+        with:
+          key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
+          path: ~/.cabal/store
+          restore-keys: ${{ runner.os }}-${{ matrix.compiler }}-
+      - name: install dependencies
+        run: |
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j2 all
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j2 all
+      - name: build w/o tests
+        run: |
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+      - name: build
+        run: |
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --write-ghc-environment-files=always
+      - name: tests
+        run: |
+          $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
+      - name: cabal check
+        run: |
+          cd ${PKGDIR_servant} || false
+          ${CABAL} -vnormal check
+          cd ${PKGDIR_servant_client} || false
+          ${CABAL} -vnormal check
+          cd ${PKGDIR_servant_docs} || false
+          ${CABAL} -vnormal check
+          cd ${PKGDIR_servant_server} || false
+          ${CABAL} -vnormal check
+      - name: haddock
+        run: |
+          $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
+      - name: unconstrained build
+        run: |
+          rm -f cabal.project.local
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
diff --git a/fixtures/copy-fields-none.project b/fixtures/copy-fields-none.project
new file mode 100644
--- /dev/null
+++ b/fixtures/copy-fields-none.project
@@ -0,0 +1,15 @@
+packages:
+  servant/
+  servant-client/
+  servant-docs/
+  servant-server/
+
+package servant
+  tests: False
+
+constraints: foundation >= 0.14
+
+allow-newer:
+  servant-js:servant
+allow-newer:
+  servant-js:servant-foreign
diff --git a/fixtures/copy-fields-none.travis b/fixtures/copy-fields-none.travis
new file mode 100644
--- /dev/null
+++ b/fixtures/copy-fields-none.travis
@@ -0,0 +1,245 @@
+# SUCCESS
+# *INFO* Generating Travis-CI config for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+# This Travis job script has been generated by a script via
+#
+#   haskell-ci '--copy-fields=none' 'travis' 'copy-fields-none.project'
+#
+# To regenerate the script (for example after adjusting tested-with) run
+#
+#   haskell-ci regenerate
+#
+# For more information, see https://github.com/haskell-CI/haskell-ci
+#
+version: ~> 1.0
+language: c
+os: linux
+dist: xenial
+git:
+  # whether to recursively clone submodules
+  submodules: false
+cache:
+  directories:
+    - $HOME/.cabal/packages
+    - $HOME/.cabal/store
+    - $HOME/.hlint
+before_cache:
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log
+  # remove files that are regenerated by 'cabal update'
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx
+  - rm -rfv $CABALHOME/packages/head.hackage
+jobs:
+  include:
+    - compiler: ghc-8.10.4
+      addons: {"apt":{"packages":["ghc-8.10.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.3
+      addons: {"apt":{"packages":["ghc-8.10.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.2
+      addons: {"apt":{"packages":["ghc-8.10.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.1
+      addons: {"apt":{"packages":["ghc-8.10.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.4
+      addons: {"apt":{"packages":["ghc-8.8.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.3
+      addons: {"apt":{"packages":["ghc-8.8.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.2
+      addons: {"apt":{"packages":["ghc-8.8.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.1
+      addons: {"apt":{"packages":["ghc-8.8.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.5
+      addons: {"apt":{"packages":["ghc-8.6.5","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.4
+      addons: {"apt":{"packages":["ghc-8.6.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.3
+      addons: {"apt":{"packages":["ghc-8.6.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.2
+      addons: {"apt":{"packages":["ghc-8.6.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.1
+      addons: {"apt":{"packages":["ghc-8.6.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.4
+      addons: {"apt":{"packages":["ghc-8.4.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.3
+      addons: {"apt":{"packages":["ghc-8.4.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.2
+      addons: {"apt":{"packages":["ghc-8.4.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.1
+      addons: {"apt":{"packages":["ghc-8.4.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.2.2
+      addons: {"apt":{"packages":["ghc-8.2.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.2.1
+      addons: {"apt":{"packages":["ghc-8.2.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.0.2
+      addons: {"apt":{"packages":["ghc-8.0.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.0.1
+      addons: {"apt":{"packages":["ghc-8.0.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.3
+      addons: {"apt":{"packages":["ghc-7.10.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.2
+      addons: {"apt":{"packages":["ghc-7.10.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.1
+      addons: {"apt":{"packages":["ghc-7.10.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.4
+      addons: {"apt":{"packages":["ghc-7.8.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.3
+      addons: {"apt":{"packages":["ghc-7.8.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.2
+      addons: {"apt":{"packages":["ghc-7.8.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.1
+      addons: {"apt":{"packages":["ghc-7.8.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+before_install:
+  - HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//')
+  - WITHCOMPILER="-w $HC"
+  - HADDOCK=$(echo "/opt/$CC/bin/haddock" | sed 's/-/\//')
+  - HCPKG="$HC-pkg"
+  - unset CC
+  - CABAL=/opt/ghc/bin/cabal
+  - CABALHOME=$HOME/.cabal
+  - export PATH="$CABALHOME/bin:$PATH"
+  - TOP=$(pwd)
+  - "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')"
+  - echo $HCNUMVER
+  - CABAL="$CABAL -vnormal+nowrap"
+  - set -o pipefail
+  - TEST=--enable-tests
+  - BENCH=--enable-benchmarks
+  - HEADHACKAGE=false
+  - rm -f $CABALHOME/config
+  - |
+    echo "verbose: normal +nowrap +markoutput"          >> $CABALHOME/config
+    echo "remote-build-reporting: anonymous"            >> $CABALHOME/config
+    echo "write-ghc-environment-files: never"           >> $CABALHOME/config
+    echo "remote-repo-cache: $CABALHOME/packages"       >> $CABALHOME/config
+    echo "logs-dir:          $CABALHOME/logs"           >> $CABALHOME/config
+    echo "world-file:        $CABALHOME/world"          >> $CABALHOME/config
+    echo "extra-prog-path:   $CABALHOME/bin"            >> $CABALHOME/config
+    echo "symlink-bindir:    $CABALHOME/bin"            >> $CABALHOME/config
+    echo "installdir:        $CABALHOME/bin"            >> $CABALHOME/config
+    echo "build-summary:     $CABALHOME/logs/build.log" >> $CABALHOME/config
+    echo "store-dir:         $CABALHOME/store"          >> $CABALHOME/config
+    echo "install-dirs user"                            >> $CABALHOME/config
+    echo "  prefix: $CABALHOME"                         >> $CABALHOME/config
+    echo "repository hackage.haskell.org"               >> $CABALHOME/config
+    echo "  url: http://hackage.haskell.org/"           >> $CABALHOME/config
+install:
+  - ${CABAL} --version
+  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
+  - |
+    echo "program-default-options"                >> $CABALHOME/config
+    echo "  ghc-options: $GHCJOBS +RTS -M6G -RTS" >> $CABALHOME/config
+  - cat $CABALHOME/config
+  - rm -fv cabal.project cabal.project.local cabal.project.freeze
+  - travis_retry ${CABAL} v2-update -v
+  # Generate cabal.project
+  - rm -rf cabal.project cabal.project.local cabal.project.freeze
+  - touch cabal.project
+  - |
+    echo "packages: servant" >> cabal.project
+    echo "packages: servant-client" >> cabal.project
+    echo "packages: servant-docs" >> cabal.project
+    echo "packages: servant-server" >> cabal.project
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-client' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-docs' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-server' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - |
+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
+  - cat cabal.project || true
+  - cat cabal.project.local || true
+  - if [ -f "servant/configure.ac" ]; then (cd "servant" && autoreconf -i); fi
+  - if [ -f "servant-client/configure.ac" ]; then (cd "servant-client" && autoreconf -i); fi
+  - if [ -f "servant-docs/configure.ac" ]; then (cd "servant-docs" && autoreconf -i); fi
+  - if [ -f "servant-server/configure.ac" ]; then (cd "servant-server" && autoreconf -i); fi
+  - ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH}
+  - "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
+  - rm  cabal.project.freeze
+  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} --dep -j2 all
+  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --dep -j2 all
+script:
+  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
+  # Packaging...
+  - ${CABAL} v2-sdist all
+  # Unpacking...
+  - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
+  - cd ${DISTDIR} || false
+  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \;
+  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm       '{}' \;
+  - PKGDIR_servant="$(find . -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+  - PKGDIR_servant_client="$(find . -maxdepth 1 -type d -regex '.*/servant-client-[0-9.]*')"
+  - PKGDIR_servant_docs="$(find . -maxdepth 1 -type d -regex '.*/servant-docs-[0-9.]*')"
+  - PKGDIR_servant_server="$(find . -maxdepth 1 -type d -regex '.*/servant-server-[0-9.]*')"
+  # Generate cabal.project
+  - rm -rf cabal.project cabal.project.local cabal.project.freeze
+  - touch cabal.project
+  - |
+    echo "packages: ${PKGDIR_servant}" >> cabal.project
+    echo "packages: ${PKGDIR_servant_client}" >> cabal.project
+    echo "packages: ${PKGDIR_servant_docs}" >> cabal.project
+    echo "packages: ${PKGDIR_servant_server}" >> cabal.project
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-client' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-docs' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-server' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - |
+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
+  - cat cabal.project || true
+  - cat cabal.project.local || true
+  # Building...
+  # this builds all libraries and executables (without tests/benchmarks)
+  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
+  # Building with tests and benchmarks...
+  # build & run tests, build benchmarks
+  - ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} all --write-ghc-environment-files=always
+  # Testing...
+  - ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all --test-show-details=direct
+  # cabal check...
+  - (cd ${PKGDIR_servant} && ${CABAL} -vnormal check)
+  - (cd ${PKGDIR_servant_client} && ${CABAL} -vnormal check)
+  - (cd ${PKGDIR_servant_docs} && ${CABAL} -vnormal check)
+  - (cd ${PKGDIR_servant_server} && ${CABAL} -vnormal check)
+  # haddock...
+  - ${CABAL} v2-haddock $WITHCOMPILER --with-haddock $HADDOCK ${TEST} ${BENCH} all
+  # Building without installed constraints for packages in global-db...
+  - rm -f cabal.project.local
+  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
+
+# REGENDATA ["--copy-fields=none","travis","copy-fields-none.project"]
+# EOF
diff --git a/fixtures/copy-fields-some.args b/fixtures/copy-fields-some.args
new file mode 100644
--- /dev/null
+++ b/fixtures/copy-fields-some.args
@@ -0,0 +1,1 @@
+--copy-fields=some
diff --git a/fixtures/copy-fields-some.bash b/fixtures/copy-fields-some.bash
new file mode 100644
--- /dev/null
+++ b/fixtures/copy-fields-some.bash
@@ -0,0 +1,544 @@
+# SUCCESS
+# *INFO* Generating Bash script for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+#!/bin/bash
+# shellcheck disable=SC2086,SC2016,SC2046
+# REGENDATA ["--copy-fields=some","bash","copy-fields-some.project"]
+
+set -o pipefail
+
+# Mode
+##############################################################################
+
+if [ "$1" = "indocker" ]; then
+    INDOCKER=true
+    shift
+else
+    INDOCKER=false
+fi
+
+# Run configuration
+##############################################################################
+
+CFG_CABAL_STORE_CACHE=""
+CFG_CABAL_REPO_CACHE=""
+CFG_JOBS="8.10.4 8.10.3 8.10.2 8.10.1 8.8.4 8.8.3 8.8.2 8.8.1 8.6.5 8.6.4 8.6.3 8.6.2 8.6.1 8.4.4 8.4.3 8.4.2 8.4.1 8.2.2 8.2.1 8.0.2 8.0.1 7.10.3 7.10.2 7.10.1 7.8.4 7.8.3 7.8.2 7.8.1"
+CFG_CABAL_UPDATE=false
+
+SCRIPT_NAME=$(basename "$0")
+START_TIME="$(date +'%s')"
+
+XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config}
+
+# Job configuration
+##############################################################################
+
+GHC_VERSION="non-existing"
+CABAL_VERSION=3.2
+HEADHACKAGE=false
+
+# Locale
+##############################################################################
+
+export LC_ALL=C.UTF-8
+
+# Utilities
+##############################################################################
+
+SGR_RED='\033[1;31m'
+SGR_GREEN='\033[1;32m'
+SGR_BLUE='\033[1;34m'
+SGR_CYAN='\033[1;96m'
+SGR_RESET='\033[0m' # No Color
+
+put_info() {
+    printf "$SGR_CYAN%s$SGR_RESET\n" "### $*"
+}
+
+put_error() {
+    printf "$SGR_RED%s$SGR_RESET\n" "!!! $*"
+}
+
+run_cmd() {
+    local PRETTYCMD="$*"
+    local PROMPT
+    if $INDOCKER; then
+        PROMPT="$(pwd) >>>"
+    else
+        PROMPT=">>>"
+    fi
+
+    printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+
+    local start_time end_time cmd_duration total_duration
+    start_time=$(date +'%s')
+
+    "$@"
+    local RET=$?
+
+    end_time=$(date +'%s')
+    cmd_duration=$((end_time - start_time))
+    total_duration=$((end_time - START_TIME))
+
+    cmd_min=$((cmd_duration / 60))
+    cmd_sec=$((cmd_duration % 60))
+
+    total_min=$((total_duration / 60))
+    total_sec=$((total_duration % 60))
+
+    if [ $RET -eq 0 ]; then
+        printf "$SGR_GREEN%s$SGR_RESET (%dm%02ds; %dm%02ds)\n" "<<< $PRETTYCMD" "$cmd_min" "$cmd_sec" "$total_min" "$total_sec"
+    else
+        printf "$SGR_RED%s$SGR_RESET\n" "!!! $PRETTYCMD"
+        exit 1
+    fi
+}
+
+run_cmd_if() {
+    local COND=$1
+    shift
+
+    if [ $COND -eq 1 ]; then
+        run_cmd "$@"
+    else
+        local PRETTYCMD="$*"
+        local PROMPT
+        PROMPT="$(pwd) (skipping) >>>"
+
+        printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+    fi
+}
+
+run_cmd_unchecked() {
+    local PRETTYCMD="$*"
+    local PROMPT
+    if $INDOCKER; then
+        PROMPT="$(pwd) >>>"
+    else
+        PROMPT=">>>"
+    fi
+
+    printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+
+    local start_time end_time cmd_duration total_duration cmd_min cmd_sec total_min total_sec
+    start_time=$(date +'%s')
+
+    "$@"
+
+    end_time=$(date +'%s')
+    cmd_duration=$((end_time - start_time))
+    total_duration=$((end_time - START_TIME))
+
+    cmd_min=$((cmd_duration / 60))
+    cmd_sec=$((cmd_duration % 60))
+
+    total_min=$((total_duration / 60))
+    total_sec=$((total_duration % 60))
+
+    printf "$SGR_GREEN%s$SGR_RESET (%dm%02ds; %dm%02ds)\n" "<<< $PRETTYCMD" "$cmd_min" "$cmd_sec" "$total_min" "$total_sec"
+}
+
+change_dir() {
+    local DIR=$1
+    if [ -d "$DIR" ]; then
+        printf "$SGR_BLUE%s$SGR_RESET\n" "change directory to $DIR"
+        cd "$DIR" || exit 1
+    else
+        printf "$SGR_RED%s$SGR_RESET\n" "!!! cd $DIR"
+        exit 1
+    fi
+}
+
+change_dir_if() {
+    local COND=$1
+    local DIR=$2
+
+    if [ $COND -ne 0 ]; then
+        change_dir "$DIR"
+    fi
+}
+
+echo_to() {
+    local DEST=$1
+    local CONTENTS=$2
+
+    echo "$CONTENTS" >> "$DEST"
+}
+
+echo_if_to() {
+    local COND=$1
+    local DEST=$2
+    local CONTENTS=$3
+
+    if [ $COND -ne 0 ]; then
+        echo_to "$DEST" "$CONTENTS"
+    fi
+}
+
+install_cabalplan() {
+    put_info "installing cabal-plan"
+
+    if [ ! -e $CABAL_REPOCACHE/downloads/cabal-plan ]; then
+        curl -L https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > /tmp/cabal-plan.xz || exit 1
+        (cd /tmp && echo "de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc  cabal-plan.xz" | sha256sum -c -)|| exit 1
+        mkdir -p $CABAL_REPOCACHE/downloads
+        xz -d < /tmp/cabal-plan.xz > $CABAL_REPOCACHE/downloads/cabal-plan || exit 1
+        chmod a+x $CABAL_REPOCACHE/downloads/cabal-plan || exit 1
+    fi
+
+    mkdir -p $CABAL_DIR/bin || exit 1
+    ln -s $CABAL_REPOCACHE/downloads/cabal-plan $CABAL_DIR/bin/cabal-plan || exit 1
+}
+
+# Help
+##############################################################################
+
+show_usage() {
+cat <<EOF
+./haskell-ci.sh - build & test
+
+Usage: ./haskell-ci.sh [options]
+  A script to run automated checks locally (using Docker)
+
+Available options:
+  --jobs JOBS               Jobs to run (default: $CFG_JOBS)
+  --cabal-store-cache PATH  Directory to use for cabal-store-cache
+  --cabal-repo-cache PATH   Directory to use for cabal-repo-cache
+  --skip-cabal-update       Skip cabal update (useful with --cabal-repo-cache)
+  --no-skip-cabal-update
+  --help                    Print this message
+
+EOF
+}
+
+# getopt
+#######################################################################
+
+process_cli_options() {
+    while [ $# -gt 0 ]; do
+        arg=$1
+        case $arg in
+            --help)
+                show_usage
+                exit
+                ;;
+            --jobs)
+                CFG_JOBS=$2
+                shift
+                shift
+                ;;
+            --cabal-store-cache)
+                CFG_CABAL_STORE_CACHE=$2
+                shift
+                shift
+                ;;
+            --cabal-repo-cache)
+                CFG_CABAL_REPO_CACHE=$2
+                shift
+                shift
+                ;;
+            --skip-cabal-update)
+                CFG_CABAL_UPDATE=false
+                shift
+                ;;
+            --no-skip-cabal-update)
+                CFG_CABAL_UPDATE=true
+                shift
+                ;;
+            *)
+                echo "Unknown option $arg"
+                exit 1
+        esac
+    done
+}
+
+process_indocker_options () {
+    while [ $# -gt 0 ]; do
+        arg=$1
+
+        case $arg in
+            --ghc-version)
+                GHC_VERSION=$2
+                shift
+                shift
+                ;;
+            --cabal-version)
+                CABAL_VERSION=$2
+                shift
+                shift
+                ;;
+            --start-time)
+                START_TIME=$2
+                shift
+                shift
+                ;;
+            --cabal-update)
+                CABAL_UPDATE=$2
+                shift
+                shift
+                ;;
+            *)
+                echo "Unknown option $arg"
+                exit 1
+        esac
+    done
+}
+
+if $INDOCKER; then
+    process_indocker_options "$@"
+
+else
+    if [ -f "$XDG_CONFIG_HOME/haskell-ci/bash.config" ]; then
+        process_cli_options $(cat "$XDG_CONFIG_HOME/haskell-ci/bash.config")
+    fi
+
+    process_cli_options "$@"
+
+    put_info "jobs:              $CFG_JOBS"
+    put_info "cabal-store-cache: $CFG_CABAL_STORE_CACHE"
+    put_info "cabal-repo-cache:  $CFG_CABAL_REPO_CACHE"
+    put_info "cabal-update:      $CFG_CABAL_UPDATE"
+fi
+
+# Constants
+##############################################################################
+
+SRCDIR=/hsci/src
+BUILDDIR=/hsci/build
+CABAL_DIR="$BUILDDIR/cabal"
+CABAL_REPOCACHE=/hsci/cabal-repocache
+CABAL_STOREDIR=/hsci/store
+
+# Docker invoke
+##############################################################################
+
+# if cache directory is specified, use it.
+# Otherwise use another tmpfs host
+if [ -z "$CFG_CABAL_STORE_CACHE" ]; then
+    CABALSTOREARG="--tmpfs $CABAL_STOREDIR:exec"
+else
+    CABALSTOREARG="--volume $CFG_CABAL_STORE_CACHE:$CABAL_STOREDIR"
+fi
+
+if [ -z "$CFG_CABAL_REPO_CACHE" ]; then
+    CABALREPOARG="--tmpfs $CABAL_REPOCACHE:exec"
+else
+    CABALREPOARG="--volume $CFG_CABAL_REPO_CACHE:$CABAL_REPOCACHE"
+fi
+
+echo_docker_cmd() {
+    local GHCVER=$1
+
+    # TODO: mount /hsci/src:ro (readonly)
+    echo docker run \
+        --tty \
+        --interactive \
+        --rm \
+        --label haskell-ci \
+        --volume "$(pwd):/hsci/src" \
+        $CABALSTOREARG \
+        $CABALREPOARG \
+        --tmpfs /tmp:exec \
+        --tmpfs /hsci/build:exec \
+        --workdir /hsci/build \
+        "phadej/ghc:$GHCVER-bionic" \
+        "/bin/bash" "/hsci/src/$SCRIPT_NAME" indocker \
+        --ghc-version "$GHCVER" \
+        --cabal-update "$CFG_CABAL_UPDATE" \
+        --start-time "$START_TIME"
+}
+
+# if we are not in docker, loop through jobs
+if ! $INDOCKER; then
+    for JOB in $CFG_JOBS; do
+        put_info "Running in docker: $JOB"
+        run_cmd $(echo_docker_cmd "$JOB")
+    done
+
+    run_cmd echo "ALL OK"
+    exit 0
+fi
+
+# Otherwise we are in docker, and the rest of script executes
+put_info "In docker"
+
+# Environment
+##############################################################################
+
+GHCDIR=/opt/ghc/$GHC_VERSION
+
+HC=$GHCDIR/bin/ghc
+HCPKG=$GHCDIR/bin/ghc-pkg
+HADDOCK=$GHCDIR/bin/haddock
+
+CABAL=/opt/cabal/$CABAL_VERSION/bin/cabal
+
+CABAL="$CABAL -vnormal+nowrap"
+
+export CABAL_DIR
+export CABAL_CONFIG="$BUILDDIR/cabal/config"
+
+PATH="$CABAL_DIR/bin:$PATH"
+
+# HCNUMVER
+HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
+GHCJSARITH=0
+
+put_info "HCNUMVER: $HCNUMVER"
+
+# Args for shorter/nicer commands
+if [ 1 -ne 0 ] ; then ARG_TESTS=--enable-tests; else ARG_TESTS=--disable-tests; fi
+if [ 1 -ne 0 ] ; then ARG_BENCH=--enable-benchmarks; else ARG_BENCH=--disable-benchmarks; fi
+ARG_COMPILER="--ghc --with-compiler=$HC"
+
+put_info "tests/benchmarks: $ARG_TESTS $ARG_BENCH"
+
+# Apt dependencies
+##############################################################################
+
+
+# Cabal config
+##############################################################################
+
+mkdir -p $BUILDDIR/cabal
+
+cat > $BUILDDIR/cabal/config <<EOF
+remote-build-reporting: anonymous
+write-ghc-environment-files: always
+remote-repo-cache: $CABAL_REPOCACHE
+logs-dir:          $CABAL_DIR/logs
+world-file:        $CABAL_DIR/world
+extra-prog-path:   $CABAL_DIR/bin
+symlink-bindir:    $CABAL_DIR/bin
+installdir:        $CABAL_DIR/bin
+build-summary:     $CABAL_DIR/logs/build.log
+store-dir:         $CABAL_STOREDIR
+install-dirs user
+  prefix: $CABAL_DIR
+repository hackage.haskell.org
+  url: http://hackage.haskell.org/
+EOF
+
+if $HEADHACKAGE; then
+    put_error "head.hackage is not implemented"
+    exit 1
+fi
+
+run_cmd cat "$BUILDDIR/cabal/config"
+
+# Version
+##############################################################################
+
+put_info "Versions"
+run_cmd $HC --version
+run_cmd_unchecked $HC --print-project-git-commit-id
+run_cmd $CABAL --version
+
+# Build script
+##############################################################################
+
+# update cabal index
+if $CABAL_UPDATE; then
+    put_info "Updating Hackage index"
+    run_cmd $CABAL v2-update -v
+fi
+
+# install cabal-plan
+install_cabalplan
+run_cmd cabal-plan --version
+
+# initial cabal.project for sdist
+put_info "initial cabal.project for sdist"
+change_dir "$BUILDDIR"
+run_cmd touch cabal.project
+echo_to cabal.project "packages: $SRCDIR/servant"
+echo_to cabal.project "packages: $SRCDIR/servant-client"
+echo_to cabal.project "packages: $SRCDIR/servant-docs"
+echo_to cabal.project "packages: $SRCDIR/servant-server"
+run_cmd cat cabal.project
+
+# sdist
+put_info "sdist"
+run_cmd mkdir -p "$BUILDDIR/sdist"
+run_cmd $CABAL sdist all --output-dir "$BUILDDIR/sdist"
+
+# unpack
+put_info "unpack"
+change_dir "$BUILDDIR"
+run_cmd mkdir -p "$BUILDDIR/unpacked"
+run_cmd find "$BUILDDIR/sdist" -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C "$BUILDDIR/unpacked" -xzvf {} \;
+
+# generate cabal.project
+put_info "generate cabal.project"
+PKGDIR_servant="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+PKGDIR_servant_client="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-client-[0-9.]*')"
+PKGDIR_servant_docs="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-docs-[0-9.]*')"
+PKGDIR_servant_server="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-server-[0-9.]*')"
+run_cmd touch cabal.project
+run_cmd touch cabal.project.local
+echo_to cabal.project "packages: ${PKGDIR_servant}"
+echo_to cabal.project "packages: ${PKGDIR_servant_client}"
+echo_to cabal.project "packages: ${PKGDIR_servant_docs}"
+echo_to cabal.project "packages: ${PKGDIR_servant_server}"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant-client"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant-docs"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant-server"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+cat >> cabal.project <<EOF
+constraints: foundation >= 0.14
+allow-newer: servant-js:servant
+allow-newer: servant-js:servant-foreign
+EOF
+$HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(servant|servant-client|servant-docs|servant-server)$/; }' >> cabal.project.local
+run_cmd cat cabal.project
+run_cmd cat cabal.project.local
+
+# dump install plan
+put_info "dump install plan"
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
+run_cmd cabal-plan
+
+# install dependencies
+put_info "install dependencies"
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j all
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j all
+
+# build w/o tests
+put_info "build w/o tests"
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+
+# build
+put_info "build"
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all
+
+# tests
+put_info "tests"
+run_cmd $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
+
+# cabal check
+put_info "cabal check"
+change_dir "${PKGDIR_servant}"
+run_cmd ${CABAL} -vnormal check
+change_dir "${PKGDIR_servant_client}"
+run_cmd ${CABAL} -vnormal check
+change_dir "${PKGDIR_servant_docs}"
+run_cmd ${CABAL} -vnormal check
+change_dir "${PKGDIR_servant_server}"
+run_cmd ${CABAL} -vnormal check
+change_dir "$BUILDDIR"
+
+# haddock
+put_info "haddock"
+run_cmd $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
+
+# unconstrained build
+put_info "unconstrained build"
+run_cmd rm -f cabal.project.local
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+
+
+# Done
+run_cmd echo OK
diff --git a/fixtures/copy-fields-some.github b/fixtures/copy-fields-some.github
new file mode 100644
--- /dev/null
+++ b/fixtures/copy-fields-some.github
@@ -0,0 +1,249 @@
+# SUCCESS
+# *INFO* Generating GitHub config for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+# This GitHub workflow config has been generated by a script via
+#
+#   haskell-ci '--copy-fields=some' 'github' 'copy-fields-some.project'
+#
+# To regenerate the script (for example after adjusting tested-with) run
+#
+#   haskell-ci regenerate
+#
+# For more information, see https://github.com/haskell-CI/haskell-ci
+#
+# REGENDATA ["--copy-fields=some","github","copy-fields-some.project"]
+#
+name: Haskell-CI
+on:
+  - push
+  - pull_request
+jobs:
+  linux:
+    name: Haskell-CI - Linux - ${{ matrix.compiler }}
+    runs-on: ubuntu-18.04
+    container:
+      image: buildpack-deps:bionic
+    continue-on-error: ${{ matrix.allow-failure }}
+    strategy:
+      matrix:
+        include:
+          - compiler: ghc-8.10.4
+            allow-failure: false
+          - compiler: ghc-8.10.3
+            allow-failure: false
+          - compiler: ghc-8.10.2
+            allow-failure: false
+          - compiler: ghc-8.10.1
+            allow-failure: false
+          - compiler: ghc-8.8.4
+            allow-failure: false
+          - compiler: ghc-8.8.3
+            allow-failure: false
+          - compiler: ghc-8.8.2
+            allow-failure: false
+          - compiler: ghc-8.8.1
+            allow-failure: false
+          - compiler: ghc-8.6.5
+            allow-failure: false
+          - compiler: ghc-8.6.4
+            allow-failure: false
+          - compiler: ghc-8.6.3
+            allow-failure: false
+          - compiler: ghc-8.6.2
+            allow-failure: false
+          - compiler: ghc-8.6.1
+            allow-failure: false
+          - compiler: ghc-8.4.4
+            allow-failure: false
+          - compiler: ghc-8.4.3
+            allow-failure: false
+          - compiler: ghc-8.4.2
+            allow-failure: false
+          - compiler: ghc-8.4.1
+            allow-failure: false
+          - compiler: ghc-8.2.2
+            allow-failure: false
+          - compiler: ghc-8.2.1
+            allow-failure: false
+          - compiler: ghc-8.0.2
+            allow-failure: false
+          - compiler: ghc-8.0.1
+            allow-failure: false
+          - compiler: ghc-7.10.3
+            allow-failure: false
+          - compiler: ghc-7.10.2
+            allow-failure: false
+          - compiler: ghc-7.10.1
+            allow-failure: false
+          - compiler: ghc-7.8.4
+            allow-failure: false
+          - compiler: ghc-7.8.3
+            allow-failure: false
+          - compiler: ghc-7.8.2
+            allow-failure: false
+          - compiler: ghc-7.8.1
+            allow-failure: false
+      fail-fast: false
+    steps:
+      - name: apt
+        run: |
+          apt-get update
+          apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common
+          apt-add-repository -y 'ppa:hvr/ghc'
+          apt-get update
+          apt-get install -y $CC cabal-install-3.4
+        env:
+          CC: ${{ matrix.compiler }}
+      - name: Set PATH and environment variables
+        run: |
+          echo "$HOME/.cabal/bin" >> $GITHUB_PATH
+          echo "LANG=C.UTF-8" >> $GITHUB_ENV
+          echo "CABAL_DIR=$HOME/.cabal" >> $GITHUB_ENV
+          echo "CABAL_CONFIG=$HOME/.cabal/config" >> $GITHUB_ENV
+          HCDIR=$(echo "/opt/$CC" | sed 's/-/\//')
+          HCNAME=ghc
+          HC=$HCDIR/bin/$HCNAME
+          echo "HC=$HC" >> $GITHUB_ENV
+          echo "HCPKG=$HCDIR/bin/$HCNAME-pkg" >> $GITHUB_ENV
+          echo "HADDOCK=$HCDIR/bin/haddock" >> $GITHUB_ENV
+          echo "CABAL=/opt/cabal/3.4/bin/cabal -vnormal+nowrap" >> $GITHUB_ENV
+          HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
+          echo "HCNUMVER=$HCNUMVER" >> $GITHUB_ENV
+          echo "ARG_TESTS=--enable-tests" >> $GITHUB_ENV
+          echo "ARG_BENCH=--enable-benchmarks" >> $GITHUB_ENV
+          echo "HEADHACKAGE=false" >> $GITHUB_ENV
+          echo "ARG_COMPILER=--$HCNAME --with-compiler=$HC" >> $GITHUB_ENV
+          echo "GHCJSARITH=0" >> $GITHUB_ENV
+        env:
+          CC: ${{ matrix.compiler }}
+      - name: env
+        run: |
+          env
+      - name: write cabal config
+        run: |
+          mkdir -p $CABAL_DIR
+          cat >> $CABAL_CONFIG <<EOF
+          remote-build-reporting: anonymous
+          write-ghc-environment-files: never
+          remote-repo-cache: $CABAL_DIR/packages
+          logs-dir:          $CABAL_DIR/logs
+          world-file:        $CABAL_DIR/world
+          extra-prog-path:   $CABAL_DIR/bin
+          symlink-bindir:    $CABAL_DIR/bin
+          installdir:        $CABAL_DIR/bin
+          build-summary:     $CABAL_DIR/logs/build.log
+          store-dir:         $CABAL_DIR/store
+          install-dirs user
+            prefix: $CABAL_DIR
+          repository hackage.haskell.org
+            url: http://hackage.haskell.org/
+          EOF
+          cat $CABAL_CONFIG
+      - name: versions
+        run: |
+          $HC --version || true
+          $HC --print-project-git-commit-id || true
+          $CABAL --version || true
+      - name: update cabal index
+        run: |
+          $CABAL v2-update -v
+      - name: install cabal-plan
+        run: |
+          mkdir -p $HOME/.cabal/bin
+          curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > cabal-plan.xz
+          echo 'de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc  cabal-plan.xz' | sha256sum -c -
+          xz -d < cabal-plan.xz > $HOME/.cabal/bin/cabal-plan
+          rm -f cabal-plan.xz
+          chmod a+x $HOME/.cabal/bin/cabal-plan
+          cabal-plan --version
+      - name: checkout
+        uses: actions/checkout@v2
+        with:
+          path: source
+      - name: initial cabal.project for sdist
+        run: |
+          touch cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant" >> cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant-client" >> cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant-docs" >> cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant-server" >> cabal.project
+          cat cabal.project
+      - name: sdist
+        run: |
+          mkdir -p sdist
+          $CABAL sdist all --output-dir $GITHUB_WORKSPACE/sdist
+      - name: unpack
+        run: |
+          mkdir -p unpacked
+          find sdist -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C $GITHUB_WORKSPACE/unpacked -xzvf {} \;
+      - name: generate cabal.project
+        run: |
+          PKGDIR_servant="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+          echo "PKGDIR_servant=${PKGDIR_servant}" >> $GITHUB_ENV
+          PKGDIR_servant_client="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-client-[0-9.]*')"
+          echo "PKGDIR_servant_client=${PKGDIR_servant_client}" >> $GITHUB_ENV
+          PKGDIR_servant_docs="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-docs-[0-9.]*')"
+          echo "PKGDIR_servant_docs=${PKGDIR_servant_docs}" >> $GITHUB_ENV
+          PKGDIR_servant_server="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-server-[0-9.]*')"
+          echo "PKGDIR_servant_server=${PKGDIR_servant_server}" >> $GITHUB_ENV
+          touch cabal.project
+          touch cabal.project.local
+          echo "packages: ${PKGDIR_servant}" >> cabal.project
+          echo "packages: ${PKGDIR_servant_client}" >> cabal.project
+          echo "packages: ${PKGDIR_servant_docs}" >> cabal.project
+          echo "packages: ${PKGDIR_servant_server}" >> cabal.project
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant-client" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant-docs" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant-server" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          cat >> cabal.project <<EOF
+          constraints: foundation >= 0.14
+          allow-newer: servant-js:servant
+          allow-newer: servant-js:servant-foreign
+          EOF
+          $HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(servant|servant-client|servant-docs|servant-server)$/; }' >> cabal.project.local
+          cat cabal.project
+          cat cabal.project.local
+      - name: dump install plan
+        run: |
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
+          cabal-plan
+      - name: cache
+        uses: actions/cache@v2
+        with:
+          key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
+          path: ~/.cabal/store
+          restore-keys: ${{ runner.os }}-${{ matrix.compiler }}-
+      - name: install dependencies
+        run: |
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j2 all
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j2 all
+      - name: build w/o tests
+        run: |
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+      - name: build
+        run: |
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --write-ghc-environment-files=always
+      - name: tests
+        run: |
+          $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
+      - name: cabal check
+        run: |
+          cd ${PKGDIR_servant} || false
+          ${CABAL} -vnormal check
+          cd ${PKGDIR_servant_client} || false
+          ${CABAL} -vnormal check
+          cd ${PKGDIR_servant_docs} || false
+          ${CABAL} -vnormal check
+          cd ${PKGDIR_servant_server} || false
+          ${CABAL} -vnormal check
+      - name: haddock
+        run: |
+          $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
+      - name: unconstrained build
+        run: |
+          rm -f cabal.project.local
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
diff --git a/fixtures/copy-fields-some.project b/fixtures/copy-fields-some.project
new file mode 100644
--- /dev/null
+++ b/fixtures/copy-fields-some.project
@@ -0,0 +1,15 @@
+packages:
+  servant/
+  servant-client/
+  servant-docs/
+  servant-server/
+
+package servant
+  tests: False
+
+constraints: foundation >= 0.14
+
+allow-newer:
+  servant-js:servant
+allow-newer:
+  servant-js:servant-foreign
diff --git a/fixtures/copy-fields-some.travis b/fixtures/copy-fields-some.travis
new file mode 100644
--- /dev/null
+++ b/fixtures/copy-fields-some.travis
@@ -0,0 +1,251 @@
+# SUCCESS
+# *INFO* Generating Travis-CI config for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+# This Travis job script has been generated by a script via
+#
+#   haskell-ci '--copy-fields=some' 'travis' 'copy-fields-some.project'
+#
+# To regenerate the script (for example after adjusting tested-with) run
+#
+#   haskell-ci regenerate
+#
+# For more information, see https://github.com/haskell-CI/haskell-ci
+#
+version: ~> 1.0
+language: c
+os: linux
+dist: xenial
+git:
+  # whether to recursively clone submodules
+  submodules: false
+cache:
+  directories:
+    - $HOME/.cabal/packages
+    - $HOME/.cabal/store
+    - $HOME/.hlint
+before_cache:
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log
+  # remove files that are regenerated by 'cabal update'
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx
+  - rm -rfv $CABALHOME/packages/head.hackage
+jobs:
+  include:
+    - compiler: ghc-8.10.4
+      addons: {"apt":{"packages":["ghc-8.10.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.3
+      addons: {"apt":{"packages":["ghc-8.10.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.2
+      addons: {"apt":{"packages":["ghc-8.10.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.1
+      addons: {"apt":{"packages":["ghc-8.10.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.4
+      addons: {"apt":{"packages":["ghc-8.8.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.3
+      addons: {"apt":{"packages":["ghc-8.8.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.2
+      addons: {"apt":{"packages":["ghc-8.8.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.1
+      addons: {"apt":{"packages":["ghc-8.8.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.5
+      addons: {"apt":{"packages":["ghc-8.6.5","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.4
+      addons: {"apt":{"packages":["ghc-8.6.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.3
+      addons: {"apt":{"packages":["ghc-8.6.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.2
+      addons: {"apt":{"packages":["ghc-8.6.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.1
+      addons: {"apt":{"packages":["ghc-8.6.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.4
+      addons: {"apt":{"packages":["ghc-8.4.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.3
+      addons: {"apt":{"packages":["ghc-8.4.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.2
+      addons: {"apt":{"packages":["ghc-8.4.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.1
+      addons: {"apt":{"packages":["ghc-8.4.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.2.2
+      addons: {"apt":{"packages":["ghc-8.2.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.2.1
+      addons: {"apt":{"packages":["ghc-8.2.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.0.2
+      addons: {"apt":{"packages":["ghc-8.0.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.0.1
+      addons: {"apt":{"packages":["ghc-8.0.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.3
+      addons: {"apt":{"packages":["ghc-7.10.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.2
+      addons: {"apt":{"packages":["ghc-7.10.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.1
+      addons: {"apt":{"packages":["ghc-7.10.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.4
+      addons: {"apt":{"packages":["ghc-7.8.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.3
+      addons: {"apt":{"packages":["ghc-7.8.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.2
+      addons: {"apt":{"packages":["ghc-7.8.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.1
+      addons: {"apt":{"packages":["ghc-7.8.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+before_install:
+  - HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//')
+  - WITHCOMPILER="-w $HC"
+  - HADDOCK=$(echo "/opt/$CC/bin/haddock" | sed 's/-/\//')
+  - HCPKG="$HC-pkg"
+  - unset CC
+  - CABAL=/opt/ghc/bin/cabal
+  - CABALHOME=$HOME/.cabal
+  - export PATH="$CABALHOME/bin:$PATH"
+  - TOP=$(pwd)
+  - "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')"
+  - echo $HCNUMVER
+  - CABAL="$CABAL -vnormal+nowrap"
+  - set -o pipefail
+  - TEST=--enable-tests
+  - BENCH=--enable-benchmarks
+  - HEADHACKAGE=false
+  - rm -f $CABALHOME/config
+  - |
+    echo "verbose: normal +nowrap +markoutput"          >> $CABALHOME/config
+    echo "remote-build-reporting: anonymous"            >> $CABALHOME/config
+    echo "write-ghc-environment-files: never"           >> $CABALHOME/config
+    echo "remote-repo-cache: $CABALHOME/packages"       >> $CABALHOME/config
+    echo "logs-dir:          $CABALHOME/logs"           >> $CABALHOME/config
+    echo "world-file:        $CABALHOME/world"          >> $CABALHOME/config
+    echo "extra-prog-path:   $CABALHOME/bin"            >> $CABALHOME/config
+    echo "symlink-bindir:    $CABALHOME/bin"            >> $CABALHOME/config
+    echo "installdir:        $CABALHOME/bin"            >> $CABALHOME/config
+    echo "build-summary:     $CABALHOME/logs/build.log" >> $CABALHOME/config
+    echo "store-dir:         $CABALHOME/store"          >> $CABALHOME/config
+    echo "install-dirs user"                            >> $CABALHOME/config
+    echo "  prefix: $CABALHOME"                         >> $CABALHOME/config
+    echo "repository hackage.haskell.org"               >> $CABALHOME/config
+    echo "  url: http://hackage.haskell.org/"           >> $CABALHOME/config
+install:
+  - ${CABAL} --version
+  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
+  - |
+    echo "program-default-options"                >> $CABALHOME/config
+    echo "  ghc-options: $GHCJOBS +RTS -M6G -RTS" >> $CABALHOME/config
+  - cat $CABALHOME/config
+  - rm -fv cabal.project cabal.project.local cabal.project.freeze
+  - travis_retry ${CABAL} v2-update -v
+  # Generate cabal.project
+  - rm -rf cabal.project cabal.project.local cabal.project.freeze
+  - touch cabal.project
+  - |
+    echo "packages: servant" >> cabal.project
+    echo "packages: servant-client" >> cabal.project
+    echo "packages: servant-docs" >> cabal.project
+    echo "packages: servant-server" >> cabal.project
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-client' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-docs' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-server' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - |
+    echo "constraints: foundation >= 0.14"         >> cabal.project
+    echo "allow-newer: servant-js:servant"         >> cabal.project
+    echo "allow-newer: servant-js:servant-foreign" >> cabal.project
+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
+  - cat cabal.project || true
+  - cat cabal.project.local || true
+  - if [ -f "servant/configure.ac" ]; then (cd "servant" && autoreconf -i); fi
+  - if [ -f "servant-client/configure.ac" ]; then (cd "servant-client" && autoreconf -i); fi
+  - if [ -f "servant-docs/configure.ac" ]; then (cd "servant-docs" && autoreconf -i); fi
+  - if [ -f "servant-server/configure.ac" ]; then (cd "servant-server" && autoreconf -i); fi
+  - ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH}
+  - "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
+  - rm  cabal.project.freeze
+  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} --dep -j2 all
+  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --dep -j2 all
+script:
+  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
+  # Packaging...
+  - ${CABAL} v2-sdist all
+  # Unpacking...
+  - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
+  - cd ${DISTDIR} || false
+  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \;
+  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm       '{}' \;
+  - PKGDIR_servant="$(find . -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+  - PKGDIR_servant_client="$(find . -maxdepth 1 -type d -regex '.*/servant-client-[0-9.]*')"
+  - PKGDIR_servant_docs="$(find . -maxdepth 1 -type d -regex '.*/servant-docs-[0-9.]*')"
+  - PKGDIR_servant_server="$(find . -maxdepth 1 -type d -regex '.*/servant-server-[0-9.]*')"
+  # Generate cabal.project
+  - rm -rf cabal.project cabal.project.local cabal.project.freeze
+  - touch cabal.project
+  - |
+    echo "packages: ${PKGDIR_servant}" >> cabal.project
+    echo "packages: ${PKGDIR_servant_client}" >> cabal.project
+    echo "packages: ${PKGDIR_servant_docs}" >> cabal.project
+    echo "packages: ${PKGDIR_servant_server}" >> cabal.project
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-client' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-docs' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-server' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - |
+    echo "constraints: foundation >= 0.14"         >> cabal.project
+    echo "allow-newer: servant-js:servant"         >> cabal.project
+    echo "allow-newer: servant-js:servant-foreign" >> cabal.project
+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
+  - cat cabal.project || true
+  - cat cabal.project.local || true
+  # Building...
+  # this builds all libraries and executables (without tests/benchmarks)
+  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
+  # Building with tests and benchmarks...
+  # build & run tests, build benchmarks
+  - ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} all --write-ghc-environment-files=always
+  # Testing...
+  - ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all --test-show-details=direct
+  # cabal check...
+  - (cd ${PKGDIR_servant} && ${CABAL} -vnormal check)
+  - (cd ${PKGDIR_servant_client} && ${CABAL} -vnormal check)
+  - (cd ${PKGDIR_servant_docs} && ${CABAL} -vnormal check)
+  - (cd ${PKGDIR_servant_server} && ${CABAL} -vnormal check)
+  # haddock...
+  - ${CABAL} v2-haddock $WITHCOMPILER --with-haddock $HADDOCK ${TEST} ${BENCH} all
+  # Building without installed constraints for packages in global-db...
+  - rm -f cabal.project.local
+  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
+
+# REGENDATA ["--copy-fields=some","travis","copy-fields-some.project"]
+# EOF
diff --git a/fixtures/doc/tutorial/tutorial.cabal b/fixtures/doc/tutorial/tutorial.cabal
deleted file mode 100644
--- a/fixtures/doc/tutorial/tutorial.cabal
+++ /dev/null
@@ -1,64 +0,0 @@
-name:                tutorial
-version:             0.10
-synopsis:            The servant tutorial
-homepage:            http://haskell-servant.readthedocs.org/
-license:             BSD3
-license-file:        LICENSE
-author:              Servant Contributors
-maintainer:          haskell-servant-maintainers@googlegroups.com
-build-type:          Simple
-cabal-version:       >=1.10
-tested-with:         GHC >= 7.10
-
-library
-  exposed-modules:     ApiType
-                     , Authentication
-                     , Client
-                     , Docs
-                     , Javascript
-                     , Server
-  build-depends:       base == 4.*
-                     , base-compat
-                     , text
-                     , aeson
-                     , aeson-compat
-                     , blaze-html
-                     , directory
-                     , blaze-markup
-                     , containers
-                     , servant == 0.11.*
-                     , servant-server == 0.11.*
-                     , servant-client == 0.11.*
-                     , servant-docs == 0.11.*
-                     , servant-js >= 0.9 && <0.10
-                     , warp
-                     , http-api-data
-                     , http-media
-                     , lucid
-                     , time
-                     , string-conversions
-                     , bytestring
-                     , attoparsec
-                     , mtl
-                     , random
-                     , js-jquery
-                     , wai
-                     , http-types
-                     , transformers
-                     , markdown-unlit >= 0.4
-                     , http-client
-  default-language:    Haskell2010
-  ghc-options:         -Wall -pgmL markdown-unlit
-
-test-suite spec
-  type: exitcode-stdio-1.0
-  ghc-options: -Wall
-  default-language: Haskell2010
-  hs-source-dirs: test
-  main-is: Spec.hs
-  other-modules: JavascriptSpec
-  build-depends: base == 4.*
-               , tutorial
-               , hspec
-               , hspec-wai
-               , string-conversions
diff --git a/fixtures/empty-line.args b/fixtures/empty-line.args
new file mode 100644
--- /dev/null
+++ b/fixtures/empty-line.args
@@ -0,0 +1,1 @@
+--ghc-head
diff --git a/fixtures/empty-line.bash b/fixtures/empty-line.bash
new file mode 100644
--- /dev/null
+++ b/fixtures/empty-line.bash
@@ -0,0 +1,544 @@
+# SUCCESS
+# *INFO* Generating Bash script for testing for GHC versions: ghc-head 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+#!/bin/bash
+# shellcheck disable=SC2086,SC2016,SC2046
+# REGENDATA ["--ghc-head","bash","empty-line.project"]
+
+set -o pipefail
+
+# Mode
+##############################################################################
+
+if [ "$1" = "indocker" ]; then
+    INDOCKER=true
+    shift
+else
+    INDOCKER=false
+fi
+
+# Run configuration
+##############################################################################
+
+CFG_CABAL_STORE_CACHE=""
+CFG_CABAL_REPO_CACHE=""
+CFG_JOBS="8.10.4 8.10.3 8.10.2 8.10.1 8.8.4 8.8.3 8.8.2 8.8.1 8.6.5 8.6.4 8.6.3 8.6.2 8.6.1 8.4.4 8.4.3 8.4.2 8.4.1 8.2.2 8.2.1 8.0.2 8.0.1 7.10.3 7.10.2 7.10.1 7.8.4 7.8.3 7.8.2 7.8.1"
+CFG_CABAL_UPDATE=false
+
+SCRIPT_NAME=$(basename "$0")
+START_TIME="$(date +'%s')"
+
+XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config}
+
+# Job configuration
+##############################################################################
+
+GHC_VERSION="non-existing"
+CABAL_VERSION=3.2
+HEADHACKAGE=false
+
+# Locale
+##############################################################################
+
+export LC_ALL=C.UTF-8
+
+# Utilities
+##############################################################################
+
+SGR_RED='\033[1;31m'
+SGR_GREEN='\033[1;32m'
+SGR_BLUE='\033[1;34m'
+SGR_CYAN='\033[1;96m'
+SGR_RESET='\033[0m' # No Color
+
+put_info() {
+    printf "$SGR_CYAN%s$SGR_RESET\n" "### $*"
+}
+
+put_error() {
+    printf "$SGR_RED%s$SGR_RESET\n" "!!! $*"
+}
+
+run_cmd() {
+    local PRETTYCMD="$*"
+    local PROMPT
+    if $INDOCKER; then
+        PROMPT="$(pwd) >>>"
+    else
+        PROMPT=">>>"
+    fi
+
+    printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+
+    local start_time end_time cmd_duration total_duration
+    start_time=$(date +'%s')
+
+    "$@"
+    local RET=$?
+
+    end_time=$(date +'%s')
+    cmd_duration=$((end_time - start_time))
+    total_duration=$((end_time - START_TIME))
+
+    cmd_min=$((cmd_duration / 60))
+    cmd_sec=$((cmd_duration % 60))
+
+    total_min=$((total_duration / 60))
+    total_sec=$((total_duration % 60))
+
+    if [ $RET -eq 0 ]; then
+        printf "$SGR_GREEN%s$SGR_RESET (%dm%02ds; %dm%02ds)\n" "<<< $PRETTYCMD" "$cmd_min" "$cmd_sec" "$total_min" "$total_sec"
+    else
+        printf "$SGR_RED%s$SGR_RESET\n" "!!! $PRETTYCMD"
+        exit 1
+    fi
+}
+
+run_cmd_if() {
+    local COND=$1
+    shift
+
+    if [ $COND -eq 1 ]; then
+        run_cmd "$@"
+    else
+        local PRETTYCMD="$*"
+        local PROMPT
+        PROMPT="$(pwd) (skipping) >>>"
+
+        printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+    fi
+}
+
+run_cmd_unchecked() {
+    local PRETTYCMD="$*"
+    local PROMPT
+    if $INDOCKER; then
+        PROMPT="$(pwd) >>>"
+    else
+        PROMPT=">>>"
+    fi
+
+    printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+
+    local start_time end_time cmd_duration total_duration cmd_min cmd_sec total_min total_sec
+    start_time=$(date +'%s')
+
+    "$@"
+
+    end_time=$(date +'%s')
+    cmd_duration=$((end_time - start_time))
+    total_duration=$((end_time - START_TIME))
+
+    cmd_min=$((cmd_duration / 60))
+    cmd_sec=$((cmd_duration % 60))
+
+    total_min=$((total_duration / 60))
+    total_sec=$((total_duration % 60))
+
+    printf "$SGR_GREEN%s$SGR_RESET (%dm%02ds; %dm%02ds)\n" "<<< $PRETTYCMD" "$cmd_min" "$cmd_sec" "$total_min" "$total_sec"
+}
+
+change_dir() {
+    local DIR=$1
+    if [ -d "$DIR" ]; then
+        printf "$SGR_BLUE%s$SGR_RESET\n" "change directory to $DIR"
+        cd "$DIR" || exit 1
+    else
+        printf "$SGR_RED%s$SGR_RESET\n" "!!! cd $DIR"
+        exit 1
+    fi
+}
+
+change_dir_if() {
+    local COND=$1
+    local DIR=$2
+
+    if [ $COND -ne 0 ]; then
+        change_dir "$DIR"
+    fi
+}
+
+echo_to() {
+    local DEST=$1
+    local CONTENTS=$2
+
+    echo "$CONTENTS" >> "$DEST"
+}
+
+echo_if_to() {
+    local COND=$1
+    local DEST=$2
+    local CONTENTS=$3
+
+    if [ $COND -ne 0 ]; then
+        echo_to "$DEST" "$CONTENTS"
+    fi
+}
+
+install_cabalplan() {
+    put_info "installing cabal-plan"
+
+    if [ ! -e $CABAL_REPOCACHE/downloads/cabal-plan ]; then
+        curl -L https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > /tmp/cabal-plan.xz || exit 1
+        (cd /tmp && echo "de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc  cabal-plan.xz" | sha256sum -c -)|| exit 1
+        mkdir -p $CABAL_REPOCACHE/downloads
+        xz -d < /tmp/cabal-plan.xz > $CABAL_REPOCACHE/downloads/cabal-plan || exit 1
+        chmod a+x $CABAL_REPOCACHE/downloads/cabal-plan || exit 1
+    fi
+
+    mkdir -p $CABAL_DIR/bin || exit 1
+    ln -s $CABAL_REPOCACHE/downloads/cabal-plan $CABAL_DIR/bin/cabal-plan || exit 1
+}
+
+# Help
+##############################################################################
+
+show_usage() {
+cat <<EOF
+./haskell-ci.sh - build & test
+
+Usage: ./haskell-ci.sh [options]
+  A script to run automated checks locally (using Docker)
+
+Available options:
+  --jobs JOBS               Jobs to run (default: $CFG_JOBS)
+  --cabal-store-cache PATH  Directory to use for cabal-store-cache
+  --cabal-repo-cache PATH   Directory to use for cabal-repo-cache
+  --skip-cabal-update       Skip cabal update (useful with --cabal-repo-cache)
+  --no-skip-cabal-update
+  --help                    Print this message
+
+EOF
+}
+
+# getopt
+#######################################################################
+
+process_cli_options() {
+    while [ $# -gt 0 ]; do
+        arg=$1
+        case $arg in
+            --help)
+                show_usage
+                exit
+                ;;
+            --jobs)
+                CFG_JOBS=$2
+                shift
+                shift
+                ;;
+            --cabal-store-cache)
+                CFG_CABAL_STORE_CACHE=$2
+                shift
+                shift
+                ;;
+            --cabal-repo-cache)
+                CFG_CABAL_REPO_CACHE=$2
+                shift
+                shift
+                ;;
+            --skip-cabal-update)
+                CFG_CABAL_UPDATE=false
+                shift
+                ;;
+            --no-skip-cabal-update)
+                CFG_CABAL_UPDATE=true
+                shift
+                ;;
+            *)
+                echo "Unknown option $arg"
+                exit 1
+        esac
+    done
+}
+
+process_indocker_options () {
+    while [ $# -gt 0 ]; do
+        arg=$1
+
+        case $arg in
+            --ghc-version)
+                GHC_VERSION=$2
+                shift
+                shift
+                ;;
+            --cabal-version)
+                CABAL_VERSION=$2
+                shift
+                shift
+                ;;
+            --start-time)
+                START_TIME=$2
+                shift
+                shift
+                ;;
+            --cabal-update)
+                CABAL_UPDATE=$2
+                shift
+                shift
+                ;;
+            *)
+                echo "Unknown option $arg"
+                exit 1
+        esac
+    done
+}
+
+if $INDOCKER; then
+    process_indocker_options "$@"
+
+else
+    if [ -f "$XDG_CONFIG_HOME/haskell-ci/bash.config" ]; then
+        process_cli_options $(cat "$XDG_CONFIG_HOME/haskell-ci/bash.config")
+    fi
+
+    process_cli_options "$@"
+
+    put_info "jobs:              $CFG_JOBS"
+    put_info "cabal-store-cache: $CFG_CABAL_STORE_CACHE"
+    put_info "cabal-repo-cache:  $CFG_CABAL_REPO_CACHE"
+    put_info "cabal-update:      $CFG_CABAL_UPDATE"
+fi
+
+# Constants
+##############################################################################
+
+SRCDIR=/hsci/src
+BUILDDIR=/hsci/build
+CABAL_DIR="$BUILDDIR/cabal"
+CABAL_REPOCACHE=/hsci/cabal-repocache
+CABAL_STOREDIR=/hsci/store
+
+# Docker invoke
+##############################################################################
+
+# if cache directory is specified, use it.
+# Otherwise use another tmpfs host
+if [ -z "$CFG_CABAL_STORE_CACHE" ]; then
+    CABALSTOREARG="--tmpfs $CABAL_STOREDIR:exec"
+else
+    CABALSTOREARG="--volume $CFG_CABAL_STORE_CACHE:$CABAL_STOREDIR"
+fi
+
+if [ -z "$CFG_CABAL_REPO_CACHE" ]; then
+    CABALREPOARG="--tmpfs $CABAL_REPOCACHE:exec"
+else
+    CABALREPOARG="--volume $CFG_CABAL_REPO_CACHE:$CABAL_REPOCACHE"
+fi
+
+echo_docker_cmd() {
+    local GHCVER=$1
+
+    # TODO: mount /hsci/src:ro (readonly)
+    echo docker run \
+        --tty \
+        --interactive \
+        --rm \
+        --label haskell-ci \
+        --volume "$(pwd):/hsci/src" \
+        $CABALSTOREARG \
+        $CABALREPOARG \
+        --tmpfs /tmp:exec \
+        --tmpfs /hsci/build:exec \
+        --workdir /hsci/build \
+        "phadej/ghc:$GHCVER-bionic" \
+        "/bin/bash" "/hsci/src/$SCRIPT_NAME" indocker \
+        --ghc-version "$GHCVER" \
+        --cabal-update "$CFG_CABAL_UPDATE" \
+        --start-time "$START_TIME"
+}
+
+# if we are not in docker, loop through jobs
+if ! $INDOCKER; then
+    for JOB in $CFG_JOBS; do
+        put_info "Running in docker: $JOB"
+        run_cmd $(echo_docker_cmd "$JOB")
+    done
+
+    run_cmd echo "ALL OK"
+    exit 0
+fi
+
+# Otherwise we are in docker, and the rest of script executes
+put_info "In docker"
+
+# Environment
+##############################################################################
+
+GHCDIR=/opt/ghc/$GHC_VERSION
+
+HC=$GHCDIR/bin/ghc
+HCPKG=$GHCDIR/bin/ghc-pkg
+HADDOCK=$GHCDIR/bin/haddock
+
+CABAL=/opt/cabal/$CABAL_VERSION/bin/cabal
+
+CABAL="$CABAL -vnormal+nowrap"
+
+export CABAL_DIR
+export CABAL_CONFIG="$BUILDDIR/cabal/config"
+
+PATH="$CABAL_DIR/bin:$PATH"
+
+# HCNUMVER
+HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
+GHCJSARITH=0
+
+put_info "HCNUMVER: $HCNUMVER"
+
+# Args for shorter/nicer commands
+if [ 1 -ne 0 ] ; then ARG_TESTS=--enable-tests; else ARG_TESTS=--disable-tests; fi
+if [ 1 -ne 0 ] ; then ARG_BENCH=--enable-benchmarks; else ARG_BENCH=--disable-benchmarks; fi
+ARG_COMPILER="--ghc --with-compiler=$HC"
+
+put_info "tests/benchmarks: $ARG_TESTS $ARG_BENCH"
+
+# Apt dependencies
+##############################################################################
+
+
+# Cabal config
+##############################################################################
+
+mkdir -p $BUILDDIR/cabal
+
+cat > $BUILDDIR/cabal/config <<EOF
+remote-build-reporting: anonymous
+write-ghc-environment-files: always
+remote-repo-cache: $CABAL_REPOCACHE
+logs-dir:          $CABAL_DIR/logs
+world-file:        $CABAL_DIR/world
+extra-prog-path:   $CABAL_DIR/bin
+symlink-bindir:    $CABAL_DIR/bin
+installdir:        $CABAL_DIR/bin
+build-summary:     $CABAL_DIR/logs/build.log
+store-dir:         $CABAL_STOREDIR
+install-dirs user
+  prefix: $CABAL_DIR
+repository hackage.haskell.org
+  url: http://hackage.haskell.org/
+EOF
+
+if $HEADHACKAGE; then
+    put_error "head.hackage is not implemented"
+    exit 1
+fi
+
+run_cmd cat "$BUILDDIR/cabal/config"
+
+# Version
+##############################################################################
+
+put_info "Versions"
+run_cmd $HC --version
+run_cmd_unchecked $HC --print-project-git-commit-id
+run_cmd $CABAL --version
+
+# Build script
+##############################################################################
+
+# update cabal index
+if $CABAL_UPDATE; then
+    put_info "Updating Hackage index"
+    run_cmd $CABAL v2-update -v
+fi
+
+# install cabal-plan
+install_cabalplan
+run_cmd cabal-plan --version
+
+# initial cabal.project for sdist
+put_info "initial cabal.project for sdist"
+change_dir "$BUILDDIR"
+run_cmd touch cabal.project
+echo_to cabal.project "packages: $SRCDIR/servant"
+echo_to cabal.project "packages: $SRCDIR/servant-client"
+echo_to cabal.project "packages: $SRCDIR/servant-docs"
+echo_to cabal.project "packages: $SRCDIR/servant-server"
+run_cmd cat cabal.project
+
+# sdist
+put_info "sdist"
+run_cmd mkdir -p "$BUILDDIR/sdist"
+run_cmd $CABAL sdist all --output-dir "$BUILDDIR/sdist"
+
+# unpack
+put_info "unpack"
+change_dir "$BUILDDIR"
+run_cmd mkdir -p "$BUILDDIR/unpacked"
+run_cmd find "$BUILDDIR/sdist" -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C "$BUILDDIR/unpacked" -xzvf {} \;
+
+# generate cabal.project
+put_info "generate cabal.project"
+PKGDIR_servant="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+PKGDIR_servant_client="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-client-[0-9.]*')"
+PKGDIR_servant_docs="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-docs-[0-9.]*')"
+PKGDIR_servant_server="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-server-[0-9.]*')"
+run_cmd touch cabal.project
+run_cmd touch cabal.project.local
+echo_to cabal.project "packages: ${PKGDIR_servant}"
+echo_to cabal.project "packages: ${PKGDIR_servant_client}"
+echo_to cabal.project "packages: ${PKGDIR_servant_docs}"
+echo_to cabal.project "packages: ${PKGDIR_servant_server}"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant-client"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant-docs"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant-server"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+cat >> cabal.project <<EOF
+constraints: foundatiion >= 0.14
+allow-newer: servant-js:servant
+allow-newer: servant-js:servant-foreign
+EOF
+$HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(servant|servant-client|servant-docs|servant-server)$/; }' >> cabal.project.local
+run_cmd cat cabal.project
+run_cmd cat cabal.project.local
+
+# dump install plan
+put_info "dump install plan"
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
+run_cmd cabal-plan
+
+# install dependencies
+put_info "install dependencies"
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j all
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j all
+
+# build w/o tests
+put_info "build w/o tests"
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+
+# build
+put_info "build"
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all
+
+# tests
+put_info "tests"
+run_cmd $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
+
+# cabal check
+put_info "cabal check"
+change_dir "${PKGDIR_servant}"
+run_cmd ${CABAL} -vnormal check
+change_dir "${PKGDIR_servant_client}"
+run_cmd ${CABAL} -vnormal check
+change_dir "${PKGDIR_servant_docs}"
+run_cmd ${CABAL} -vnormal check
+change_dir "${PKGDIR_servant_server}"
+run_cmd ${CABAL} -vnormal check
+change_dir "$BUILDDIR"
+
+# haddock
+put_info "haddock"
+run_cmd $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
+
+# unconstrained build
+put_info "unconstrained build"
+run_cmd rm -f cabal.project.local
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+
+
+# Done
+run_cmd echo OK
diff --git a/fixtures/empty-line.github b/fixtures/empty-line.github
new file mode 100644
--- /dev/null
+++ b/fixtures/empty-line.github
@@ -0,0 +1,263 @@
+# SUCCESS
+# *INFO* Generating GitHub config for testing for GHC versions: ghc-head 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+# This GitHub workflow config has been generated by a script via
+#
+#   haskell-ci '--ghc-head' 'github' 'empty-line.project'
+#
+# To regenerate the script (for example after adjusting tested-with) run
+#
+#   haskell-ci regenerate
+#
+# For more information, see https://github.com/haskell-CI/haskell-ci
+#
+# REGENDATA ["--ghc-head","github","empty-line.project"]
+#
+name: Haskell-CI
+on:
+  - push
+  - pull_request
+jobs:
+  linux:
+    name: Haskell-CI - Linux - ${{ matrix.compiler }}
+    runs-on: ubuntu-18.04
+    container:
+      image: buildpack-deps:bionic
+    continue-on-error: ${{ matrix.allow-failure }}
+    strategy:
+      matrix:
+        include:
+          - compiler: ghc-8.10.4
+            allow-failure: false
+          - compiler: ghc-8.10.3
+            allow-failure: false
+          - compiler: ghc-8.10.2
+            allow-failure: false
+          - compiler: ghc-8.10.1
+            allow-failure: false
+          - compiler: ghc-8.8.4
+            allow-failure: false
+          - compiler: ghc-8.8.3
+            allow-failure: false
+          - compiler: ghc-8.8.2
+            allow-failure: false
+          - compiler: ghc-8.8.1
+            allow-failure: false
+          - compiler: ghc-8.6.5
+            allow-failure: false
+          - compiler: ghc-8.6.4
+            allow-failure: false
+          - compiler: ghc-8.6.3
+            allow-failure: false
+          - compiler: ghc-8.6.2
+            allow-failure: false
+          - compiler: ghc-8.6.1
+            allow-failure: false
+          - compiler: ghc-8.4.4
+            allow-failure: false
+          - compiler: ghc-8.4.3
+            allow-failure: false
+          - compiler: ghc-8.4.2
+            allow-failure: false
+          - compiler: ghc-8.4.1
+            allow-failure: false
+          - compiler: ghc-8.2.2
+            allow-failure: false
+          - compiler: ghc-8.2.1
+            allow-failure: false
+          - compiler: ghc-8.0.2
+            allow-failure: false
+          - compiler: ghc-8.0.1
+            allow-failure: false
+          - compiler: ghc-7.10.3
+            allow-failure: false
+          - compiler: ghc-7.10.2
+            allow-failure: false
+          - compiler: ghc-7.10.1
+            allow-failure: false
+          - compiler: ghc-7.8.4
+            allow-failure: false
+          - compiler: ghc-7.8.3
+            allow-failure: false
+          - compiler: ghc-7.8.2
+            allow-failure: false
+          - compiler: ghc-7.8.1
+            allow-failure: false
+      fail-fast: false
+    steps:
+      - name: apt
+        run: |
+          apt-get update
+          apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common
+          apt-add-repository -y 'ppa:hvr/ghc'
+          apt-get update
+          apt-get install -y $CC cabal-install-3.4
+        env:
+          CC: ${{ matrix.compiler }}
+      - name: Set PATH and environment variables
+        run: |
+          echo "$HOME/.cabal/bin" >> $GITHUB_PATH
+          echo "LANG=C.UTF-8" >> $GITHUB_ENV
+          echo "CABAL_DIR=$HOME/.cabal" >> $GITHUB_ENV
+          echo "CABAL_CONFIG=$HOME/.cabal/config" >> $GITHUB_ENV
+          HCDIR=$(echo "/opt/$CC" | sed 's/-/\//')
+          HCNAME=ghc
+          HC=$HCDIR/bin/$HCNAME
+          echo "HC=$HC" >> $GITHUB_ENV
+          echo "HCPKG=$HCDIR/bin/$HCNAME-pkg" >> $GITHUB_ENV
+          echo "HADDOCK=$HCDIR/bin/haddock" >> $GITHUB_ENV
+          echo "CABAL=/opt/cabal/3.4/bin/cabal -vnormal+nowrap" >> $GITHUB_ENV
+          HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
+          echo "HCNUMVER=$HCNUMVER" >> $GITHUB_ENV
+          echo "ARG_TESTS=--enable-tests" >> $GITHUB_ENV
+          echo "ARG_BENCH=--enable-benchmarks" >> $GITHUB_ENV
+          if [ $((HCNUMVER > 81004)) -ne 0 ] ; then echo "HEADHACKAGE=true" >> $GITHUB_ENV ; else echo "HEADHACKAGE=false" >> $GITHUB_ENV ; fi
+          echo "ARG_COMPILER=--$HCNAME --with-compiler=$HC" >> $GITHUB_ENV
+          echo "GHCJSARITH=0" >> $GITHUB_ENV
+        env:
+          CC: ${{ matrix.compiler }}
+      - name: env
+        run: |
+          env
+      - name: write cabal config
+        run: |
+          mkdir -p $CABAL_DIR
+          cat >> $CABAL_CONFIG <<EOF
+          remote-build-reporting: anonymous
+          write-ghc-environment-files: never
+          remote-repo-cache: $CABAL_DIR/packages
+          logs-dir:          $CABAL_DIR/logs
+          world-file:        $CABAL_DIR/world
+          extra-prog-path:   $CABAL_DIR/bin
+          symlink-bindir:    $CABAL_DIR/bin
+          installdir:        $CABAL_DIR/bin
+          build-summary:     $CABAL_DIR/logs/build.log
+          store-dir:         $CABAL_DIR/store
+          install-dirs user
+            prefix: $CABAL_DIR
+          repository hackage.haskell.org
+            url: http://hackage.haskell.org/
+          EOF
+          if $HEADHACKAGE; then
+          cat >> $CABAL_CONFIG <<EOF
+          repository head.hackage.ghc.haskell.org
+             url: https://ghc.gitlab.haskell.org/head.hackage/
+             secure: True
+             root-keys: 7541f32a4ccca4f97aea3b22f5e593ba2c0267546016b992dfadcd2fe944e55d
+                        26021a13b401500c8eb2761ca95c61f2d625bfef951b939a8124ed12ecf07329
+                        f76d08be13e9a61a377a85e2fb63f4c5435d40f8feb3e12eb05905edb8cdea89
+             key-threshold: 3
+          EOF
+          fi
+          cat $CABAL_CONFIG
+      - name: versions
+        run: |
+          $HC --version || true
+          $HC --print-project-git-commit-id || true
+          $CABAL --version || true
+      - name: update cabal index
+        run: |
+          $CABAL v2-update -v
+      - name: install cabal-plan
+        run: |
+          mkdir -p $HOME/.cabal/bin
+          curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > cabal-plan.xz
+          echo 'de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc  cabal-plan.xz' | sha256sum -c -
+          xz -d < cabal-plan.xz > $HOME/.cabal/bin/cabal-plan
+          rm -f cabal-plan.xz
+          chmod a+x $HOME/.cabal/bin/cabal-plan
+          cabal-plan --version
+      - name: checkout
+        uses: actions/checkout@v2
+        with:
+          path: source
+      - name: initial cabal.project for sdist
+        run: |
+          touch cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant" >> cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant-client" >> cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant-docs" >> cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant-server" >> cabal.project
+          cat cabal.project
+      - name: sdist
+        run: |
+          mkdir -p sdist
+          $CABAL sdist all --output-dir $GITHUB_WORKSPACE/sdist
+      - name: unpack
+        run: |
+          mkdir -p unpacked
+          find sdist -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C $GITHUB_WORKSPACE/unpacked -xzvf {} \;
+      - name: generate cabal.project
+        run: |
+          PKGDIR_servant="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+          echo "PKGDIR_servant=${PKGDIR_servant}" >> $GITHUB_ENV
+          PKGDIR_servant_client="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-client-[0-9.]*')"
+          echo "PKGDIR_servant_client=${PKGDIR_servant_client}" >> $GITHUB_ENV
+          PKGDIR_servant_docs="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-docs-[0-9.]*')"
+          echo "PKGDIR_servant_docs=${PKGDIR_servant_docs}" >> $GITHUB_ENV
+          PKGDIR_servant_server="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-server-[0-9.]*')"
+          echo "PKGDIR_servant_server=${PKGDIR_servant_server}" >> $GITHUB_ENV
+          touch cabal.project
+          touch cabal.project.local
+          echo "packages: ${PKGDIR_servant}" >> cabal.project
+          echo "packages: ${PKGDIR_servant_client}" >> cabal.project
+          echo "packages: ${PKGDIR_servant_docs}" >> cabal.project
+          echo "packages: ${PKGDIR_servant_server}" >> cabal.project
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant-client" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant-docs" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant-server" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          cat >> cabal.project <<EOF
+          constraints: foundatiion >= 0.14
+          allow-newer: servant-js:servant
+          allow-newer: servant-js:servant-foreign
+          EOF
+          if $HEADHACKAGE; then
+          echo "allow-newer: $($HCPKG list --simple-output | sed -E 's/([a-zA-Z-]+)-[0-9.]+/*:\1,/g')" >> cabal.project
+          fi
+          $HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(servant|servant-client|servant-docs|servant-server)$/; }' >> cabal.project.local
+          cat cabal.project
+          cat cabal.project.local
+      - name: dump install plan
+        run: |
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
+          cabal-plan
+      - name: cache
+        uses: actions/cache@v2
+        with:
+          key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
+          path: ~/.cabal/store
+          restore-keys: ${{ runner.os }}-${{ matrix.compiler }}-
+      - name: install dependencies
+        run: |
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j2 all
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j2 all
+      - name: build w/o tests
+        run: |
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+      - name: build
+        run: |
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --write-ghc-environment-files=always
+      - name: tests
+        run: |
+          $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
+      - name: cabal check
+        run: |
+          cd ${PKGDIR_servant} || false
+          ${CABAL} -vnormal check
+          cd ${PKGDIR_servant_client} || false
+          ${CABAL} -vnormal check
+          cd ${PKGDIR_servant_docs} || false
+          ${CABAL} -vnormal check
+          cd ${PKGDIR_servant_server} || false
+          ${CABAL} -vnormal check
+      - name: haddock
+        run: |
+          $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
+      - name: unconstrained build
+        run: |
+          rm -f cabal.project.local
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
diff --git a/fixtures/empty-line.project b/fixtures/empty-line.project
new file mode 100644
--- /dev/null
+++ b/fixtures/empty-line.project
@@ -0,0 +1,12 @@
+packages:
+  servant/
+  servant-client/
+  servant-docs/
+  servant-server/
+
+constraints: foundatiion >= 0.14
+allow-newer:
+  servant-js:servant
+allow-newer:
+  servant-js:servant-foreign
+allow-newer:
diff --git a/fixtures/empty-line.travis b/fixtures/empty-line.travis
new file mode 100644
--- /dev/null
+++ b/fixtures/empty-line.travis
@@ -0,0 +1,275 @@
+# SUCCESS
+# *INFO* Generating Travis-CI config for testing for GHC versions: ghc-head 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+# This Travis job script has been generated by a script via
+#
+#   haskell-ci '--ghc-head' 'travis' 'empty-line.project'
+#
+# To regenerate the script (for example after adjusting tested-with) run
+#
+#   haskell-ci regenerate
+#
+# For more information, see https://github.com/haskell-CI/haskell-ci
+#
+version: ~> 1.0
+language: c
+os: linux
+dist: xenial
+git:
+  # whether to recursively clone submodules
+  submodules: false
+cache:
+  directories:
+    - $HOME/.cabal/packages
+    - $HOME/.cabal/store
+    - $HOME/.hlint
+before_cache:
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log
+  # remove files that are regenerated by 'cabal update'
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx
+  - rm -rfv $CABALHOME/packages/head.hackage
+jobs:
+  include:
+    - compiler: ghc-8.10.4
+      addons: {"apt":{"packages":["ghc-8.10.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.3
+      addons: {"apt":{"packages":["ghc-8.10.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.2
+      addons: {"apt":{"packages":["ghc-8.10.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.1
+      addons: {"apt":{"packages":["ghc-8.10.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.4
+      addons: {"apt":{"packages":["ghc-8.8.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.3
+      addons: {"apt":{"packages":["ghc-8.8.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.2
+      addons: {"apt":{"packages":["ghc-8.8.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.1
+      addons: {"apt":{"packages":["ghc-8.8.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.5
+      addons: {"apt":{"packages":["ghc-8.6.5","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.4
+      addons: {"apt":{"packages":["ghc-8.6.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.3
+      addons: {"apt":{"packages":["ghc-8.6.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.2
+      addons: {"apt":{"packages":["ghc-8.6.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.1
+      addons: {"apt":{"packages":["ghc-8.6.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.4
+      addons: {"apt":{"packages":["ghc-8.4.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.3
+      addons: {"apt":{"packages":["ghc-8.4.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.2
+      addons: {"apt":{"packages":["ghc-8.4.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.1
+      addons: {"apt":{"packages":["ghc-8.4.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.2.2
+      addons: {"apt":{"packages":["ghc-8.2.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.2.1
+      addons: {"apt":{"packages":["ghc-8.2.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.0.2
+      addons: {"apt":{"packages":["ghc-8.0.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.0.1
+      addons: {"apt":{"packages":["ghc-8.0.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.3
+      addons: {"apt":{"packages":["ghc-7.10.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.2
+      addons: {"apt":{"packages":["ghc-7.10.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.1
+      addons: {"apt":{"packages":["ghc-7.10.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.4
+      addons: {"apt":{"packages":["ghc-7.8.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.3
+      addons: {"apt":{"packages":["ghc-7.8.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.2
+      addons: {"apt":{"packages":["ghc-7.8.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.1
+      addons: {"apt":{"packages":["ghc-7.8.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-head
+      addons: {"apt":{"packages":["ghc-head","cabal-install-head"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+  allow_failures:
+    - compiler: ghc-head
+before_install:
+  - HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//')
+  - WITHCOMPILER="-w $HC"
+  - HADDOCK=$(echo "/opt/$CC/bin/haddock" | sed 's/-/\//')
+  - HCPKG="$HC-pkg"
+  - unset CC
+  - CABAL=/opt/ghc/bin/cabal
+  - CABALHOME=$HOME/.cabal
+  - export PATH="$CABALHOME/bin:$PATH"
+  - TOP=$(pwd)
+  - "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')"
+  - echo $HCNUMVER
+  - CABAL="$CABAL -vnormal+nowrap"
+  - set -o pipefail
+  - TEST=--enable-tests
+  - BENCH=--enable-benchmarks
+  - HEADHACKAGE=false
+  - if [ $((HCNUMVER > 81004)) -ne 0 ] ; then HEADHACKAGE=true ; fi
+  - rm -f $CABALHOME/config
+  - |
+    echo "verbose: normal +nowrap +markoutput"          >> $CABALHOME/config
+    echo "remote-build-reporting: anonymous"            >> $CABALHOME/config
+    echo "write-ghc-environment-files: never"           >> $CABALHOME/config
+    echo "remote-repo-cache: $CABALHOME/packages"       >> $CABALHOME/config
+    echo "logs-dir:          $CABALHOME/logs"           >> $CABALHOME/config
+    echo "world-file:        $CABALHOME/world"          >> $CABALHOME/config
+    echo "extra-prog-path:   $CABALHOME/bin"            >> $CABALHOME/config
+    echo "symlink-bindir:    $CABALHOME/bin"            >> $CABALHOME/config
+    echo "installdir:        $CABALHOME/bin"            >> $CABALHOME/config
+    echo "build-summary:     $CABALHOME/logs/build.log" >> $CABALHOME/config
+    echo "store-dir:         $CABALHOME/store"          >> $CABALHOME/config
+    echo "install-dirs user"                            >> $CABALHOME/config
+    echo "  prefix: $CABALHOME"                         >> $CABALHOME/config
+    echo "repository hackage.haskell.org"               >> $CABALHOME/config
+    echo "  url: http://hackage.haskell.org/"           >> $CABALHOME/config
+  - |
+    if $HEADHACKAGE; then
+    echo "repository head.hackage.ghc.haskell.org"                                        >> $CABALHOME/config
+    echo "   url: https://ghc.gitlab.haskell.org/head.hackage/"                           >> $CABALHOME/config
+    echo "   secure: True"                                                                >> $CABALHOME/config
+    echo "   root-keys: 7541f32a4ccca4f97aea3b22f5e593ba2c0267546016b992dfadcd2fe944e55d" >> $CABALHOME/config
+    echo "              26021a13b401500c8eb2761ca95c61f2d625bfef951b939a8124ed12ecf07329" >> $CABALHOME/config
+    echo "              f76d08be13e9a61a377a85e2fb63f4c5435d40f8feb3e12eb05905edb8cdea89" >> $CABALHOME/config
+    echo "   key-threshold: 3"                                                            >> $CABALHOME/config
+    fi
+install:
+  - ${CABAL} --version
+  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
+  - |
+    echo "program-default-options"                >> $CABALHOME/config
+    echo "  ghc-options: $GHCJOBS +RTS -M6G -RTS" >> $CABALHOME/config
+  - cat $CABALHOME/config
+  - rm -fv cabal.project cabal.project.local cabal.project.freeze
+  - travis_retry ${CABAL} v2-update -v
+  # Generate cabal.project
+  - rm -rf cabal.project cabal.project.local cabal.project.freeze
+  - touch cabal.project
+  - |
+    echo "packages: servant" >> cabal.project
+    echo "packages: servant-client" >> cabal.project
+    echo "packages: servant-docs" >> cabal.project
+    echo "packages: servant-server" >> cabal.project
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-client' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-docs' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-server' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - |
+    echo "constraints: foundatiion >= 0.14"        >> cabal.project
+    echo "allow-newer: servant-js:servant"         >> cabal.project
+    echo "allow-newer: servant-js:servant-foreign" >> cabal.project
+  - |
+    if $HEADHACKAGE; then
+    echo "allow-newer: $($HCPKG list --simple-output | sed -E 's/([a-zA-Z-]+)-[0-9.]+/*:\1,/g')" >> $CABALHOME/config
+    fi
+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
+  - cat cabal.project || true
+  - cat cabal.project.local || true
+  - if [ -f "servant/configure.ac" ]; then (cd "servant" && autoreconf -i); fi
+  - if [ -f "servant-client/configure.ac" ]; then (cd "servant-client" && autoreconf -i); fi
+  - if [ -f "servant-docs/configure.ac" ]; then (cd "servant-docs" && autoreconf -i); fi
+  - if [ -f "servant-server/configure.ac" ]; then (cd "servant-server" && autoreconf -i); fi
+  - ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH}
+  - "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
+  - rm  cabal.project.freeze
+  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} --dep -j2 all
+  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --dep -j2 all
+script:
+  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
+  # Packaging...
+  - ${CABAL} v2-sdist all
+  # Unpacking...
+  - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
+  - cd ${DISTDIR} || false
+  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \;
+  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm       '{}' \;
+  - PKGDIR_servant="$(find . -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+  - PKGDIR_servant_client="$(find . -maxdepth 1 -type d -regex '.*/servant-client-[0-9.]*')"
+  - PKGDIR_servant_docs="$(find . -maxdepth 1 -type d -regex '.*/servant-docs-[0-9.]*')"
+  - PKGDIR_servant_server="$(find . -maxdepth 1 -type d -regex '.*/servant-server-[0-9.]*')"
+  # Generate cabal.project
+  - rm -rf cabal.project cabal.project.local cabal.project.freeze
+  - touch cabal.project
+  - |
+    echo "packages: ${PKGDIR_servant}" >> cabal.project
+    echo "packages: ${PKGDIR_servant_client}" >> cabal.project
+    echo "packages: ${PKGDIR_servant_docs}" >> cabal.project
+    echo "packages: ${PKGDIR_servant_server}" >> cabal.project
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-client' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-docs' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-server' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - |
+    echo "constraints: foundatiion >= 0.14"        >> cabal.project
+    echo "allow-newer: servant-js:servant"         >> cabal.project
+    echo "allow-newer: servant-js:servant-foreign" >> cabal.project
+  - |
+    if $HEADHACKAGE; then
+    echo "allow-newer: $($HCPKG list --simple-output | sed -E 's/([a-zA-Z-]+)-[0-9.]+/*:\1,/g')" >> $CABALHOME/config
+    fi
+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
+  - cat cabal.project || true
+  - cat cabal.project.local || true
+  # Building...
+  # this builds all libraries and executables (without tests/benchmarks)
+  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
+  # Building with tests and benchmarks...
+  # build & run tests, build benchmarks
+  - ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} all --write-ghc-environment-files=always
+  # Testing...
+  - ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all --test-show-details=direct
+  # cabal check...
+  - (cd ${PKGDIR_servant} && ${CABAL} -vnormal check)
+  - (cd ${PKGDIR_servant_client} && ${CABAL} -vnormal check)
+  - (cd ${PKGDIR_servant_docs} && ${CABAL} -vnormal check)
+  - (cd ${PKGDIR_servant_server} && ${CABAL} -vnormal check)
+  # haddock...
+  - ${CABAL} v2-haddock $WITHCOMPILER --with-haddock $HADDOCK ${TEST} ${BENCH} all
+  # Building without installed constraints for packages in global-db...
+  - rm -f cabal.project.local
+  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
+
+# REGENDATA ["--ghc-head","travis","empty-line.project"]
+# EOF
diff --git a/fixtures/fail-versions.args b/fixtures/fail-versions.args
new file mode 100644
--- /dev/null
+++ b/fixtures/fail-versions.args
diff --git a/fixtures/fail-versions.bash b/fixtures/fail-versions.bash
new file mode 100644
--- /dev/null
+++ b/fixtures/fail-versions.bash
@@ -0,0 +1,3 @@
+# FAILURE
+# *ERROR* servant-client-core is missing tested-with annotations for: ghc-7.8.1,ghc-7.8.2,ghc-7.8.3,ghc-7.8.4
+# *ERROR* servant-foreign is missing tested-with annotations for: ghc-7.8.1,ghc-7.8.2,ghc-7.8.3,ghc-7.8.4
diff --git a/fixtures/fail-versions.github b/fixtures/fail-versions.github
new file mode 100644
--- /dev/null
+++ b/fixtures/fail-versions.github
@@ -0,0 +1,3 @@
+# FAILURE
+# *ERROR* servant-client-core is missing tested-with annotations for: ghc-7.8.1,ghc-7.8.2,ghc-7.8.3,ghc-7.8.4
+# *ERROR* servant-foreign is missing tested-with annotations for: ghc-7.8.1,ghc-7.8.2,ghc-7.8.3,ghc-7.8.4
diff --git a/fixtures/fail-versions.project b/fixtures/fail-versions.project
new file mode 100644
--- /dev/null
+++ b/fixtures/fail-versions.project
@@ -0,0 +1,6 @@
+packages: servant/
+  servant-client/
+  servant-client-core/
+  servant-docs/
+  servant-foreign/
+  servant-server/
diff --git a/fixtures/fail-versions.travis b/fixtures/fail-versions.travis
new file mode 100644
--- /dev/null
+++ b/fixtures/fail-versions.travis
@@ -0,0 +1,3 @@
+# FAILURE
+# *ERROR* servant-client-core is missing tested-with annotations for: ghc-7.8.1,ghc-7.8.2,ghc-7.8.3,ghc-7.8.4
+# *ERROR* servant-foreign is missing tested-with annotations for: ghc-7.8.1,ghc-7.8.2,ghc-7.8.3,ghc-7.8.4
diff --git a/fixtures/irc-channels.args b/fixtures/irc-channels.args
new file mode 100644
--- /dev/null
+++ b/fixtures/irc-channels.args
@@ -0,0 +1,1 @@
+--irc-channels=chat.freenode.net#mychannel
diff --git a/fixtures/irc-channels.bash b/fixtures/irc-channels.bash
new file mode 100644
--- /dev/null
+++ b/fixtures/irc-channels.bash
@@ -0,0 +1,520 @@
+# SUCCESS
+# *INFO* Generating Bash script for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+#!/bin/bash
+# shellcheck disable=SC2086,SC2016,SC2046
+# REGENDATA ["--irc-channels=chat.freenode.net#mychannel","bash","irc-channels.project"]
+
+set -o pipefail
+
+# Mode
+##############################################################################
+
+if [ "$1" = "indocker" ]; then
+    INDOCKER=true
+    shift
+else
+    INDOCKER=false
+fi
+
+# Run configuration
+##############################################################################
+
+CFG_CABAL_STORE_CACHE=""
+CFG_CABAL_REPO_CACHE=""
+CFG_JOBS="8.10.4 8.10.3 8.10.2 8.10.1 8.8.4 8.8.3 8.8.2 8.8.1 8.6.5 8.6.4 8.6.3 8.6.2 8.6.1 8.4.4 8.4.3 8.4.2 8.4.1 8.2.2 8.2.1 8.0.2 8.0.1 7.10.3 7.10.2 7.10.1 7.8.4 7.8.3 7.8.2 7.8.1"
+CFG_CABAL_UPDATE=false
+
+SCRIPT_NAME=$(basename "$0")
+START_TIME="$(date +'%s')"
+
+XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config}
+
+# Job configuration
+##############################################################################
+
+GHC_VERSION="non-existing"
+CABAL_VERSION=3.2
+HEADHACKAGE=false
+
+# Locale
+##############################################################################
+
+export LC_ALL=C.UTF-8
+
+# Utilities
+##############################################################################
+
+SGR_RED='\033[1;31m'
+SGR_GREEN='\033[1;32m'
+SGR_BLUE='\033[1;34m'
+SGR_CYAN='\033[1;96m'
+SGR_RESET='\033[0m' # No Color
+
+put_info() {
+    printf "$SGR_CYAN%s$SGR_RESET\n" "### $*"
+}
+
+put_error() {
+    printf "$SGR_RED%s$SGR_RESET\n" "!!! $*"
+}
+
+run_cmd() {
+    local PRETTYCMD="$*"
+    local PROMPT
+    if $INDOCKER; then
+        PROMPT="$(pwd) >>>"
+    else
+        PROMPT=">>>"
+    fi
+
+    printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+
+    local start_time end_time cmd_duration total_duration
+    start_time=$(date +'%s')
+
+    "$@"
+    local RET=$?
+
+    end_time=$(date +'%s')
+    cmd_duration=$((end_time - start_time))
+    total_duration=$((end_time - START_TIME))
+
+    cmd_min=$((cmd_duration / 60))
+    cmd_sec=$((cmd_duration % 60))
+
+    total_min=$((total_duration / 60))
+    total_sec=$((total_duration % 60))
+
+    if [ $RET -eq 0 ]; then
+        printf "$SGR_GREEN%s$SGR_RESET (%dm%02ds; %dm%02ds)\n" "<<< $PRETTYCMD" "$cmd_min" "$cmd_sec" "$total_min" "$total_sec"
+    else
+        printf "$SGR_RED%s$SGR_RESET\n" "!!! $PRETTYCMD"
+        exit 1
+    fi
+}
+
+run_cmd_if() {
+    local COND=$1
+    shift
+
+    if [ $COND -eq 1 ]; then
+        run_cmd "$@"
+    else
+        local PRETTYCMD="$*"
+        local PROMPT
+        PROMPT="$(pwd) (skipping) >>>"
+
+        printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+    fi
+}
+
+run_cmd_unchecked() {
+    local PRETTYCMD="$*"
+    local PROMPT
+    if $INDOCKER; then
+        PROMPT="$(pwd) >>>"
+    else
+        PROMPT=">>>"
+    fi
+
+    printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+
+    local start_time end_time cmd_duration total_duration cmd_min cmd_sec total_min total_sec
+    start_time=$(date +'%s')
+
+    "$@"
+
+    end_time=$(date +'%s')
+    cmd_duration=$((end_time - start_time))
+    total_duration=$((end_time - START_TIME))
+
+    cmd_min=$((cmd_duration / 60))
+    cmd_sec=$((cmd_duration % 60))
+
+    total_min=$((total_duration / 60))
+    total_sec=$((total_duration % 60))
+
+    printf "$SGR_GREEN%s$SGR_RESET (%dm%02ds; %dm%02ds)\n" "<<< $PRETTYCMD" "$cmd_min" "$cmd_sec" "$total_min" "$total_sec"
+}
+
+change_dir() {
+    local DIR=$1
+    if [ -d "$DIR" ]; then
+        printf "$SGR_BLUE%s$SGR_RESET\n" "change directory to $DIR"
+        cd "$DIR" || exit 1
+    else
+        printf "$SGR_RED%s$SGR_RESET\n" "!!! cd $DIR"
+        exit 1
+    fi
+}
+
+change_dir_if() {
+    local COND=$1
+    local DIR=$2
+
+    if [ $COND -ne 0 ]; then
+        change_dir "$DIR"
+    fi
+}
+
+echo_to() {
+    local DEST=$1
+    local CONTENTS=$2
+
+    echo "$CONTENTS" >> "$DEST"
+}
+
+echo_if_to() {
+    local COND=$1
+    local DEST=$2
+    local CONTENTS=$3
+
+    if [ $COND -ne 0 ]; then
+        echo_to "$DEST" "$CONTENTS"
+    fi
+}
+
+install_cabalplan() {
+    put_info "installing cabal-plan"
+
+    if [ ! -e $CABAL_REPOCACHE/downloads/cabal-plan ]; then
+        curl -L https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > /tmp/cabal-plan.xz || exit 1
+        (cd /tmp && echo "de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc  cabal-plan.xz" | sha256sum -c -)|| exit 1
+        mkdir -p $CABAL_REPOCACHE/downloads
+        xz -d < /tmp/cabal-plan.xz > $CABAL_REPOCACHE/downloads/cabal-plan || exit 1
+        chmod a+x $CABAL_REPOCACHE/downloads/cabal-plan || exit 1
+    fi
+
+    mkdir -p $CABAL_DIR/bin || exit 1
+    ln -s $CABAL_REPOCACHE/downloads/cabal-plan $CABAL_DIR/bin/cabal-plan || exit 1
+}
+
+# Help
+##############################################################################
+
+show_usage() {
+cat <<EOF
+./haskell-ci.sh - build & test
+
+Usage: ./haskell-ci.sh [options]
+  A script to run automated checks locally (using Docker)
+
+Available options:
+  --jobs JOBS               Jobs to run (default: $CFG_JOBS)
+  --cabal-store-cache PATH  Directory to use for cabal-store-cache
+  --cabal-repo-cache PATH   Directory to use for cabal-repo-cache
+  --skip-cabal-update       Skip cabal update (useful with --cabal-repo-cache)
+  --no-skip-cabal-update
+  --help                    Print this message
+
+EOF
+}
+
+# getopt
+#######################################################################
+
+process_cli_options() {
+    while [ $# -gt 0 ]; do
+        arg=$1
+        case $arg in
+            --help)
+                show_usage
+                exit
+                ;;
+            --jobs)
+                CFG_JOBS=$2
+                shift
+                shift
+                ;;
+            --cabal-store-cache)
+                CFG_CABAL_STORE_CACHE=$2
+                shift
+                shift
+                ;;
+            --cabal-repo-cache)
+                CFG_CABAL_REPO_CACHE=$2
+                shift
+                shift
+                ;;
+            --skip-cabal-update)
+                CFG_CABAL_UPDATE=false
+                shift
+                ;;
+            --no-skip-cabal-update)
+                CFG_CABAL_UPDATE=true
+                shift
+                ;;
+            *)
+                echo "Unknown option $arg"
+                exit 1
+        esac
+    done
+}
+
+process_indocker_options () {
+    while [ $# -gt 0 ]; do
+        arg=$1
+
+        case $arg in
+            --ghc-version)
+                GHC_VERSION=$2
+                shift
+                shift
+                ;;
+            --cabal-version)
+                CABAL_VERSION=$2
+                shift
+                shift
+                ;;
+            --start-time)
+                START_TIME=$2
+                shift
+                shift
+                ;;
+            --cabal-update)
+                CABAL_UPDATE=$2
+                shift
+                shift
+                ;;
+            *)
+                echo "Unknown option $arg"
+                exit 1
+        esac
+    done
+}
+
+if $INDOCKER; then
+    process_indocker_options "$@"
+
+else
+    if [ -f "$XDG_CONFIG_HOME/haskell-ci/bash.config" ]; then
+        process_cli_options $(cat "$XDG_CONFIG_HOME/haskell-ci/bash.config")
+    fi
+
+    process_cli_options "$@"
+
+    put_info "jobs:              $CFG_JOBS"
+    put_info "cabal-store-cache: $CFG_CABAL_STORE_CACHE"
+    put_info "cabal-repo-cache:  $CFG_CABAL_REPO_CACHE"
+    put_info "cabal-update:      $CFG_CABAL_UPDATE"
+fi
+
+# Constants
+##############################################################################
+
+SRCDIR=/hsci/src
+BUILDDIR=/hsci/build
+CABAL_DIR="$BUILDDIR/cabal"
+CABAL_REPOCACHE=/hsci/cabal-repocache
+CABAL_STOREDIR=/hsci/store
+
+# Docker invoke
+##############################################################################
+
+# if cache directory is specified, use it.
+# Otherwise use another tmpfs host
+if [ -z "$CFG_CABAL_STORE_CACHE" ]; then
+    CABALSTOREARG="--tmpfs $CABAL_STOREDIR:exec"
+else
+    CABALSTOREARG="--volume $CFG_CABAL_STORE_CACHE:$CABAL_STOREDIR"
+fi
+
+if [ -z "$CFG_CABAL_REPO_CACHE" ]; then
+    CABALREPOARG="--tmpfs $CABAL_REPOCACHE:exec"
+else
+    CABALREPOARG="--volume $CFG_CABAL_REPO_CACHE:$CABAL_REPOCACHE"
+fi
+
+echo_docker_cmd() {
+    local GHCVER=$1
+
+    # TODO: mount /hsci/src:ro (readonly)
+    echo docker run \
+        --tty \
+        --interactive \
+        --rm \
+        --label haskell-ci \
+        --volume "$(pwd):/hsci/src" \
+        $CABALSTOREARG \
+        $CABALREPOARG \
+        --tmpfs /tmp:exec \
+        --tmpfs /hsci/build:exec \
+        --workdir /hsci/build \
+        "phadej/ghc:$GHCVER-bionic" \
+        "/bin/bash" "/hsci/src/$SCRIPT_NAME" indocker \
+        --ghc-version "$GHCVER" \
+        --cabal-update "$CFG_CABAL_UPDATE" \
+        --start-time "$START_TIME"
+}
+
+# if we are not in docker, loop through jobs
+if ! $INDOCKER; then
+    for JOB in $CFG_JOBS; do
+        put_info "Running in docker: $JOB"
+        run_cmd $(echo_docker_cmd "$JOB")
+    done
+
+    run_cmd echo "ALL OK"
+    exit 0
+fi
+
+# Otherwise we are in docker, and the rest of script executes
+put_info "In docker"
+
+# Environment
+##############################################################################
+
+GHCDIR=/opt/ghc/$GHC_VERSION
+
+HC=$GHCDIR/bin/ghc
+HCPKG=$GHCDIR/bin/ghc-pkg
+HADDOCK=$GHCDIR/bin/haddock
+
+CABAL=/opt/cabal/$CABAL_VERSION/bin/cabal
+
+CABAL="$CABAL -vnormal+nowrap"
+
+export CABAL_DIR
+export CABAL_CONFIG="$BUILDDIR/cabal/config"
+
+PATH="$CABAL_DIR/bin:$PATH"
+
+# HCNUMVER
+HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
+GHCJSARITH=0
+
+put_info "HCNUMVER: $HCNUMVER"
+
+# Args for shorter/nicer commands
+if [ 1 -ne 0 ] ; then ARG_TESTS=--enable-tests; else ARG_TESTS=--disable-tests; fi
+if [ 1 -ne 0 ] ; then ARG_BENCH=--enable-benchmarks; else ARG_BENCH=--disable-benchmarks; fi
+ARG_COMPILER="--ghc --with-compiler=$HC"
+
+put_info "tests/benchmarks: $ARG_TESTS $ARG_BENCH"
+
+# Apt dependencies
+##############################################################################
+
+
+# Cabal config
+##############################################################################
+
+mkdir -p $BUILDDIR/cabal
+
+cat > $BUILDDIR/cabal/config <<EOF
+remote-build-reporting: anonymous
+write-ghc-environment-files: always
+remote-repo-cache: $CABAL_REPOCACHE
+logs-dir:          $CABAL_DIR/logs
+world-file:        $CABAL_DIR/world
+extra-prog-path:   $CABAL_DIR/bin
+symlink-bindir:    $CABAL_DIR/bin
+installdir:        $CABAL_DIR/bin
+build-summary:     $CABAL_DIR/logs/build.log
+store-dir:         $CABAL_STOREDIR
+install-dirs user
+  prefix: $CABAL_DIR
+repository hackage.haskell.org
+  url: http://hackage.haskell.org/
+EOF
+
+if $HEADHACKAGE; then
+    put_error "head.hackage is not implemented"
+    exit 1
+fi
+
+run_cmd cat "$BUILDDIR/cabal/config"
+
+# Version
+##############################################################################
+
+put_info "Versions"
+run_cmd $HC --version
+run_cmd_unchecked $HC --print-project-git-commit-id
+run_cmd $CABAL --version
+
+# Build script
+##############################################################################
+
+# update cabal index
+if $CABAL_UPDATE; then
+    put_info "Updating Hackage index"
+    run_cmd $CABAL v2-update -v
+fi
+
+# install cabal-plan
+install_cabalplan
+run_cmd cabal-plan --version
+
+# initial cabal.project for sdist
+put_info "initial cabal.project for sdist"
+change_dir "$BUILDDIR"
+run_cmd touch cabal.project
+echo_to cabal.project "packages: $SRCDIR/servant"
+run_cmd cat cabal.project
+
+# sdist
+put_info "sdist"
+run_cmd mkdir -p "$BUILDDIR/sdist"
+run_cmd $CABAL sdist all --output-dir "$BUILDDIR/sdist"
+
+# unpack
+put_info "unpack"
+change_dir "$BUILDDIR"
+run_cmd mkdir -p "$BUILDDIR/unpacked"
+run_cmd find "$BUILDDIR/sdist" -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C "$BUILDDIR/unpacked" -xzvf {} \;
+
+# generate cabal.project
+put_info "generate cabal.project"
+PKGDIR_servant="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+run_cmd touch cabal.project
+run_cmd touch cabal.project.local
+echo_to cabal.project "packages: ${PKGDIR_servant}"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+cat >> cabal.project <<EOF
+EOF
+$HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(servant)$/; }' >> cabal.project.local
+run_cmd cat cabal.project
+run_cmd cat cabal.project.local
+
+# dump install plan
+put_info "dump install plan"
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
+run_cmd cabal-plan
+
+# install dependencies
+put_info "install dependencies"
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j all
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j all
+
+# build w/o tests
+put_info "build w/o tests"
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+
+# build
+put_info "build"
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all
+
+# tests
+put_info "tests"
+run_cmd $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
+
+# cabal check
+put_info "cabal check"
+change_dir "${PKGDIR_servant}"
+run_cmd ${CABAL} -vnormal check
+change_dir "$BUILDDIR"
+
+# haddock
+put_info "haddock"
+run_cmd $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
+
+# unconstrained build
+put_info "unconstrained build"
+run_cmd rm -f cabal.project.local
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+
+
+# Done
+run_cmd echo OK
diff --git a/fixtures/irc-channels.github b/fixtures/irc-channels.github
new file mode 100644
--- /dev/null
+++ b/fixtures/irc-channels.github
@@ -0,0 +1,247 @@
+# SUCCESS
+# *INFO* Generating GitHub config for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+# This GitHub workflow config has been generated by a script via
+#
+#   haskell-ci '--irc-channels=chat.freenode.net#mychannel' 'github' 'irc-channels.project'
+#
+# To regenerate the script (for example after adjusting tested-with) run
+#
+#   haskell-ci regenerate
+#
+# For more information, see https://github.com/haskell-CI/haskell-ci
+#
+# REGENDATA ["--irc-channels=chat.freenode.net#mychannel","github","irc-channels.project"]
+#
+name: Haskell-CI
+on:
+  - push
+  - pull_request
+jobs:
+  irc:
+    name: Haskell-CI (IRC notification)
+    runs-on: ubuntu-18.04
+    needs:
+      - linux
+    if: ${{ always() }}
+    strategy:
+      fail-fast: false
+    steps:
+      - name: IRC success notification (chat.freenode.net#mychannel)
+        uses: Gottox/irc-message-action@v1.1
+        if: needs.linux.result == 'success'
+        with:
+          channel: "#mychannel"
+          message: "\x0313servant\x03/\x0306${{ github.ref }}\x03 \x0314${{ github.sha }}\x03 https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} The build succeeded."
+          nickname: github-actions
+          server: chat.freenode.net
+      - name: IRC failure notification (chat.freenode.net#mychannel)
+        uses: Gottox/irc-message-action@v1.1
+        if: needs.linux.result != 'success'
+        with:
+          channel: "#mychannel"
+          message: "\x0313servant\x03/\x0306${{ github.ref }}\x03 \x0314${{ github.sha }}\x03 https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} The build failed."
+          nickname: github-actions
+          server: chat.freenode.net
+  linux:
+    name: Haskell-CI - Linux - ${{ matrix.compiler }}
+    runs-on: ubuntu-18.04
+    container:
+      image: buildpack-deps:bionic
+    continue-on-error: ${{ matrix.allow-failure }}
+    strategy:
+      matrix:
+        include:
+          - compiler: ghc-8.10.4
+            allow-failure: false
+          - compiler: ghc-8.10.3
+            allow-failure: false
+          - compiler: ghc-8.10.2
+            allow-failure: false
+          - compiler: ghc-8.10.1
+            allow-failure: false
+          - compiler: ghc-8.8.4
+            allow-failure: false
+          - compiler: ghc-8.8.3
+            allow-failure: false
+          - compiler: ghc-8.8.2
+            allow-failure: false
+          - compiler: ghc-8.8.1
+            allow-failure: false
+          - compiler: ghc-8.6.5
+            allow-failure: false
+          - compiler: ghc-8.6.4
+            allow-failure: false
+          - compiler: ghc-8.6.3
+            allow-failure: false
+          - compiler: ghc-8.6.2
+            allow-failure: false
+          - compiler: ghc-8.6.1
+            allow-failure: false
+          - compiler: ghc-8.4.4
+            allow-failure: false
+          - compiler: ghc-8.4.3
+            allow-failure: false
+          - compiler: ghc-8.4.2
+            allow-failure: false
+          - compiler: ghc-8.4.1
+            allow-failure: false
+          - compiler: ghc-8.2.2
+            allow-failure: false
+          - compiler: ghc-8.2.1
+            allow-failure: false
+          - compiler: ghc-8.0.2
+            allow-failure: false
+          - compiler: ghc-8.0.1
+            allow-failure: false
+          - compiler: ghc-7.10.3
+            allow-failure: false
+          - compiler: ghc-7.10.2
+            allow-failure: false
+          - compiler: ghc-7.10.1
+            allow-failure: false
+          - compiler: ghc-7.8.4
+            allow-failure: false
+          - compiler: ghc-7.8.3
+            allow-failure: false
+          - compiler: ghc-7.8.2
+            allow-failure: false
+          - compiler: ghc-7.8.1
+            allow-failure: false
+      fail-fast: false
+    steps:
+      - name: apt
+        run: |
+          apt-get update
+          apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common
+          apt-add-repository -y 'ppa:hvr/ghc'
+          apt-get update
+          apt-get install -y $CC cabal-install-3.4
+        env:
+          CC: ${{ matrix.compiler }}
+      - name: Set PATH and environment variables
+        run: |
+          echo "$HOME/.cabal/bin" >> $GITHUB_PATH
+          echo "LANG=C.UTF-8" >> $GITHUB_ENV
+          echo "CABAL_DIR=$HOME/.cabal" >> $GITHUB_ENV
+          echo "CABAL_CONFIG=$HOME/.cabal/config" >> $GITHUB_ENV
+          HCDIR=$(echo "/opt/$CC" | sed 's/-/\//')
+          HCNAME=ghc
+          HC=$HCDIR/bin/$HCNAME
+          echo "HC=$HC" >> $GITHUB_ENV
+          echo "HCPKG=$HCDIR/bin/$HCNAME-pkg" >> $GITHUB_ENV
+          echo "HADDOCK=$HCDIR/bin/haddock" >> $GITHUB_ENV
+          echo "CABAL=/opt/cabal/3.4/bin/cabal -vnormal+nowrap" >> $GITHUB_ENV
+          HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
+          echo "HCNUMVER=$HCNUMVER" >> $GITHUB_ENV
+          echo "ARG_TESTS=--enable-tests" >> $GITHUB_ENV
+          echo "ARG_BENCH=--enable-benchmarks" >> $GITHUB_ENV
+          echo "HEADHACKAGE=false" >> $GITHUB_ENV
+          echo "ARG_COMPILER=--$HCNAME --with-compiler=$HC" >> $GITHUB_ENV
+          echo "GHCJSARITH=0" >> $GITHUB_ENV
+        env:
+          CC: ${{ matrix.compiler }}
+      - name: env
+        run: |
+          env
+      - name: write cabal config
+        run: |
+          mkdir -p $CABAL_DIR
+          cat >> $CABAL_CONFIG <<EOF
+          remote-build-reporting: anonymous
+          write-ghc-environment-files: never
+          remote-repo-cache: $CABAL_DIR/packages
+          logs-dir:          $CABAL_DIR/logs
+          world-file:        $CABAL_DIR/world
+          extra-prog-path:   $CABAL_DIR/bin
+          symlink-bindir:    $CABAL_DIR/bin
+          installdir:        $CABAL_DIR/bin
+          build-summary:     $CABAL_DIR/logs/build.log
+          store-dir:         $CABAL_DIR/store
+          install-dirs user
+            prefix: $CABAL_DIR
+          repository hackage.haskell.org
+            url: http://hackage.haskell.org/
+          EOF
+          cat $CABAL_CONFIG
+      - name: versions
+        run: |
+          $HC --version || true
+          $HC --print-project-git-commit-id || true
+          $CABAL --version || true
+      - name: update cabal index
+        run: |
+          $CABAL v2-update -v
+      - name: install cabal-plan
+        run: |
+          mkdir -p $HOME/.cabal/bin
+          curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > cabal-plan.xz
+          echo 'de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc  cabal-plan.xz' | sha256sum -c -
+          xz -d < cabal-plan.xz > $HOME/.cabal/bin/cabal-plan
+          rm -f cabal-plan.xz
+          chmod a+x $HOME/.cabal/bin/cabal-plan
+          cabal-plan --version
+      - name: checkout
+        uses: actions/checkout@v2
+        with:
+          path: source
+      - name: initial cabal.project for sdist
+        run: |
+          touch cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant" >> cabal.project
+          cat cabal.project
+      - name: sdist
+        run: |
+          mkdir -p sdist
+          $CABAL sdist all --output-dir $GITHUB_WORKSPACE/sdist
+      - name: unpack
+        run: |
+          mkdir -p unpacked
+          find sdist -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C $GITHUB_WORKSPACE/unpacked -xzvf {} \;
+      - name: generate cabal.project
+        run: |
+          PKGDIR_servant="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+          echo "PKGDIR_servant=${PKGDIR_servant}" >> $GITHUB_ENV
+          touch cabal.project
+          touch cabal.project.local
+          echo "packages: ${PKGDIR_servant}" >> cabal.project
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          cat >> cabal.project <<EOF
+          EOF
+          $HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(servant)$/; }' >> cabal.project.local
+          cat cabal.project
+          cat cabal.project.local
+      - name: dump install plan
+        run: |
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
+          cabal-plan
+      - name: cache
+        uses: actions/cache@v2
+        with:
+          key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
+          path: ~/.cabal/store
+          restore-keys: ${{ runner.os }}-${{ matrix.compiler }}-
+      - name: install dependencies
+        run: |
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j2 all
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j2 all
+      - name: build w/o tests
+        run: |
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+      - name: build
+        run: |
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --write-ghc-environment-files=always
+      - name: tests
+        run: |
+          $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
+      - name: cabal check
+        run: |
+          cd ${PKGDIR_servant} || false
+          ${CABAL} -vnormal check
+      - name: haddock
+        run: |
+          $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
+      - name: unconstrained build
+        run: |
+          rm -f cabal.project.local
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
diff --git a/fixtures/irc-channels.project b/fixtures/irc-channels.project
new file mode 100644
--- /dev/null
+++ b/fixtures/irc-channels.project
@@ -0,0 +1,1 @@
+packages: servant
diff --git a/fixtures/irc-channels.travis b/fixtures/irc-channels.travis
new file mode 100644
--- /dev/null
+++ b/fixtures/irc-channels.travis
@@ -0,0 +1,225 @@
+# SUCCESS
+# *INFO* Generating Travis-CI config for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+# This Travis job script has been generated by a script via
+#
+#   haskell-ci '--irc-channels=chat.freenode.net#mychannel' 'travis' 'irc-channels.project'
+#
+# To regenerate the script (for example after adjusting tested-with) run
+#
+#   haskell-ci regenerate
+#
+# For more information, see https://github.com/haskell-CI/haskell-ci
+#
+version: ~> 1.0
+language: c
+os: linux
+dist: xenial
+git:
+  # whether to recursively clone submodules
+  submodules: false
+notifications:
+  irc:
+    channels:
+      - chat.freenode.net#mychannel
+    skip_join: true
+    template:
+      - "\x0313servant\x03/\x0306%{branch}\x03 \x0314%{commit}\x03 %{build_url} %{message}"
+cache:
+  directories:
+    - $HOME/.cabal/packages
+    - $HOME/.cabal/store
+    - $HOME/.hlint
+before_cache:
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log
+  # remove files that are regenerated by 'cabal update'
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx
+  - rm -rfv $CABALHOME/packages/head.hackage
+jobs:
+  include:
+    - compiler: ghc-8.10.4
+      addons: {"apt":{"packages":["ghc-8.10.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.3
+      addons: {"apt":{"packages":["ghc-8.10.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.2
+      addons: {"apt":{"packages":["ghc-8.10.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.1
+      addons: {"apt":{"packages":["ghc-8.10.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.4
+      addons: {"apt":{"packages":["ghc-8.8.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.3
+      addons: {"apt":{"packages":["ghc-8.8.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.2
+      addons: {"apt":{"packages":["ghc-8.8.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.1
+      addons: {"apt":{"packages":["ghc-8.8.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.5
+      addons: {"apt":{"packages":["ghc-8.6.5","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.4
+      addons: {"apt":{"packages":["ghc-8.6.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.3
+      addons: {"apt":{"packages":["ghc-8.6.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.2
+      addons: {"apt":{"packages":["ghc-8.6.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.1
+      addons: {"apt":{"packages":["ghc-8.6.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.4
+      addons: {"apt":{"packages":["ghc-8.4.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.3
+      addons: {"apt":{"packages":["ghc-8.4.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.2
+      addons: {"apt":{"packages":["ghc-8.4.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.1
+      addons: {"apt":{"packages":["ghc-8.4.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.2.2
+      addons: {"apt":{"packages":["ghc-8.2.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.2.1
+      addons: {"apt":{"packages":["ghc-8.2.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.0.2
+      addons: {"apt":{"packages":["ghc-8.0.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.0.1
+      addons: {"apt":{"packages":["ghc-8.0.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.3
+      addons: {"apt":{"packages":["ghc-7.10.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.2
+      addons: {"apt":{"packages":["ghc-7.10.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.1
+      addons: {"apt":{"packages":["ghc-7.10.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.4
+      addons: {"apt":{"packages":["ghc-7.8.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.3
+      addons: {"apt":{"packages":["ghc-7.8.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.2
+      addons: {"apt":{"packages":["ghc-7.8.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.1
+      addons: {"apt":{"packages":["ghc-7.8.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+before_install:
+  - HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//')
+  - WITHCOMPILER="-w $HC"
+  - HADDOCK=$(echo "/opt/$CC/bin/haddock" | sed 's/-/\//')
+  - HCPKG="$HC-pkg"
+  - unset CC
+  - CABAL=/opt/ghc/bin/cabal
+  - CABALHOME=$HOME/.cabal
+  - export PATH="$CABALHOME/bin:$PATH"
+  - TOP=$(pwd)
+  - "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')"
+  - echo $HCNUMVER
+  - CABAL="$CABAL -vnormal+nowrap"
+  - set -o pipefail
+  - TEST=--enable-tests
+  - BENCH=--enable-benchmarks
+  - HEADHACKAGE=false
+  - rm -f $CABALHOME/config
+  - |
+    echo "verbose: normal +nowrap +markoutput"          >> $CABALHOME/config
+    echo "remote-build-reporting: anonymous"            >> $CABALHOME/config
+    echo "write-ghc-environment-files: never"           >> $CABALHOME/config
+    echo "remote-repo-cache: $CABALHOME/packages"       >> $CABALHOME/config
+    echo "logs-dir:          $CABALHOME/logs"           >> $CABALHOME/config
+    echo "world-file:        $CABALHOME/world"          >> $CABALHOME/config
+    echo "extra-prog-path:   $CABALHOME/bin"            >> $CABALHOME/config
+    echo "symlink-bindir:    $CABALHOME/bin"            >> $CABALHOME/config
+    echo "installdir:        $CABALHOME/bin"            >> $CABALHOME/config
+    echo "build-summary:     $CABALHOME/logs/build.log" >> $CABALHOME/config
+    echo "store-dir:         $CABALHOME/store"          >> $CABALHOME/config
+    echo "install-dirs user"                            >> $CABALHOME/config
+    echo "  prefix: $CABALHOME"                         >> $CABALHOME/config
+    echo "repository hackage.haskell.org"               >> $CABALHOME/config
+    echo "  url: http://hackage.haskell.org/"           >> $CABALHOME/config
+install:
+  - ${CABAL} --version
+  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
+  - |
+    echo "program-default-options"                >> $CABALHOME/config
+    echo "  ghc-options: $GHCJOBS +RTS -M6G -RTS" >> $CABALHOME/config
+  - cat $CABALHOME/config
+  - rm -fv cabal.project cabal.project.local cabal.project.freeze
+  - travis_retry ${CABAL} v2-update -v
+  # Generate cabal.project
+  - rm -rf cabal.project cabal.project.local cabal.project.freeze
+  - touch cabal.project
+  - |
+    echo "packages: servant" >> cabal.project
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - |
+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
+  - cat cabal.project || true
+  - cat cabal.project.local || true
+  - if [ -f "servant/configure.ac" ]; then (cd "servant" && autoreconf -i); fi
+  - ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH}
+  - "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
+  - rm  cabal.project.freeze
+  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} --dep -j2 all
+  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --dep -j2 all
+script:
+  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
+  # Packaging...
+  - ${CABAL} v2-sdist all
+  # Unpacking...
+  - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
+  - cd ${DISTDIR} || false
+  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \;
+  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm       '{}' \;
+  - PKGDIR_servant="$(find . -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+  # Generate cabal.project
+  - rm -rf cabal.project cabal.project.local cabal.project.freeze
+  - touch cabal.project
+  - |
+    echo "packages: ${PKGDIR_servant}" >> cabal.project
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - |
+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
+  - cat cabal.project || true
+  - cat cabal.project.local || true
+  # Building...
+  # this builds all libraries and executables (without tests/benchmarks)
+  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
+  # Building with tests and benchmarks...
+  # build & run tests, build benchmarks
+  - ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} all --write-ghc-environment-files=always
+  # Testing...
+  - ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all --test-show-details=direct
+  # cabal check...
+  - (cd ${PKGDIR_servant} && ${CABAL} -vnormal check)
+  # haddock...
+  - ${CABAL} v2-haddock $WITHCOMPILER --with-haddock $HADDOCK ${TEST} ${BENCH} all
+  # Building without installed constraints for packages in global-db...
+  - rm -f cabal.project.local
+  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
+
+# REGENDATA ["--irc-channels=chat.freenode.net#mychannel","travis","irc-channels.project"]
+# EOF
diff --git a/fixtures/messy.args b/fixtures/messy.args
new file mode 100644
--- /dev/null
+++ b/fixtures/messy.args
@@ -0,0 +1,3 @@
+--ghc-head
+--apt=fftw3-dev
+--installed=-all +deepseq
diff --git a/fixtures/messy.bash b/fixtures/messy.bash
new file mode 100644
--- /dev/null
+++ b/fixtures/messy.bash
@@ -0,0 +1,545 @@
+# SUCCESS
+# *INFO* Generating Bash script for testing for GHC versions: ghc-head 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+#!/bin/bash
+# shellcheck disable=SC2086,SC2016,SC2046
+# REGENDATA ["--ghc-head","--apt=fftw3-dev","--installed=-all +deepseq","bash","messy.project"]
+
+set -o pipefail
+
+# Mode
+##############################################################################
+
+if [ "$1" = "indocker" ]; then
+    INDOCKER=true
+    shift
+else
+    INDOCKER=false
+fi
+
+# Run configuration
+##############################################################################
+
+CFG_CABAL_STORE_CACHE=""
+CFG_CABAL_REPO_CACHE=""
+CFG_JOBS="8.10.4 8.10.3 8.10.2 8.10.1 8.8.4 8.8.3 8.8.2 8.8.1 8.6.5 8.6.4 8.6.3 8.6.2 8.6.1 8.4.4 8.4.3 8.4.2 8.4.1 8.2.2 8.2.1 8.0.2 8.0.1 7.10.3 7.10.2 7.10.1 7.8.4 7.8.3 7.8.2 7.8.1"
+CFG_CABAL_UPDATE=false
+
+SCRIPT_NAME=$(basename "$0")
+START_TIME="$(date +'%s')"
+
+XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config}
+
+# Job configuration
+##############################################################################
+
+GHC_VERSION="non-existing"
+CABAL_VERSION=3.2
+HEADHACKAGE=false
+
+# Locale
+##############################################################################
+
+export LC_ALL=C.UTF-8
+
+# Utilities
+##############################################################################
+
+SGR_RED='\033[1;31m'
+SGR_GREEN='\033[1;32m'
+SGR_BLUE='\033[1;34m'
+SGR_CYAN='\033[1;96m'
+SGR_RESET='\033[0m' # No Color
+
+put_info() {
+    printf "$SGR_CYAN%s$SGR_RESET\n" "### $*"
+}
+
+put_error() {
+    printf "$SGR_RED%s$SGR_RESET\n" "!!! $*"
+}
+
+run_cmd() {
+    local PRETTYCMD="$*"
+    local PROMPT
+    if $INDOCKER; then
+        PROMPT="$(pwd) >>>"
+    else
+        PROMPT=">>>"
+    fi
+
+    printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+
+    local start_time end_time cmd_duration total_duration
+    start_time=$(date +'%s')
+
+    "$@"
+    local RET=$?
+
+    end_time=$(date +'%s')
+    cmd_duration=$((end_time - start_time))
+    total_duration=$((end_time - START_TIME))
+
+    cmd_min=$((cmd_duration / 60))
+    cmd_sec=$((cmd_duration % 60))
+
+    total_min=$((total_duration / 60))
+    total_sec=$((total_duration % 60))
+
+    if [ $RET -eq 0 ]; then
+        printf "$SGR_GREEN%s$SGR_RESET (%dm%02ds; %dm%02ds)\n" "<<< $PRETTYCMD" "$cmd_min" "$cmd_sec" "$total_min" "$total_sec"
+    else
+        printf "$SGR_RED%s$SGR_RESET\n" "!!! $PRETTYCMD"
+        exit 1
+    fi
+}
+
+run_cmd_if() {
+    local COND=$1
+    shift
+
+    if [ $COND -eq 1 ]; then
+        run_cmd "$@"
+    else
+        local PRETTYCMD="$*"
+        local PROMPT
+        PROMPT="$(pwd) (skipping) >>>"
+
+        printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+    fi
+}
+
+run_cmd_unchecked() {
+    local PRETTYCMD="$*"
+    local PROMPT
+    if $INDOCKER; then
+        PROMPT="$(pwd) >>>"
+    else
+        PROMPT=">>>"
+    fi
+
+    printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+
+    local start_time end_time cmd_duration total_duration cmd_min cmd_sec total_min total_sec
+    start_time=$(date +'%s')
+
+    "$@"
+
+    end_time=$(date +'%s')
+    cmd_duration=$((end_time - start_time))
+    total_duration=$((end_time - START_TIME))
+
+    cmd_min=$((cmd_duration / 60))
+    cmd_sec=$((cmd_duration % 60))
+
+    total_min=$((total_duration / 60))
+    total_sec=$((total_duration % 60))
+
+    printf "$SGR_GREEN%s$SGR_RESET (%dm%02ds; %dm%02ds)\n" "<<< $PRETTYCMD" "$cmd_min" "$cmd_sec" "$total_min" "$total_sec"
+}
+
+change_dir() {
+    local DIR=$1
+    if [ -d "$DIR" ]; then
+        printf "$SGR_BLUE%s$SGR_RESET\n" "change directory to $DIR"
+        cd "$DIR" || exit 1
+    else
+        printf "$SGR_RED%s$SGR_RESET\n" "!!! cd $DIR"
+        exit 1
+    fi
+}
+
+change_dir_if() {
+    local COND=$1
+    local DIR=$2
+
+    if [ $COND -ne 0 ]; then
+        change_dir "$DIR"
+    fi
+}
+
+echo_to() {
+    local DEST=$1
+    local CONTENTS=$2
+
+    echo "$CONTENTS" >> "$DEST"
+}
+
+echo_if_to() {
+    local COND=$1
+    local DEST=$2
+    local CONTENTS=$3
+
+    if [ $COND -ne 0 ]; then
+        echo_to "$DEST" "$CONTENTS"
+    fi
+}
+
+install_cabalplan() {
+    put_info "installing cabal-plan"
+
+    if [ ! -e $CABAL_REPOCACHE/downloads/cabal-plan ]; then
+        curl -L https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > /tmp/cabal-plan.xz || exit 1
+        (cd /tmp && echo "de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc  cabal-plan.xz" | sha256sum -c -)|| exit 1
+        mkdir -p $CABAL_REPOCACHE/downloads
+        xz -d < /tmp/cabal-plan.xz > $CABAL_REPOCACHE/downloads/cabal-plan || exit 1
+        chmod a+x $CABAL_REPOCACHE/downloads/cabal-plan || exit 1
+    fi
+
+    mkdir -p $CABAL_DIR/bin || exit 1
+    ln -s $CABAL_REPOCACHE/downloads/cabal-plan $CABAL_DIR/bin/cabal-plan || exit 1
+}
+
+# Help
+##############################################################################
+
+show_usage() {
+cat <<EOF
+./haskell-ci.sh - build & test
+
+Usage: ./haskell-ci.sh [options]
+  A script to run automated checks locally (using Docker)
+
+Available options:
+  --jobs JOBS               Jobs to run (default: $CFG_JOBS)
+  --cabal-store-cache PATH  Directory to use for cabal-store-cache
+  --cabal-repo-cache PATH   Directory to use for cabal-repo-cache
+  --skip-cabal-update       Skip cabal update (useful with --cabal-repo-cache)
+  --no-skip-cabal-update
+  --help                    Print this message
+
+EOF
+}
+
+# getopt
+#######################################################################
+
+process_cli_options() {
+    while [ $# -gt 0 ]; do
+        arg=$1
+        case $arg in
+            --help)
+                show_usage
+                exit
+                ;;
+            --jobs)
+                CFG_JOBS=$2
+                shift
+                shift
+                ;;
+            --cabal-store-cache)
+                CFG_CABAL_STORE_CACHE=$2
+                shift
+                shift
+                ;;
+            --cabal-repo-cache)
+                CFG_CABAL_REPO_CACHE=$2
+                shift
+                shift
+                ;;
+            --skip-cabal-update)
+                CFG_CABAL_UPDATE=false
+                shift
+                ;;
+            --no-skip-cabal-update)
+                CFG_CABAL_UPDATE=true
+                shift
+                ;;
+            *)
+                echo "Unknown option $arg"
+                exit 1
+        esac
+    done
+}
+
+process_indocker_options () {
+    while [ $# -gt 0 ]; do
+        arg=$1
+
+        case $arg in
+            --ghc-version)
+                GHC_VERSION=$2
+                shift
+                shift
+                ;;
+            --cabal-version)
+                CABAL_VERSION=$2
+                shift
+                shift
+                ;;
+            --start-time)
+                START_TIME=$2
+                shift
+                shift
+                ;;
+            --cabal-update)
+                CABAL_UPDATE=$2
+                shift
+                shift
+                ;;
+            *)
+                echo "Unknown option $arg"
+                exit 1
+        esac
+    done
+}
+
+if $INDOCKER; then
+    process_indocker_options "$@"
+
+else
+    if [ -f "$XDG_CONFIG_HOME/haskell-ci/bash.config" ]; then
+        process_cli_options $(cat "$XDG_CONFIG_HOME/haskell-ci/bash.config")
+    fi
+
+    process_cli_options "$@"
+
+    put_info "jobs:              $CFG_JOBS"
+    put_info "cabal-store-cache: $CFG_CABAL_STORE_CACHE"
+    put_info "cabal-repo-cache:  $CFG_CABAL_REPO_CACHE"
+    put_info "cabal-update:      $CFG_CABAL_UPDATE"
+fi
+
+# Constants
+##############################################################################
+
+SRCDIR=/hsci/src
+BUILDDIR=/hsci/build
+CABAL_DIR="$BUILDDIR/cabal"
+CABAL_REPOCACHE=/hsci/cabal-repocache
+CABAL_STOREDIR=/hsci/store
+
+# Docker invoke
+##############################################################################
+
+# if cache directory is specified, use it.
+# Otherwise use another tmpfs host
+if [ -z "$CFG_CABAL_STORE_CACHE" ]; then
+    CABALSTOREARG="--tmpfs $CABAL_STOREDIR:exec"
+else
+    CABALSTOREARG="--volume $CFG_CABAL_STORE_CACHE:$CABAL_STOREDIR"
+fi
+
+if [ -z "$CFG_CABAL_REPO_CACHE" ]; then
+    CABALREPOARG="--tmpfs $CABAL_REPOCACHE:exec"
+else
+    CABALREPOARG="--volume $CFG_CABAL_REPO_CACHE:$CABAL_REPOCACHE"
+fi
+
+echo_docker_cmd() {
+    local GHCVER=$1
+
+    # TODO: mount /hsci/src:ro (readonly)
+    echo docker run \
+        --tty \
+        --interactive \
+        --rm \
+        --label haskell-ci \
+        --volume "$(pwd):/hsci/src" \
+        $CABALSTOREARG \
+        $CABALREPOARG \
+        --tmpfs /tmp:exec \
+        --tmpfs /hsci/build:exec \
+        --workdir /hsci/build \
+        "phadej/ghc:$GHCVER-bionic" \
+        "/bin/bash" "/hsci/src/$SCRIPT_NAME" indocker \
+        --ghc-version "$GHCVER" \
+        --cabal-update "$CFG_CABAL_UPDATE" \
+        --start-time "$START_TIME"
+}
+
+# if we are not in docker, loop through jobs
+if ! $INDOCKER; then
+    for JOB in $CFG_JOBS; do
+        put_info "Running in docker: $JOB"
+        run_cmd $(echo_docker_cmd "$JOB")
+    done
+
+    run_cmd echo "ALL OK"
+    exit 0
+fi
+
+# Otherwise we are in docker, and the rest of script executes
+put_info "In docker"
+
+# Environment
+##############################################################################
+
+GHCDIR=/opt/ghc/$GHC_VERSION
+
+HC=$GHCDIR/bin/ghc
+HCPKG=$GHCDIR/bin/ghc-pkg
+HADDOCK=$GHCDIR/bin/haddock
+
+CABAL=/opt/cabal/$CABAL_VERSION/bin/cabal
+
+CABAL="$CABAL -vnormal+nowrap"
+
+export CABAL_DIR
+export CABAL_CONFIG="$BUILDDIR/cabal/config"
+
+PATH="$CABAL_DIR/bin:$PATH"
+
+# HCNUMVER
+HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
+GHCJSARITH=0
+
+put_info "HCNUMVER: $HCNUMVER"
+
+# Args for shorter/nicer commands
+if [ 1 -ne 0 ] ; then ARG_TESTS=--enable-tests; else ARG_TESTS=--disable-tests; fi
+if [ 1 -ne 0 ] ; then ARG_BENCH=--enable-benchmarks; else ARG_BENCH=--disable-benchmarks; fi
+ARG_COMPILER="--ghc --with-compiler=$HC"
+
+put_info "tests/benchmarks: $ARG_TESTS $ARG_BENCH"
+
+# Apt dependencies
+##############################################################################
+
+run_cmd apt-get update
+run_cmd apt-get install -y --no-install-recommends fftw3-dev
+
+# Cabal config
+##############################################################################
+
+mkdir -p $BUILDDIR/cabal
+
+cat > $BUILDDIR/cabal/config <<EOF
+remote-build-reporting: anonymous
+write-ghc-environment-files: always
+remote-repo-cache: $CABAL_REPOCACHE
+logs-dir:          $CABAL_DIR/logs
+world-file:        $CABAL_DIR/world
+extra-prog-path:   $CABAL_DIR/bin
+symlink-bindir:    $CABAL_DIR/bin
+installdir:        $CABAL_DIR/bin
+build-summary:     $CABAL_DIR/logs/build.log
+store-dir:         $CABAL_STOREDIR
+install-dirs user
+  prefix: $CABAL_DIR
+repository hackage.haskell.org
+  url: http://hackage.haskell.org/
+EOF
+
+if $HEADHACKAGE; then
+    put_error "head.hackage is not implemented"
+    exit 1
+fi
+
+run_cmd cat "$BUILDDIR/cabal/config"
+
+# Version
+##############################################################################
+
+put_info "Versions"
+run_cmd $HC --version
+run_cmd_unchecked $HC --print-project-git-commit-id
+run_cmd $CABAL --version
+
+# Build script
+##############################################################################
+
+# update cabal index
+if $CABAL_UPDATE; then
+    put_info "Updating Hackage index"
+    run_cmd $CABAL v2-update -v
+fi
+
+# install cabal-plan
+install_cabalplan
+run_cmd cabal-plan --version
+
+# initial cabal.project for sdist
+put_info "initial cabal.project for sdist"
+change_dir "$BUILDDIR"
+run_cmd touch cabal.project
+echo_to cabal.project "packages: $SRCDIR/servant"
+echo_to cabal.project "packages: $SRCDIR/servant-client"
+echo_to cabal.project "packages: $SRCDIR/servant-docs"
+echo_to cabal.project "packages: $SRCDIR/servant-server"
+run_cmd cat cabal.project
+
+# sdist
+put_info "sdist"
+run_cmd mkdir -p "$BUILDDIR/sdist"
+run_cmd $CABAL sdist all --output-dir "$BUILDDIR/sdist"
+
+# unpack
+put_info "unpack"
+change_dir "$BUILDDIR"
+run_cmd mkdir -p "$BUILDDIR/unpacked"
+run_cmd find "$BUILDDIR/sdist" -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C "$BUILDDIR/unpacked" -xzvf {} \;
+
+# generate cabal.project
+put_info "generate cabal.project"
+PKGDIR_servant="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+PKGDIR_servant_client="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-client-[0-9.]*')"
+PKGDIR_servant_docs="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-docs-[0-9.]*')"
+PKGDIR_servant_server="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-server-[0-9.]*')"
+run_cmd touch cabal.project
+run_cmd touch cabal.project.local
+echo_to cabal.project "packages: ${PKGDIR_servant}"
+echo_to cabal.project "packages: ${PKGDIR_servant_client}"
+echo_to cabal.project "packages: ${PKGDIR_servant_docs}"
+echo_to cabal.project "packages: ${PKGDIR_servant_server}"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant-client"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant-docs"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant-server"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+cat >> cabal.project <<EOF
+EOF
+cat >> cabal.project.local <<EOF
+constraints: deepseq installed
+EOF
+run_cmd cat cabal.project
+run_cmd cat cabal.project.local
+
+# dump install plan
+put_info "dump install plan"
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
+run_cmd cabal-plan
+
+# install dependencies
+put_info "install dependencies"
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j all
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j all
+
+# build w/o tests
+put_info "build w/o tests"
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+
+# build
+put_info "build"
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all
+
+# tests
+put_info "tests"
+run_cmd $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
+
+# cabal check
+put_info "cabal check"
+change_dir "${PKGDIR_servant}"
+run_cmd ${CABAL} -vnormal check
+change_dir "${PKGDIR_servant_client}"
+run_cmd ${CABAL} -vnormal check
+change_dir "${PKGDIR_servant_docs}"
+run_cmd ${CABAL} -vnormal check
+change_dir "${PKGDIR_servant_server}"
+run_cmd ${CABAL} -vnormal check
+change_dir "$BUILDDIR"
+
+# haddock
+put_info "haddock"
+run_cmd $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
+
+# unconstrained build
+put_info "unconstrained build"
+run_cmd rm -f cabal.project.local
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+
+
+# Done
+run_cmd echo OK
diff --git a/fixtures/messy.github b/fixtures/messy.github
new file mode 100644
--- /dev/null
+++ b/fixtures/messy.github
@@ -0,0 +1,262 @@
+# SUCCESS
+# *INFO* Generating GitHub config for testing for GHC versions: ghc-head 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+# This GitHub workflow config has been generated by a script via
+#
+#   haskell-ci '--ghc-head' '--apt=fftw3-dev' '--installed=-all +deepseq' 'github' 'messy.project'
+#
+# To regenerate the script (for example after adjusting tested-with) run
+#
+#   haskell-ci regenerate
+#
+# For more information, see https://github.com/haskell-CI/haskell-ci
+#
+# REGENDATA ["--ghc-head","--apt=fftw3-dev","--installed=-all +deepseq","github","messy.project"]
+#
+name: Haskell-CI
+on:
+  - push
+  - pull_request
+jobs:
+  linux:
+    name: Haskell-CI - Linux - ${{ matrix.compiler }}
+    runs-on: ubuntu-18.04
+    container:
+      image: buildpack-deps:bionic
+    continue-on-error: ${{ matrix.allow-failure }}
+    strategy:
+      matrix:
+        include:
+          - compiler: ghc-8.10.4
+            allow-failure: false
+          - compiler: ghc-8.10.3
+            allow-failure: false
+          - compiler: ghc-8.10.2
+            allow-failure: false
+          - compiler: ghc-8.10.1
+            allow-failure: false
+          - compiler: ghc-8.8.4
+            allow-failure: false
+          - compiler: ghc-8.8.3
+            allow-failure: false
+          - compiler: ghc-8.8.2
+            allow-failure: false
+          - compiler: ghc-8.8.1
+            allow-failure: false
+          - compiler: ghc-8.6.5
+            allow-failure: false
+          - compiler: ghc-8.6.4
+            allow-failure: false
+          - compiler: ghc-8.6.3
+            allow-failure: false
+          - compiler: ghc-8.6.2
+            allow-failure: false
+          - compiler: ghc-8.6.1
+            allow-failure: false
+          - compiler: ghc-8.4.4
+            allow-failure: false
+          - compiler: ghc-8.4.3
+            allow-failure: false
+          - compiler: ghc-8.4.2
+            allow-failure: false
+          - compiler: ghc-8.4.1
+            allow-failure: false
+          - compiler: ghc-8.2.2
+            allow-failure: false
+          - compiler: ghc-8.2.1
+            allow-failure: false
+          - compiler: ghc-8.0.2
+            allow-failure: false
+          - compiler: ghc-8.0.1
+            allow-failure: false
+          - compiler: ghc-7.10.3
+            allow-failure: false
+          - compiler: ghc-7.10.2
+            allow-failure: false
+          - compiler: ghc-7.10.1
+            allow-failure: false
+          - compiler: ghc-7.8.4
+            allow-failure: false
+          - compiler: ghc-7.8.3
+            allow-failure: false
+          - compiler: ghc-7.8.2
+            allow-failure: false
+          - compiler: ghc-7.8.1
+            allow-failure: false
+      fail-fast: false
+    steps:
+      - name: apt
+        run: |
+          apt-get update
+          apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common
+          apt-add-repository -y 'ppa:hvr/ghc'
+          apt-get update
+          apt-get install -y $CC cabal-install-3.4 fftw3-dev
+        env:
+          CC: ${{ matrix.compiler }}
+      - name: Set PATH and environment variables
+        run: |
+          echo "$HOME/.cabal/bin" >> $GITHUB_PATH
+          echo "LANG=C.UTF-8" >> $GITHUB_ENV
+          echo "CABAL_DIR=$HOME/.cabal" >> $GITHUB_ENV
+          echo "CABAL_CONFIG=$HOME/.cabal/config" >> $GITHUB_ENV
+          HCDIR=$(echo "/opt/$CC" | sed 's/-/\//')
+          HCNAME=ghc
+          HC=$HCDIR/bin/$HCNAME
+          echo "HC=$HC" >> $GITHUB_ENV
+          echo "HCPKG=$HCDIR/bin/$HCNAME-pkg" >> $GITHUB_ENV
+          echo "HADDOCK=$HCDIR/bin/haddock" >> $GITHUB_ENV
+          echo "CABAL=/opt/cabal/3.4/bin/cabal -vnormal+nowrap" >> $GITHUB_ENV
+          HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
+          echo "HCNUMVER=$HCNUMVER" >> $GITHUB_ENV
+          echo "ARG_TESTS=--enable-tests" >> $GITHUB_ENV
+          echo "ARG_BENCH=--enable-benchmarks" >> $GITHUB_ENV
+          if [ $((HCNUMVER > 81004)) -ne 0 ] ; then echo "HEADHACKAGE=true" >> $GITHUB_ENV ; else echo "HEADHACKAGE=false" >> $GITHUB_ENV ; fi
+          echo "ARG_COMPILER=--$HCNAME --with-compiler=$HC" >> $GITHUB_ENV
+          echo "GHCJSARITH=0" >> $GITHUB_ENV
+        env:
+          CC: ${{ matrix.compiler }}
+      - name: env
+        run: |
+          env
+      - name: write cabal config
+        run: |
+          mkdir -p $CABAL_DIR
+          cat >> $CABAL_CONFIG <<EOF
+          remote-build-reporting: anonymous
+          write-ghc-environment-files: never
+          remote-repo-cache: $CABAL_DIR/packages
+          logs-dir:          $CABAL_DIR/logs
+          world-file:        $CABAL_DIR/world
+          extra-prog-path:   $CABAL_DIR/bin
+          symlink-bindir:    $CABAL_DIR/bin
+          installdir:        $CABAL_DIR/bin
+          build-summary:     $CABAL_DIR/logs/build.log
+          store-dir:         $CABAL_DIR/store
+          install-dirs user
+            prefix: $CABAL_DIR
+          repository hackage.haskell.org
+            url: http://hackage.haskell.org/
+          EOF
+          if $HEADHACKAGE; then
+          cat >> $CABAL_CONFIG <<EOF
+          repository head.hackage.ghc.haskell.org
+             url: https://ghc.gitlab.haskell.org/head.hackage/
+             secure: True
+             root-keys: 7541f32a4ccca4f97aea3b22f5e593ba2c0267546016b992dfadcd2fe944e55d
+                        26021a13b401500c8eb2761ca95c61f2d625bfef951b939a8124ed12ecf07329
+                        f76d08be13e9a61a377a85e2fb63f4c5435d40f8feb3e12eb05905edb8cdea89
+             key-threshold: 3
+          EOF
+          fi
+          cat $CABAL_CONFIG
+      - name: versions
+        run: |
+          $HC --version || true
+          $HC --print-project-git-commit-id || true
+          $CABAL --version || true
+      - name: update cabal index
+        run: |
+          $CABAL v2-update -v
+      - name: install cabal-plan
+        run: |
+          mkdir -p $HOME/.cabal/bin
+          curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > cabal-plan.xz
+          echo 'de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc  cabal-plan.xz' | sha256sum -c -
+          xz -d < cabal-plan.xz > $HOME/.cabal/bin/cabal-plan
+          rm -f cabal-plan.xz
+          chmod a+x $HOME/.cabal/bin/cabal-plan
+          cabal-plan --version
+      - name: checkout
+        uses: actions/checkout@v2
+        with:
+          path: source
+      - name: initial cabal.project for sdist
+        run: |
+          touch cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant" >> cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant-client" >> cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant-docs" >> cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant-server" >> cabal.project
+          cat cabal.project
+      - name: sdist
+        run: |
+          mkdir -p sdist
+          $CABAL sdist all --output-dir $GITHUB_WORKSPACE/sdist
+      - name: unpack
+        run: |
+          mkdir -p unpacked
+          find sdist -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C $GITHUB_WORKSPACE/unpacked -xzvf {} \;
+      - name: generate cabal.project
+        run: |
+          PKGDIR_servant="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+          echo "PKGDIR_servant=${PKGDIR_servant}" >> $GITHUB_ENV
+          PKGDIR_servant_client="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-client-[0-9.]*')"
+          echo "PKGDIR_servant_client=${PKGDIR_servant_client}" >> $GITHUB_ENV
+          PKGDIR_servant_docs="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-docs-[0-9.]*')"
+          echo "PKGDIR_servant_docs=${PKGDIR_servant_docs}" >> $GITHUB_ENV
+          PKGDIR_servant_server="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-server-[0-9.]*')"
+          echo "PKGDIR_servant_server=${PKGDIR_servant_server}" >> $GITHUB_ENV
+          touch cabal.project
+          touch cabal.project.local
+          echo "packages: ${PKGDIR_servant}" >> cabal.project
+          echo "packages: ${PKGDIR_servant_client}" >> cabal.project
+          echo "packages: ${PKGDIR_servant_docs}" >> cabal.project
+          echo "packages: ${PKGDIR_servant_server}" >> cabal.project
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant-client" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant-docs" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant-server" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          cat >> cabal.project <<EOF
+          EOF
+          if $HEADHACKAGE; then
+          echo "allow-newer: $($HCPKG list --simple-output | sed -E 's/([a-zA-Z-]+)-[0-9.]+/*:\1,/g')" >> cabal.project
+          fi
+          cat >> cabal.project.local <<EOF
+          constraints: deepseq installed
+          EOF
+          cat cabal.project
+          cat cabal.project.local
+      - name: dump install plan
+        run: |
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
+          cabal-plan
+      - name: cache
+        uses: actions/cache@v2
+        with:
+          key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
+          path: ~/.cabal/store
+          restore-keys: ${{ runner.os }}-${{ matrix.compiler }}-
+      - name: install dependencies
+        run: |
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j2 all
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j2 all
+      - name: build w/o tests
+        run: |
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+      - name: build
+        run: |
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --write-ghc-environment-files=always
+      - name: tests
+        run: |
+          $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
+      - name: cabal check
+        run: |
+          cd ${PKGDIR_servant} || false
+          ${CABAL} -vnormal check
+          cd ${PKGDIR_servant_client} || false
+          ${CABAL} -vnormal check
+          cd ${PKGDIR_servant_docs} || false
+          ${CABAL} -vnormal check
+          cd ${PKGDIR_servant_server} || false
+          ${CABAL} -vnormal check
+      - name: haddock
+        run: |
+          $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
+      - name: unconstrained build
+        run: |
+          rm -f cabal.project.local
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
diff --git a/fixtures/messy.project b/fixtures/messy.project
new file mode 100644
--- /dev/null
+++ b/fixtures/messy.project
@@ -0,0 +1,6 @@
+packages: servant/,
+
+  servant-client/
+ 
+ ,
+     servant-docs/,servant-server/
diff --git a/fixtures/messy.travis b/fixtures/messy.travis
new file mode 100644
--- /dev/null
+++ b/fixtures/messy.travis
@@ -0,0 +1,269 @@
+# SUCCESS
+# *INFO* Generating Travis-CI config for testing for GHC versions: ghc-head 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+# This Travis job script has been generated by a script via
+#
+#   haskell-ci '--ghc-head' '--apt=fftw3-dev' '--installed=-all +deepseq' 'travis' 'messy.project'
+#
+# To regenerate the script (for example after adjusting tested-with) run
+#
+#   haskell-ci regenerate
+#
+# For more information, see https://github.com/haskell-CI/haskell-ci
+#
+version: ~> 1.0
+language: c
+os: linux
+dist: xenial
+git:
+  # whether to recursively clone submodules
+  submodules: false
+cache:
+  directories:
+    - $HOME/.cabal/packages
+    - $HOME/.cabal/store
+    - $HOME/.hlint
+before_cache:
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log
+  # remove files that are regenerated by 'cabal update'
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx
+  - rm -rfv $CABALHOME/packages/head.hackage
+jobs:
+  include:
+    - compiler: ghc-8.10.4
+      addons: {"apt":{"packages":["ghc-8.10.4","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.3
+      addons: {"apt":{"packages":["ghc-8.10.3","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.2
+      addons: {"apt":{"packages":["ghc-8.10.2","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.1
+      addons: {"apt":{"packages":["ghc-8.10.1","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.4
+      addons: {"apt":{"packages":["ghc-8.8.4","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.3
+      addons: {"apt":{"packages":["ghc-8.8.3","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.2
+      addons: {"apt":{"packages":["ghc-8.8.2","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.1
+      addons: {"apt":{"packages":["ghc-8.8.1","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.5
+      addons: {"apt":{"packages":["ghc-8.6.5","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.4
+      addons: {"apt":{"packages":["ghc-8.6.4","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.3
+      addons: {"apt":{"packages":["ghc-8.6.3","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.2
+      addons: {"apt":{"packages":["ghc-8.6.2","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.1
+      addons: {"apt":{"packages":["ghc-8.6.1","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.4
+      addons: {"apt":{"packages":["ghc-8.4.4","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.3
+      addons: {"apt":{"packages":["ghc-8.4.3","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.2
+      addons: {"apt":{"packages":["ghc-8.4.2","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.1
+      addons: {"apt":{"packages":["ghc-8.4.1","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.2.2
+      addons: {"apt":{"packages":["ghc-8.2.2","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.2.1
+      addons: {"apt":{"packages":["ghc-8.2.1","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.0.2
+      addons: {"apt":{"packages":["ghc-8.0.2","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.0.1
+      addons: {"apt":{"packages":["ghc-8.0.1","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.3
+      addons: {"apt":{"packages":["ghc-7.10.3","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.2
+      addons: {"apt":{"packages":["ghc-7.10.2","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.1
+      addons: {"apt":{"packages":["ghc-7.10.1","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.4
+      addons: {"apt":{"packages":["ghc-7.8.4","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.3
+      addons: {"apt":{"packages":["ghc-7.8.3","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.2
+      addons: {"apt":{"packages":["ghc-7.8.2","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.1
+      addons: {"apt":{"packages":["ghc-7.8.1","cabal-install-3.4","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-head
+      addons: {"apt":{"packages":["ghc-head","cabal-install-head","fftw3-dev"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+  allow_failures:
+    - compiler: ghc-head
+before_install:
+  - HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//')
+  - WITHCOMPILER="-w $HC"
+  - HADDOCK=$(echo "/opt/$CC/bin/haddock" | sed 's/-/\//')
+  - HCPKG="$HC-pkg"
+  - unset CC
+  - CABAL=/opt/ghc/bin/cabal
+  - CABALHOME=$HOME/.cabal
+  - export PATH="$CABALHOME/bin:$PATH"
+  - TOP=$(pwd)
+  - "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')"
+  - echo $HCNUMVER
+  - CABAL="$CABAL -vnormal+nowrap"
+  - set -o pipefail
+  - TEST=--enable-tests
+  - BENCH=--enable-benchmarks
+  - HEADHACKAGE=false
+  - if [ $((HCNUMVER > 81004)) -ne 0 ] ; then HEADHACKAGE=true ; fi
+  - rm -f $CABALHOME/config
+  - |
+    echo "verbose: normal +nowrap +markoutput"          >> $CABALHOME/config
+    echo "remote-build-reporting: anonymous"            >> $CABALHOME/config
+    echo "write-ghc-environment-files: never"           >> $CABALHOME/config
+    echo "remote-repo-cache: $CABALHOME/packages"       >> $CABALHOME/config
+    echo "logs-dir:          $CABALHOME/logs"           >> $CABALHOME/config
+    echo "world-file:        $CABALHOME/world"          >> $CABALHOME/config
+    echo "extra-prog-path:   $CABALHOME/bin"            >> $CABALHOME/config
+    echo "symlink-bindir:    $CABALHOME/bin"            >> $CABALHOME/config
+    echo "installdir:        $CABALHOME/bin"            >> $CABALHOME/config
+    echo "build-summary:     $CABALHOME/logs/build.log" >> $CABALHOME/config
+    echo "store-dir:         $CABALHOME/store"          >> $CABALHOME/config
+    echo "install-dirs user"                            >> $CABALHOME/config
+    echo "  prefix: $CABALHOME"                         >> $CABALHOME/config
+    echo "repository hackage.haskell.org"               >> $CABALHOME/config
+    echo "  url: http://hackage.haskell.org/"           >> $CABALHOME/config
+  - |
+    if $HEADHACKAGE; then
+    echo "repository head.hackage.ghc.haskell.org"                                        >> $CABALHOME/config
+    echo "   url: https://ghc.gitlab.haskell.org/head.hackage/"                           >> $CABALHOME/config
+    echo "   secure: True"                                                                >> $CABALHOME/config
+    echo "   root-keys: 7541f32a4ccca4f97aea3b22f5e593ba2c0267546016b992dfadcd2fe944e55d" >> $CABALHOME/config
+    echo "              26021a13b401500c8eb2761ca95c61f2d625bfef951b939a8124ed12ecf07329" >> $CABALHOME/config
+    echo "              f76d08be13e9a61a377a85e2fb63f4c5435d40f8feb3e12eb05905edb8cdea89" >> $CABALHOME/config
+    echo "   key-threshold: 3"                                                            >> $CABALHOME/config
+    fi
+install:
+  - ${CABAL} --version
+  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
+  - |
+    echo "program-default-options"                >> $CABALHOME/config
+    echo "  ghc-options: $GHCJOBS +RTS -M6G -RTS" >> $CABALHOME/config
+  - cat $CABALHOME/config
+  - rm -fv cabal.project cabal.project.local cabal.project.freeze
+  - travis_retry ${CABAL} v2-update -v
+  # Generate cabal.project
+  - rm -rf cabal.project cabal.project.local cabal.project.freeze
+  - touch cabal.project
+  - |
+    echo "packages: servant" >> cabal.project
+    echo "packages: servant-client" >> cabal.project
+    echo "packages: servant-docs" >> cabal.project
+    echo "packages: servant-server" >> cabal.project
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-client' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-docs' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-server' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - |
+  - |
+    if $HEADHACKAGE; then
+    echo "allow-newer: $($HCPKG list --simple-output | sed -E 's/([a-zA-Z-]+)-[0-9.]+/*:\1,/g')" >> $CABALHOME/config
+    fi
+  - "for pkg in deepseq; do echo \"constraints: $pkg installed\" >> cabal.project.local; done"
+  - cat cabal.project || true
+  - cat cabal.project.local || true
+  - if [ -f "servant/configure.ac" ]; then (cd "servant" && autoreconf -i); fi
+  - if [ -f "servant-client/configure.ac" ]; then (cd "servant-client" && autoreconf -i); fi
+  - if [ -f "servant-docs/configure.ac" ]; then (cd "servant-docs" && autoreconf -i); fi
+  - if [ -f "servant-server/configure.ac" ]; then (cd "servant-server" && autoreconf -i); fi
+  - ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH}
+  - "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
+  - rm  cabal.project.freeze
+  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} --dep -j2 all
+  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --dep -j2 all
+script:
+  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
+  # Packaging...
+  - ${CABAL} v2-sdist all
+  # Unpacking...
+  - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
+  - cd ${DISTDIR} || false
+  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \;
+  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm       '{}' \;
+  - PKGDIR_servant="$(find . -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+  - PKGDIR_servant_client="$(find . -maxdepth 1 -type d -regex '.*/servant-client-[0-9.]*')"
+  - PKGDIR_servant_docs="$(find . -maxdepth 1 -type d -regex '.*/servant-docs-[0-9.]*')"
+  - PKGDIR_servant_server="$(find . -maxdepth 1 -type d -regex '.*/servant-server-[0-9.]*')"
+  # Generate cabal.project
+  - rm -rf cabal.project cabal.project.local cabal.project.freeze
+  - touch cabal.project
+  - |
+    echo "packages: ${PKGDIR_servant}" >> cabal.project
+    echo "packages: ${PKGDIR_servant_client}" >> cabal.project
+    echo "packages: ${PKGDIR_servant_docs}" >> cabal.project
+    echo "packages: ${PKGDIR_servant_server}" >> cabal.project
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-client' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-docs' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant-server' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - |
+  - |
+    if $HEADHACKAGE; then
+    echo "allow-newer: $($HCPKG list --simple-output | sed -E 's/([a-zA-Z-]+)-[0-9.]+/*:\1,/g')" >> $CABALHOME/config
+    fi
+  - "for pkg in deepseq; do echo \"constraints: $pkg installed\" >> cabal.project.local; done"
+  - cat cabal.project || true
+  - cat cabal.project.local || true
+  # Building...
+  # this builds all libraries and executables (without tests/benchmarks)
+  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
+  # Building with tests and benchmarks...
+  # build & run tests, build benchmarks
+  - ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} all --write-ghc-environment-files=always
+  # Testing...
+  - ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all --test-show-details=direct
+  # cabal check...
+  - (cd ${PKGDIR_servant} && ${CABAL} -vnormal check)
+  - (cd ${PKGDIR_servant_client} && ${CABAL} -vnormal check)
+  - (cd ${PKGDIR_servant_docs} && ${CABAL} -vnormal check)
+  - (cd ${PKGDIR_servant_server} && ${CABAL} -vnormal check)
+  # haddock...
+  - ${CABAL} v2-haddock $WITHCOMPILER --with-haddock $HADDOCK ${TEST} ${BENCH} all
+  # Building without installed constraints for packages in global-db...
+  - rm -f cabal.project.local
+  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
+
+# REGENDATA ["--ghc-head","--apt=fftw3-dev","--installed=-all +deepseq","travis","messy.project"]
+# EOF
diff --git a/fixtures/psql.args b/fixtures/psql.args
new file mode 100644
--- /dev/null
+++ b/fixtures/psql.args
@@ -0,0 +1,1 @@
+--postgresql
diff --git a/fixtures/psql.bash b/fixtures/psql.bash
new file mode 100644
--- /dev/null
+++ b/fixtures/psql.bash
@@ -0,0 +1,520 @@
+# SUCCESS
+# *INFO* Generating Bash script for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+#!/bin/bash
+# shellcheck disable=SC2086,SC2016,SC2046
+# REGENDATA ["--postgresql","bash","psql.project"]
+
+set -o pipefail
+
+# Mode
+##############################################################################
+
+if [ "$1" = "indocker" ]; then
+    INDOCKER=true
+    shift
+else
+    INDOCKER=false
+fi
+
+# Run configuration
+##############################################################################
+
+CFG_CABAL_STORE_CACHE=""
+CFG_CABAL_REPO_CACHE=""
+CFG_JOBS="8.10.4 8.10.3 8.10.2 8.10.1 8.8.4 8.8.3 8.8.2 8.8.1 8.6.5 8.6.4 8.6.3 8.6.2 8.6.1 8.4.4 8.4.3 8.4.2 8.4.1 8.2.2 8.2.1 8.0.2 8.0.1 7.10.3 7.10.2 7.10.1 7.8.4 7.8.3 7.8.2 7.8.1"
+CFG_CABAL_UPDATE=false
+
+SCRIPT_NAME=$(basename "$0")
+START_TIME="$(date +'%s')"
+
+XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config}
+
+# Job configuration
+##############################################################################
+
+GHC_VERSION="non-existing"
+CABAL_VERSION=3.2
+HEADHACKAGE=false
+
+# Locale
+##############################################################################
+
+export LC_ALL=C.UTF-8
+
+# Utilities
+##############################################################################
+
+SGR_RED='\033[1;31m'
+SGR_GREEN='\033[1;32m'
+SGR_BLUE='\033[1;34m'
+SGR_CYAN='\033[1;96m'
+SGR_RESET='\033[0m' # No Color
+
+put_info() {
+    printf "$SGR_CYAN%s$SGR_RESET\n" "### $*"
+}
+
+put_error() {
+    printf "$SGR_RED%s$SGR_RESET\n" "!!! $*"
+}
+
+run_cmd() {
+    local PRETTYCMD="$*"
+    local PROMPT
+    if $INDOCKER; then
+        PROMPT="$(pwd) >>>"
+    else
+        PROMPT=">>>"
+    fi
+
+    printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+
+    local start_time end_time cmd_duration total_duration
+    start_time=$(date +'%s')
+
+    "$@"
+    local RET=$?
+
+    end_time=$(date +'%s')
+    cmd_duration=$((end_time - start_time))
+    total_duration=$((end_time - START_TIME))
+
+    cmd_min=$((cmd_duration / 60))
+    cmd_sec=$((cmd_duration % 60))
+
+    total_min=$((total_duration / 60))
+    total_sec=$((total_duration % 60))
+
+    if [ $RET -eq 0 ]; then
+        printf "$SGR_GREEN%s$SGR_RESET (%dm%02ds; %dm%02ds)\n" "<<< $PRETTYCMD" "$cmd_min" "$cmd_sec" "$total_min" "$total_sec"
+    else
+        printf "$SGR_RED%s$SGR_RESET\n" "!!! $PRETTYCMD"
+        exit 1
+    fi
+}
+
+run_cmd_if() {
+    local COND=$1
+    shift
+
+    if [ $COND -eq 1 ]; then
+        run_cmd "$@"
+    else
+        local PRETTYCMD="$*"
+        local PROMPT
+        PROMPT="$(pwd) (skipping) >>>"
+
+        printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+    fi
+}
+
+run_cmd_unchecked() {
+    local PRETTYCMD="$*"
+    local PROMPT
+    if $INDOCKER; then
+        PROMPT="$(pwd) >>>"
+    else
+        PROMPT=">>>"
+    fi
+
+    printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+
+    local start_time end_time cmd_duration total_duration cmd_min cmd_sec total_min total_sec
+    start_time=$(date +'%s')
+
+    "$@"
+
+    end_time=$(date +'%s')
+    cmd_duration=$((end_time - start_time))
+    total_duration=$((end_time - START_TIME))
+
+    cmd_min=$((cmd_duration / 60))
+    cmd_sec=$((cmd_duration % 60))
+
+    total_min=$((total_duration / 60))
+    total_sec=$((total_duration % 60))
+
+    printf "$SGR_GREEN%s$SGR_RESET (%dm%02ds; %dm%02ds)\n" "<<< $PRETTYCMD" "$cmd_min" "$cmd_sec" "$total_min" "$total_sec"
+}
+
+change_dir() {
+    local DIR=$1
+    if [ -d "$DIR" ]; then
+        printf "$SGR_BLUE%s$SGR_RESET\n" "change directory to $DIR"
+        cd "$DIR" || exit 1
+    else
+        printf "$SGR_RED%s$SGR_RESET\n" "!!! cd $DIR"
+        exit 1
+    fi
+}
+
+change_dir_if() {
+    local COND=$1
+    local DIR=$2
+
+    if [ $COND -ne 0 ]; then
+        change_dir "$DIR"
+    fi
+}
+
+echo_to() {
+    local DEST=$1
+    local CONTENTS=$2
+
+    echo "$CONTENTS" >> "$DEST"
+}
+
+echo_if_to() {
+    local COND=$1
+    local DEST=$2
+    local CONTENTS=$3
+
+    if [ $COND -ne 0 ]; then
+        echo_to "$DEST" "$CONTENTS"
+    fi
+}
+
+install_cabalplan() {
+    put_info "installing cabal-plan"
+
+    if [ ! -e $CABAL_REPOCACHE/downloads/cabal-plan ]; then
+        curl -L https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > /tmp/cabal-plan.xz || exit 1
+        (cd /tmp && echo "de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc  cabal-plan.xz" | sha256sum -c -)|| exit 1
+        mkdir -p $CABAL_REPOCACHE/downloads
+        xz -d < /tmp/cabal-plan.xz > $CABAL_REPOCACHE/downloads/cabal-plan || exit 1
+        chmod a+x $CABAL_REPOCACHE/downloads/cabal-plan || exit 1
+    fi
+
+    mkdir -p $CABAL_DIR/bin || exit 1
+    ln -s $CABAL_REPOCACHE/downloads/cabal-plan $CABAL_DIR/bin/cabal-plan || exit 1
+}
+
+# Help
+##############################################################################
+
+show_usage() {
+cat <<EOF
+./haskell-ci.sh - build & test
+
+Usage: ./haskell-ci.sh [options]
+  A script to run automated checks locally (using Docker)
+
+Available options:
+  --jobs JOBS               Jobs to run (default: $CFG_JOBS)
+  --cabal-store-cache PATH  Directory to use for cabal-store-cache
+  --cabal-repo-cache PATH   Directory to use for cabal-repo-cache
+  --skip-cabal-update       Skip cabal update (useful with --cabal-repo-cache)
+  --no-skip-cabal-update
+  --help                    Print this message
+
+EOF
+}
+
+# getopt
+#######################################################################
+
+process_cli_options() {
+    while [ $# -gt 0 ]; do
+        arg=$1
+        case $arg in
+            --help)
+                show_usage
+                exit
+                ;;
+            --jobs)
+                CFG_JOBS=$2
+                shift
+                shift
+                ;;
+            --cabal-store-cache)
+                CFG_CABAL_STORE_CACHE=$2
+                shift
+                shift
+                ;;
+            --cabal-repo-cache)
+                CFG_CABAL_REPO_CACHE=$2
+                shift
+                shift
+                ;;
+            --skip-cabal-update)
+                CFG_CABAL_UPDATE=false
+                shift
+                ;;
+            --no-skip-cabal-update)
+                CFG_CABAL_UPDATE=true
+                shift
+                ;;
+            *)
+                echo "Unknown option $arg"
+                exit 1
+        esac
+    done
+}
+
+process_indocker_options () {
+    while [ $# -gt 0 ]; do
+        arg=$1
+
+        case $arg in
+            --ghc-version)
+                GHC_VERSION=$2
+                shift
+                shift
+                ;;
+            --cabal-version)
+                CABAL_VERSION=$2
+                shift
+                shift
+                ;;
+            --start-time)
+                START_TIME=$2
+                shift
+                shift
+                ;;
+            --cabal-update)
+                CABAL_UPDATE=$2
+                shift
+                shift
+                ;;
+            *)
+                echo "Unknown option $arg"
+                exit 1
+        esac
+    done
+}
+
+if $INDOCKER; then
+    process_indocker_options "$@"
+
+else
+    if [ -f "$XDG_CONFIG_HOME/haskell-ci/bash.config" ]; then
+        process_cli_options $(cat "$XDG_CONFIG_HOME/haskell-ci/bash.config")
+    fi
+
+    process_cli_options "$@"
+
+    put_info "jobs:              $CFG_JOBS"
+    put_info "cabal-store-cache: $CFG_CABAL_STORE_CACHE"
+    put_info "cabal-repo-cache:  $CFG_CABAL_REPO_CACHE"
+    put_info "cabal-update:      $CFG_CABAL_UPDATE"
+fi
+
+# Constants
+##############################################################################
+
+SRCDIR=/hsci/src
+BUILDDIR=/hsci/build
+CABAL_DIR="$BUILDDIR/cabal"
+CABAL_REPOCACHE=/hsci/cabal-repocache
+CABAL_STOREDIR=/hsci/store
+
+# Docker invoke
+##############################################################################
+
+# if cache directory is specified, use it.
+# Otherwise use another tmpfs host
+if [ -z "$CFG_CABAL_STORE_CACHE" ]; then
+    CABALSTOREARG="--tmpfs $CABAL_STOREDIR:exec"
+else
+    CABALSTOREARG="--volume $CFG_CABAL_STORE_CACHE:$CABAL_STOREDIR"
+fi
+
+if [ -z "$CFG_CABAL_REPO_CACHE" ]; then
+    CABALREPOARG="--tmpfs $CABAL_REPOCACHE:exec"
+else
+    CABALREPOARG="--volume $CFG_CABAL_REPO_CACHE:$CABAL_REPOCACHE"
+fi
+
+echo_docker_cmd() {
+    local GHCVER=$1
+
+    # TODO: mount /hsci/src:ro (readonly)
+    echo docker run \
+        --tty \
+        --interactive \
+        --rm \
+        --label haskell-ci \
+        --volume "$(pwd):/hsci/src" \
+        $CABALSTOREARG \
+        $CABALREPOARG \
+        --tmpfs /tmp:exec \
+        --tmpfs /hsci/build:exec \
+        --workdir /hsci/build \
+        "phadej/ghc:$GHCVER-bionic" \
+        "/bin/bash" "/hsci/src/$SCRIPT_NAME" indocker \
+        --ghc-version "$GHCVER" \
+        --cabal-update "$CFG_CABAL_UPDATE" \
+        --start-time "$START_TIME"
+}
+
+# if we are not in docker, loop through jobs
+if ! $INDOCKER; then
+    for JOB in $CFG_JOBS; do
+        put_info "Running in docker: $JOB"
+        run_cmd $(echo_docker_cmd "$JOB")
+    done
+
+    run_cmd echo "ALL OK"
+    exit 0
+fi
+
+# Otherwise we are in docker, and the rest of script executes
+put_info "In docker"
+
+# Environment
+##############################################################################
+
+GHCDIR=/opt/ghc/$GHC_VERSION
+
+HC=$GHCDIR/bin/ghc
+HCPKG=$GHCDIR/bin/ghc-pkg
+HADDOCK=$GHCDIR/bin/haddock
+
+CABAL=/opt/cabal/$CABAL_VERSION/bin/cabal
+
+CABAL="$CABAL -vnormal+nowrap"
+
+export CABAL_DIR
+export CABAL_CONFIG="$BUILDDIR/cabal/config"
+
+PATH="$CABAL_DIR/bin:$PATH"
+
+# HCNUMVER
+HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
+GHCJSARITH=0
+
+put_info "HCNUMVER: $HCNUMVER"
+
+# Args for shorter/nicer commands
+if [ 1 -ne 0 ] ; then ARG_TESTS=--enable-tests; else ARG_TESTS=--disable-tests; fi
+if [ 1 -ne 0 ] ; then ARG_BENCH=--enable-benchmarks; else ARG_BENCH=--disable-benchmarks; fi
+ARG_COMPILER="--ghc --with-compiler=$HC"
+
+put_info "tests/benchmarks: $ARG_TESTS $ARG_BENCH"
+
+# Apt dependencies
+##############################################################################
+
+
+# Cabal config
+##############################################################################
+
+mkdir -p $BUILDDIR/cabal
+
+cat > $BUILDDIR/cabal/config <<EOF
+remote-build-reporting: anonymous
+write-ghc-environment-files: always
+remote-repo-cache: $CABAL_REPOCACHE
+logs-dir:          $CABAL_DIR/logs
+world-file:        $CABAL_DIR/world
+extra-prog-path:   $CABAL_DIR/bin
+symlink-bindir:    $CABAL_DIR/bin
+installdir:        $CABAL_DIR/bin
+build-summary:     $CABAL_DIR/logs/build.log
+store-dir:         $CABAL_STOREDIR
+install-dirs user
+  prefix: $CABAL_DIR
+repository hackage.haskell.org
+  url: http://hackage.haskell.org/
+EOF
+
+if $HEADHACKAGE; then
+    put_error "head.hackage is not implemented"
+    exit 1
+fi
+
+run_cmd cat "$BUILDDIR/cabal/config"
+
+# Version
+##############################################################################
+
+put_info "Versions"
+run_cmd $HC --version
+run_cmd_unchecked $HC --print-project-git-commit-id
+run_cmd $CABAL --version
+
+# Build script
+##############################################################################
+
+# update cabal index
+if $CABAL_UPDATE; then
+    put_info "Updating Hackage index"
+    run_cmd $CABAL v2-update -v
+fi
+
+# install cabal-plan
+install_cabalplan
+run_cmd cabal-plan --version
+
+# initial cabal.project for sdist
+put_info "initial cabal.project for sdist"
+change_dir "$BUILDDIR"
+run_cmd touch cabal.project
+echo_to cabal.project "packages: $SRCDIR/servant"
+run_cmd cat cabal.project
+
+# sdist
+put_info "sdist"
+run_cmd mkdir -p "$BUILDDIR/sdist"
+run_cmd $CABAL sdist all --output-dir "$BUILDDIR/sdist"
+
+# unpack
+put_info "unpack"
+change_dir "$BUILDDIR"
+run_cmd mkdir -p "$BUILDDIR/unpacked"
+run_cmd find "$BUILDDIR/sdist" -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C "$BUILDDIR/unpacked" -xzvf {} \;
+
+# generate cabal.project
+put_info "generate cabal.project"
+PKGDIR_servant="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+run_cmd touch cabal.project
+run_cmd touch cabal.project.local
+echo_to cabal.project "packages: ${PKGDIR_servant}"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+cat >> cabal.project <<EOF
+EOF
+$HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(servant)$/; }' >> cabal.project.local
+run_cmd cat cabal.project
+run_cmd cat cabal.project.local
+
+# dump install plan
+put_info "dump install plan"
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
+run_cmd cabal-plan
+
+# install dependencies
+put_info "install dependencies"
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j all
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j all
+
+# build w/o tests
+put_info "build w/o tests"
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+
+# build
+put_info "build"
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all
+
+# tests
+put_info "tests"
+run_cmd $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
+
+# cabal check
+put_info "cabal check"
+change_dir "${PKGDIR_servant}"
+run_cmd ${CABAL} -vnormal check
+change_dir "$BUILDDIR"
+
+# haddock
+put_info "haddock"
+run_cmd $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
+
+# unconstrained build
+put_info "unconstrained build"
+run_cmd rm -f cabal.project.local
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+
+
+# Done
+run_cmd echo OK
diff --git a/fixtures/psql.github b/fixtures/psql.github
new file mode 100644
--- /dev/null
+++ b/fixtures/psql.github
@@ -0,0 +1,228 @@
+# SUCCESS
+# *INFO* Generating GitHub config for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+# This GitHub workflow config has been generated by a script via
+#
+#   haskell-ci '--postgresql' 'github' 'psql.project'
+#
+# To regenerate the script (for example after adjusting tested-with) run
+#
+#   haskell-ci regenerate
+#
+# For more information, see https://github.com/haskell-CI/haskell-ci
+#
+# REGENDATA ["--postgresql","github","psql.project"]
+#
+name: Haskell-CI
+on:
+  - push
+  - pull_request
+jobs:
+  linux:
+    name: Haskell-CI - Linux - ${{ matrix.compiler }}
+    runs-on: ubuntu-18.04
+    container:
+      image: buildpack-deps:bionic
+    services:
+      postgres:
+        image: postgres:10
+        env:
+          POSTGRES_PASSWORD: postgres
+        options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
+    continue-on-error: ${{ matrix.allow-failure }}
+    strategy:
+      matrix:
+        include:
+          - compiler: ghc-8.10.4
+            allow-failure: false
+          - compiler: ghc-8.10.3
+            allow-failure: false
+          - compiler: ghc-8.10.2
+            allow-failure: false
+          - compiler: ghc-8.10.1
+            allow-failure: false
+          - compiler: ghc-8.8.4
+            allow-failure: false
+          - compiler: ghc-8.8.3
+            allow-failure: false
+          - compiler: ghc-8.8.2
+            allow-failure: false
+          - compiler: ghc-8.8.1
+            allow-failure: false
+          - compiler: ghc-8.6.5
+            allow-failure: false
+          - compiler: ghc-8.6.4
+            allow-failure: false
+          - compiler: ghc-8.6.3
+            allow-failure: false
+          - compiler: ghc-8.6.2
+            allow-failure: false
+          - compiler: ghc-8.6.1
+            allow-failure: false
+          - compiler: ghc-8.4.4
+            allow-failure: false
+          - compiler: ghc-8.4.3
+            allow-failure: false
+          - compiler: ghc-8.4.2
+            allow-failure: false
+          - compiler: ghc-8.4.1
+            allow-failure: false
+          - compiler: ghc-8.2.2
+            allow-failure: false
+          - compiler: ghc-8.2.1
+            allow-failure: false
+          - compiler: ghc-8.0.2
+            allow-failure: false
+          - compiler: ghc-8.0.1
+            allow-failure: false
+          - compiler: ghc-7.10.3
+            allow-failure: false
+          - compiler: ghc-7.10.2
+            allow-failure: false
+          - compiler: ghc-7.10.1
+            allow-failure: false
+          - compiler: ghc-7.8.4
+            allow-failure: false
+          - compiler: ghc-7.8.3
+            allow-failure: false
+          - compiler: ghc-7.8.2
+            allow-failure: false
+          - compiler: ghc-7.8.1
+            allow-failure: false
+      fail-fast: false
+    steps:
+      - name: apt
+        run: |
+          apt-get update
+          apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common
+          apt-add-repository -y 'ppa:hvr/ghc'
+          apt-get update
+          apt-get install -y $CC cabal-install-3.4
+        env:
+          CC: ${{ matrix.compiler }}
+      - name: Set PATH and environment variables
+        run: |
+          echo "$HOME/.cabal/bin" >> $GITHUB_PATH
+          echo "LANG=C.UTF-8" >> $GITHUB_ENV
+          echo "CABAL_DIR=$HOME/.cabal" >> $GITHUB_ENV
+          echo "CABAL_CONFIG=$HOME/.cabal/config" >> $GITHUB_ENV
+          HCDIR=$(echo "/opt/$CC" | sed 's/-/\//')
+          HCNAME=ghc
+          HC=$HCDIR/bin/$HCNAME
+          echo "HC=$HC" >> $GITHUB_ENV
+          echo "HCPKG=$HCDIR/bin/$HCNAME-pkg" >> $GITHUB_ENV
+          echo "HADDOCK=$HCDIR/bin/haddock" >> $GITHUB_ENV
+          echo "CABAL=/opt/cabal/3.4/bin/cabal -vnormal+nowrap" >> $GITHUB_ENV
+          HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
+          echo "HCNUMVER=$HCNUMVER" >> $GITHUB_ENV
+          echo "ARG_TESTS=--enable-tests" >> $GITHUB_ENV
+          echo "ARG_BENCH=--enable-benchmarks" >> $GITHUB_ENV
+          echo "HEADHACKAGE=false" >> $GITHUB_ENV
+          echo "ARG_COMPILER=--$HCNAME --with-compiler=$HC" >> $GITHUB_ENV
+          echo "GHCJSARITH=0" >> $GITHUB_ENV
+        env:
+          CC: ${{ matrix.compiler }}
+      - name: env
+        run: |
+          env
+      - name: write cabal config
+        run: |
+          mkdir -p $CABAL_DIR
+          cat >> $CABAL_CONFIG <<EOF
+          remote-build-reporting: anonymous
+          write-ghc-environment-files: never
+          remote-repo-cache: $CABAL_DIR/packages
+          logs-dir:          $CABAL_DIR/logs
+          world-file:        $CABAL_DIR/world
+          extra-prog-path:   $CABAL_DIR/bin
+          symlink-bindir:    $CABAL_DIR/bin
+          installdir:        $CABAL_DIR/bin
+          build-summary:     $CABAL_DIR/logs/build.log
+          store-dir:         $CABAL_DIR/store
+          install-dirs user
+            prefix: $CABAL_DIR
+          repository hackage.haskell.org
+            url: http://hackage.haskell.org/
+          EOF
+          cat $CABAL_CONFIG
+      - name: versions
+        run: |
+          $HC --version || true
+          $HC --print-project-git-commit-id || true
+          $CABAL --version || true
+      - name: update cabal index
+        run: |
+          $CABAL v2-update -v
+      - name: install cabal-plan
+        run: |
+          mkdir -p $HOME/.cabal/bin
+          curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > cabal-plan.xz
+          echo 'de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc  cabal-plan.xz' | sha256sum -c -
+          xz -d < cabal-plan.xz > $HOME/.cabal/bin/cabal-plan
+          rm -f cabal-plan.xz
+          chmod a+x $HOME/.cabal/bin/cabal-plan
+          cabal-plan --version
+      - name: checkout
+        uses: actions/checkout@v2
+        with:
+          path: source
+      - name: initial cabal.project for sdist
+        run: |
+          touch cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant" >> cabal.project
+          cat cabal.project
+      - name: sdist
+        run: |
+          mkdir -p sdist
+          $CABAL sdist all --output-dir $GITHUB_WORKSPACE/sdist
+      - name: unpack
+        run: |
+          mkdir -p unpacked
+          find sdist -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C $GITHUB_WORKSPACE/unpacked -xzvf {} \;
+      - name: generate cabal.project
+        run: |
+          PKGDIR_servant="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+          echo "PKGDIR_servant=${PKGDIR_servant}" >> $GITHUB_ENV
+          touch cabal.project
+          touch cabal.project.local
+          echo "packages: ${PKGDIR_servant}" >> cabal.project
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          cat >> cabal.project <<EOF
+          EOF
+          $HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(servant)$/; }' >> cabal.project.local
+          cat cabal.project
+          cat cabal.project.local
+      - name: dump install plan
+        run: |
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
+          cabal-plan
+      - name: cache
+        uses: actions/cache@v2
+        with:
+          key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
+          path: ~/.cabal/store
+          restore-keys: ${{ runner.os }}-${{ matrix.compiler }}-
+      - name: install dependencies
+        run: |
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j2 all
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j2 all
+      - name: build w/o tests
+        run: |
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+      - name: build
+        run: |
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --write-ghc-environment-files=always
+      - name: tests
+        run: |
+          $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
+      - name: cabal check
+        run: |
+          cd ${PKGDIR_servant} || false
+          ${CABAL} -vnormal check
+      - name: haddock
+        run: |
+          $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
+      - name: unconstrained build
+        run: |
+          rm -f cabal.project.local
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
diff --git a/fixtures/psql.project b/fixtures/psql.project
new file mode 100644
--- /dev/null
+++ b/fixtures/psql.project
@@ -0,0 +1,1 @@
+packages: servant
diff --git a/fixtures/psql.travis b/fixtures/psql.travis
new file mode 100644
--- /dev/null
+++ b/fixtures/psql.travis
@@ -0,0 +1,222 @@
+# SUCCESS
+# *INFO* Generating Travis-CI config for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+# This Travis job script has been generated by a script via
+#
+#   haskell-ci '--postgresql' 'travis' 'psql.project'
+#
+# To regenerate the script (for example after adjusting tested-with) run
+#
+#   haskell-ci regenerate
+#
+# For more information, see https://github.com/haskell-CI/haskell-ci
+#
+version: ~> 1.0
+language: c
+os: linux
+dist: xenial
+git:
+  # whether to recursively clone submodules
+  submodules: false
+services:
+  - postgresql
+addons:
+  postgresql: "10"
+cache:
+  directories:
+    - $HOME/.cabal/packages
+    - $HOME/.cabal/store
+    - $HOME/.hlint
+before_cache:
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log
+  # remove files that are regenerated by 'cabal update'
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx
+  - rm -rfv $CABALHOME/packages/head.hackage
+jobs:
+  include:
+    - compiler: ghc-8.10.4
+      addons: {"apt":{"packages":["ghc-8.10.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.3
+      addons: {"apt":{"packages":["ghc-8.10.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.2
+      addons: {"apt":{"packages":["ghc-8.10.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.1
+      addons: {"apt":{"packages":["ghc-8.10.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.4
+      addons: {"apt":{"packages":["ghc-8.8.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.3
+      addons: {"apt":{"packages":["ghc-8.8.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.2
+      addons: {"apt":{"packages":["ghc-8.8.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.1
+      addons: {"apt":{"packages":["ghc-8.8.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.5
+      addons: {"apt":{"packages":["ghc-8.6.5","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.4
+      addons: {"apt":{"packages":["ghc-8.6.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.3
+      addons: {"apt":{"packages":["ghc-8.6.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.2
+      addons: {"apt":{"packages":["ghc-8.6.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.1
+      addons: {"apt":{"packages":["ghc-8.6.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.4
+      addons: {"apt":{"packages":["ghc-8.4.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.3
+      addons: {"apt":{"packages":["ghc-8.4.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.2
+      addons: {"apt":{"packages":["ghc-8.4.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.1
+      addons: {"apt":{"packages":["ghc-8.4.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.2.2
+      addons: {"apt":{"packages":["ghc-8.2.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.2.1
+      addons: {"apt":{"packages":["ghc-8.2.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.0.2
+      addons: {"apt":{"packages":["ghc-8.0.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.0.1
+      addons: {"apt":{"packages":["ghc-8.0.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.3
+      addons: {"apt":{"packages":["ghc-7.10.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.2
+      addons: {"apt":{"packages":["ghc-7.10.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.1
+      addons: {"apt":{"packages":["ghc-7.10.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.4
+      addons: {"apt":{"packages":["ghc-7.8.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.3
+      addons: {"apt":{"packages":["ghc-7.8.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.2
+      addons: {"apt":{"packages":["ghc-7.8.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.1
+      addons: {"apt":{"packages":["ghc-7.8.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+before_install:
+  - HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//')
+  - WITHCOMPILER="-w $HC"
+  - HADDOCK=$(echo "/opt/$CC/bin/haddock" | sed 's/-/\//')
+  - HCPKG="$HC-pkg"
+  - unset CC
+  - CABAL=/opt/ghc/bin/cabal
+  - CABALHOME=$HOME/.cabal
+  - export PATH="$CABALHOME/bin:$PATH"
+  - TOP=$(pwd)
+  - "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')"
+  - echo $HCNUMVER
+  - CABAL="$CABAL -vnormal+nowrap"
+  - set -o pipefail
+  - TEST=--enable-tests
+  - BENCH=--enable-benchmarks
+  - HEADHACKAGE=false
+  - rm -f $CABALHOME/config
+  - |
+    echo "verbose: normal +nowrap +markoutput"          >> $CABALHOME/config
+    echo "remote-build-reporting: anonymous"            >> $CABALHOME/config
+    echo "write-ghc-environment-files: never"           >> $CABALHOME/config
+    echo "remote-repo-cache: $CABALHOME/packages"       >> $CABALHOME/config
+    echo "logs-dir:          $CABALHOME/logs"           >> $CABALHOME/config
+    echo "world-file:        $CABALHOME/world"          >> $CABALHOME/config
+    echo "extra-prog-path:   $CABALHOME/bin"            >> $CABALHOME/config
+    echo "symlink-bindir:    $CABALHOME/bin"            >> $CABALHOME/config
+    echo "installdir:        $CABALHOME/bin"            >> $CABALHOME/config
+    echo "build-summary:     $CABALHOME/logs/build.log" >> $CABALHOME/config
+    echo "store-dir:         $CABALHOME/store"          >> $CABALHOME/config
+    echo "install-dirs user"                            >> $CABALHOME/config
+    echo "  prefix: $CABALHOME"                         >> $CABALHOME/config
+    echo "repository hackage.haskell.org"               >> $CABALHOME/config
+    echo "  url: http://hackage.haskell.org/"           >> $CABALHOME/config
+install:
+  - ${CABAL} --version
+  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
+  - |
+    echo "program-default-options"                >> $CABALHOME/config
+    echo "  ghc-options: $GHCJOBS +RTS -M6G -RTS" >> $CABALHOME/config
+  - cat $CABALHOME/config
+  - rm -fv cabal.project cabal.project.local cabal.project.freeze
+  - travis_retry ${CABAL} v2-update -v
+  # Generate cabal.project
+  - rm -rf cabal.project cabal.project.local cabal.project.freeze
+  - touch cabal.project
+  - |
+    echo "packages: servant" >> cabal.project
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - |
+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
+  - cat cabal.project || true
+  - cat cabal.project.local || true
+  - if [ -f "servant/configure.ac" ]; then (cd "servant" && autoreconf -i); fi
+  - ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH}
+  - "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
+  - rm  cabal.project.freeze
+  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} --dep -j2 all
+  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --dep -j2 all
+script:
+  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
+  # Packaging...
+  - ${CABAL} v2-sdist all
+  # Unpacking...
+  - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
+  - cd ${DISTDIR} || false
+  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \;
+  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm       '{}' \;
+  - PKGDIR_servant="$(find . -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+  # Generate cabal.project
+  - rm -rf cabal.project cabal.project.local cabal.project.freeze
+  - touch cabal.project
+  - |
+    echo "packages: ${PKGDIR_servant}" >> cabal.project
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - |
+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
+  - cat cabal.project || true
+  - cat cabal.project.local || true
+  # Building...
+  # this builds all libraries and executables (without tests/benchmarks)
+  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
+  # Building with tests and benchmarks...
+  # build & run tests, build benchmarks
+  - ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} all --write-ghc-environment-files=always
+  # Testing...
+  - ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all --test-show-details=direct
+  # cabal check...
+  - (cd ${PKGDIR_servant} && ${CABAL} -vnormal check)
+  # haddock...
+  - ${CABAL} v2-haddock $WITHCOMPILER --with-haddock $HADDOCK ${TEST} ${BENCH} all
+  # Building without installed constraints for packages in global-db...
+  - rm -f cabal.project.local
+  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
+
+# REGENDATA ["--postgresql","travis","psql.project"]
+# EOF
diff --git a/fixtures/servant-client-core/servant-client-core.cabal b/fixtures/servant-client-core/servant-client-core.cabal
--- a/fixtures/servant-client-core/servant-client-core.cabal
+++ b/fixtures/servant-client-core/servant-client-core.cabal
@@ -14,7 +14,7 @@
 copyright:           2014-2016 Zalora South East Asia Pte Ltd, 2016-2017 Servant Contributors
 category:            Web
 build-type:          Simple
-tested-with:         GHC >= 7.10
+tested-with:         GHC >= 7.10 && <9
 extra-source-files:
   include/*.h
   CHANGELOG.md
diff --git a/fixtures/servant-client/servant-client.cabal b/fixtures/servant-client/servant-client.cabal
--- a/fixtures/servant-client/servant-client.cabal
+++ b/fixtures/servant-client/servant-client.cabal
@@ -16,7 +16,7 @@
 category:            Servant, Web
 build-type:          Simple
 cabal-version:       >=1.10
-tested-with:         GHC >= 7.8
+tested-with:         GHC >= 7.8 && <9
 homepage:            http://haskell-servant.readthedocs.org/
 Bug-reports:         http://github.com/haskell-servant/servant/issues
 extra-source-files:
diff --git a/fixtures/servant-docs/servant-docs.cabal b/fixtures/servant-docs/servant-docs.cabal
--- a/fixtures/servant-docs/servant-docs.cabal
+++ b/fixtures/servant-docs/servant-docs.cabal
@@ -15,7 +15,7 @@
 category:            Servant, Web
 build-type:          Simple
 cabal-version:       >=1.10
-tested-with:         GHC >= 7.8
+tested-with:         GHC >= 7.8 && <9
 homepage:            http://haskell-servant.readthedocs.org/
 Bug-reports:         http://github.com/haskell-servant/servant/issues
 extra-source-files:
diff --git a/fixtures/servant-foreign/servant-foreign.cabal b/fixtures/servant-foreign/servant-foreign.cabal
--- a/fixtures/servant-foreign/servant-foreign.cabal
+++ b/fixtures/servant-foreign/servant-foreign.cabal
@@ -17,7 +17,7 @@
 category:            Servant, Web
 build-type:          Simple
 cabal-version:       >=1.10
-tested-with:         GHC >= 7.10
+tested-with:         GHC >= 7.10 && <9
 extra-source-files:
   include/*.h
   CHANGELOG.md
diff --git a/fixtures/servant-server/servant-server.cabal b/fixtures/servant-server/servant-server.cabal
--- a/fixtures/servant-server/servant-server.cabal
+++ b/fixtures/servant-server/servant-server.cabal
@@ -21,7 +21,7 @@
 category:            Servant, Web
 build-type:          Custom
 cabal-version:       >=1.10
-tested-with:         GHC >= 7.8
+tested-with:         GHC >= 7.8 && <9
 extra-source-files:
   include/*.h
   CHANGELOG.md
diff --git a/fixtures/servant/servant.cabal b/fixtures/servant/servant.cabal
--- a/fixtures/servant/servant.cabal
+++ b/fixtures/servant/servant.cabal
@@ -17,7 +17,7 @@
 category:            Servant, Web
 build-type:          Custom
 cabal-version:       >=1.10
-tested-with:         GHC >= 7.8
+tested-with:         GHC >= 7.8 && <9
 extra-source-files:
   include/*.h
   CHANGELOG.md
diff --git a/fixtures/splitmix/splitmix.cabal b/fixtures/splitmix/splitmix.cabal
new file mode 100644
--- /dev/null
+++ b/fixtures/splitmix/splitmix.cabal
@@ -0,0 +1,232 @@
+cabal-version:      >=1.10
+name:               splitmix
+version:            0.1.0.3
+synopsis:           Fast Splittable PRNG
+description:
+  Pure Haskell implementation of SplitMix described in
+  .
+  Guy L. Steele, Jr., Doug Lea, and Christine H. Flood. 2014.
+  Fast splittable pseudorandom number generators. In Proceedings
+  of the 2014 ACM International Conference on Object Oriented
+  Programming Systems Languages & Applications (OOPSLA '14). ACM,
+  New York, NY, USA, 453-472. DOI:
+  <https://doi.org/10.1145/2660193.2660195>
+  .
+  The paper describes a new algorithm /SplitMix/ for /splittable/
+  pseudorandom number generator that is quite fast: 9 64 bit arithmetic/logical
+  operations per 64 bits generated.
+  .
+  /SplitMix/ is tested with two standard statistical test suites (DieHarder and
+  TestU01, this implementation only using the former) and it appears to be
+  adequate for "everyday" use, such as Monte Carlo algorithms and randomized
+  data structures where speed is important.
+  .
+  In particular, it __should not be used for cryptographic or security applications__,
+  because generated sequences of pseudorandom values are too predictable
+  (the mixing functions are easily inverted, and two successive outputs
+  suffice to reconstruct the internal state).
+
+license:            BSD3
+license-file:       LICENSE
+maintainer:         Oleg Grenrus <oleg.grenrus@iki.fi>
+bug-reports:        https://github.com/haskellari/splitmix/issues
+category:           System, Random
+build-type:         Simple
+
+-- All GHC versions
+tested-with:
+    GHC >=7.0
+  , GHCJS ==8.4
+
+extra-source-files:
+  Changelog.md
+  make-hugs.sh
+  README.md
+  test-hugs.sh
+
+flag optimised-mixer
+  description: Use JavaScript for mix32
+  manual:      True
+  default:     False
+
+library
+  default-language: Haskell2010
+  ghc-options:      -Wall
+  hs-source-dirs:   src src-compat
+  exposed-modules:
+    System.Random.SplitMix
+    System.Random.SplitMix32
+
+  other-modules:
+    Data.Bits.Compat
+    System.Random.SplitMix.Init
+
+  -- dump-core
+  -- build-depends: dump-core
+  -- ghc-options: -fplugin=DumpCore -fplugin-opt DumpCore:core-html
+
+  build-depends:
+      base     >=4.3     && <4.16
+    , deepseq  >=1.3.0.0 && <1.5
+
+  if flag(optimised-mixer)
+    cpp-options: -DOPTIMISED_MIX32=1
+
+  -- We don't want to depend on time, nor unix or Win32 packages
+  -- because it's valuable that splitmix and QuickCheck doesn't
+  -- depend on about anything
+
+  if impl(ghcjs)
+    cpp-options: -DSPLITMIX_INIT_GHCJS=1
+
+  else
+    if impl(ghc)
+      cpp-options: -DSPLITMIX_INIT_C=1
+
+      if os(windows)
+        c-sources: cbits-win/init.c
+
+      else
+        c-sources: cbits-unix/init.c
+
+    else
+      cpp-options:   -DSPLITMIX_INIT_COMPAT=1
+      build-depends: time >=1.2.0.3 && <1.11
+
+source-repository head
+  type:     git
+  location: https://github.com/haskellari/splitmix.git
+
+benchmark comparison
+  type:             exitcode-stdio-1.0
+  default-language: Haskell2010
+  ghc-options:      -Wall
+  hs-source-dirs:   bench
+  main-is:          Bench.hs
+  build-depends:
+      base
+    , containers  >=0.4.2.1 && <0.7
+    , criterion   >=1.1.0.0 && <1.6
+    , random
+    , splitmix
+    , tf-random   >=0.5     && <0.6
+
+benchmark simple-sum
+  type:             exitcode-stdio-1.0
+  default-language: Haskell2010
+  ghc-options:      -Wall
+  hs-source-dirs:   bench
+  main-is:          SimpleSum.hs
+  build-depends:
+      base
+    , random
+    , splitmix
+
+benchmark range
+  type:             exitcode-stdio-1.0
+  default-language: Haskell2010
+  ghc-options:      -Wall
+  hs-source-dirs:   bench src-compat
+  main-is:          Range.hs
+  other-modules:    Data.Bits.Compat
+  build-depends:
+      base
+    , clock     >=0.8 && <0.9
+    , random
+    , splitmix
+
+test-suite examples
+  type:             exitcode-stdio-1.0
+  default-language: Haskell2010
+  ghc-options:      -Wall
+  hs-source-dirs:   tests
+  main-is:          Examples.hs
+  build-depends:
+      base
+    , HUnit     ==1.3.1.2 || >=1.6.0.0 && <1.7
+    , splitmix
+
+test-suite splitmix-tests
+  type:             exitcode-stdio-1.0
+  default-language: Haskell2010
+  ghc-options:      -Wall
+  hs-source-dirs:   tests
+  main-is:          Tests.hs
+  other-modules:
+    MiniQC
+    Uniformity
+
+  build-depends:
+      base
+    , base-compat           >=0.11.1  && <0.12
+    , containers            >=0.4.0.0 && <0.7
+    , HUnit                 ==1.3.1.2 || >=1.6.0.0 && <1.7
+    , math-functions        ==0.1.7.0 || >=0.3.3.0 && <0.4
+    , splitmix
+    , test-framework        >=0.8.2.0 && <0.9
+    , test-framework-hunit  >=0.3.0.2 && <0.4
+
+test-suite montecarlo-pi
+  type:             exitcode-stdio-1.0
+  default-language: Haskell2010
+  ghc-options:      -Wall
+  hs-source-dirs:   tests
+  main-is:          SplitMixPi.hs
+  build-depends:
+      base
+    , splitmix
+
+test-suite montecarlo-pi-32
+  type:             exitcode-stdio-1.0
+  default-language: Haskell2010
+  ghc-options:      -Wall
+  hs-source-dirs:   tests
+  main-is:          SplitMixPi32.hs
+  build-depends:
+      base
+    , splitmix
+
+test-suite splitmix-dieharder
+  default-language: Haskell2010
+  type:             exitcode-stdio-1.0
+  ghc-options:      -Wall -threaded -rtsopts
+  hs-source-dirs:   tests
+  main-is:          Dieharder.hs
+  build-depends:
+      async                  >=2.2.1    && <2.3
+    , base
+    , base-compat-batteries  >=0.10.5   && <0.12
+    , bytestring             >=0.9.1.8  && <0.11
+    , deepseq
+    , process                >=1.0.1.5  && <1.7
+    , random
+    , splitmix
+    , tf-random              >=0.5      && <0.6
+    , vector                 >=0.11.0.0 && <0.13
+
+test-suite splitmix-testu01
+  if !os(linux)
+    buildable: False
+
+  default-language: Haskell2010
+  type:             exitcode-stdio-1.0
+  ghc-options:      -Wall -threaded -rtsopts
+  hs-source-dirs:   tests
+  main-is:          TestU01.hs
+  c-sources:        tests/cbits/testu01.c
+  extra-libraries:  testu01
+  build-depends:
+      base
+    , base-compat-batteries  >=0.10.5   && <0.12
+    , splitmix
+
+test-suite initialization
+  default-language: Haskell2010
+  type:             exitcode-stdio-1.0
+  ghc-options:      -Wall -threaded -rtsopts
+  hs-source-dirs:   tests
+  main-is:          Initialization.hs
+  build-depends:
+      base
+    , HUnit     ==1.3.1.2 || >=1.6.0.0 && <1.7
+    , splitmix
diff --git a/fixtures/travis-patch.args b/fixtures/travis-patch.args
new file mode 100644
--- /dev/null
+++ b/fixtures/travis-patch.args
@@ -0,0 +1,1 @@
+--travis-patches=travis-patch.patch
diff --git a/fixtures/travis-patch.bash b/fixtures/travis-patch.bash
new file mode 100644
--- /dev/null
+++ b/fixtures/travis-patch.bash
@@ -0,0 +1,520 @@
+# SUCCESS
+# *INFO* Generating Bash script for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+#!/bin/bash
+# shellcheck disable=SC2086,SC2016,SC2046
+# REGENDATA ["--travis-patches=travis-patch.patch","bash","travis-patch.project"]
+
+set -o pipefail
+
+# Mode
+##############################################################################
+
+if [ "$1" = "indocker" ]; then
+    INDOCKER=true
+    shift
+else
+    INDOCKER=false
+fi
+
+# Run configuration
+##############################################################################
+
+CFG_CABAL_STORE_CACHE=""
+CFG_CABAL_REPO_CACHE=""
+CFG_JOBS="8.10.4 8.10.3 8.10.2 8.10.1 8.8.4 8.8.3 8.8.2 8.8.1 8.6.5 8.6.4 8.6.3 8.6.2 8.6.1 8.4.4 8.4.3 8.4.2 8.4.1 8.2.2 8.2.1 8.0.2 8.0.1 7.10.3 7.10.2 7.10.1 7.8.4 7.8.3 7.8.2 7.8.1"
+CFG_CABAL_UPDATE=false
+
+SCRIPT_NAME=$(basename "$0")
+START_TIME="$(date +'%s')"
+
+XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config}
+
+# Job configuration
+##############################################################################
+
+GHC_VERSION="non-existing"
+CABAL_VERSION=3.2
+HEADHACKAGE=false
+
+# Locale
+##############################################################################
+
+export LC_ALL=C.UTF-8
+
+# Utilities
+##############################################################################
+
+SGR_RED='\033[1;31m'
+SGR_GREEN='\033[1;32m'
+SGR_BLUE='\033[1;34m'
+SGR_CYAN='\033[1;96m'
+SGR_RESET='\033[0m' # No Color
+
+put_info() {
+    printf "$SGR_CYAN%s$SGR_RESET\n" "### $*"
+}
+
+put_error() {
+    printf "$SGR_RED%s$SGR_RESET\n" "!!! $*"
+}
+
+run_cmd() {
+    local PRETTYCMD="$*"
+    local PROMPT
+    if $INDOCKER; then
+        PROMPT="$(pwd) >>>"
+    else
+        PROMPT=">>>"
+    fi
+
+    printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+
+    local start_time end_time cmd_duration total_duration
+    start_time=$(date +'%s')
+
+    "$@"
+    local RET=$?
+
+    end_time=$(date +'%s')
+    cmd_duration=$((end_time - start_time))
+    total_duration=$((end_time - START_TIME))
+
+    cmd_min=$((cmd_duration / 60))
+    cmd_sec=$((cmd_duration % 60))
+
+    total_min=$((total_duration / 60))
+    total_sec=$((total_duration % 60))
+
+    if [ $RET -eq 0 ]; then
+        printf "$SGR_GREEN%s$SGR_RESET (%dm%02ds; %dm%02ds)\n" "<<< $PRETTYCMD" "$cmd_min" "$cmd_sec" "$total_min" "$total_sec"
+    else
+        printf "$SGR_RED%s$SGR_RESET\n" "!!! $PRETTYCMD"
+        exit 1
+    fi
+}
+
+run_cmd_if() {
+    local COND=$1
+    shift
+
+    if [ $COND -eq 1 ]; then
+        run_cmd "$@"
+    else
+        local PRETTYCMD="$*"
+        local PROMPT
+        PROMPT="$(pwd) (skipping) >>>"
+
+        printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+    fi
+}
+
+run_cmd_unchecked() {
+    local PRETTYCMD="$*"
+    local PROMPT
+    if $INDOCKER; then
+        PROMPT="$(pwd) >>>"
+    else
+        PROMPT=">>>"
+    fi
+
+    printf "$SGR_BLUE%s %s$SGR_RESET\n" "$PROMPT" "$PRETTYCMD"
+
+    local start_time end_time cmd_duration total_duration cmd_min cmd_sec total_min total_sec
+    start_time=$(date +'%s')
+
+    "$@"
+
+    end_time=$(date +'%s')
+    cmd_duration=$((end_time - start_time))
+    total_duration=$((end_time - START_TIME))
+
+    cmd_min=$((cmd_duration / 60))
+    cmd_sec=$((cmd_duration % 60))
+
+    total_min=$((total_duration / 60))
+    total_sec=$((total_duration % 60))
+
+    printf "$SGR_GREEN%s$SGR_RESET (%dm%02ds; %dm%02ds)\n" "<<< $PRETTYCMD" "$cmd_min" "$cmd_sec" "$total_min" "$total_sec"
+}
+
+change_dir() {
+    local DIR=$1
+    if [ -d "$DIR" ]; then
+        printf "$SGR_BLUE%s$SGR_RESET\n" "change directory to $DIR"
+        cd "$DIR" || exit 1
+    else
+        printf "$SGR_RED%s$SGR_RESET\n" "!!! cd $DIR"
+        exit 1
+    fi
+}
+
+change_dir_if() {
+    local COND=$1
+    local DIR=$2
+
+    if [ $COND -ne 0 ]; then
+        change_dir "$DIR"
+    fi
+}
+
+echo_to() {
+    local DEST=$1
+    local CONTENTS=$2
+
+    echo "$CONTENTS" >> "$DEST"
+}
+
+echo_if_to() {
+    local COND=$1
+    local DEST=$2
+    local CONTENTS=$3
+
+    if [ $COND -ne 0 ]; then
+        echo_to "$DEST" "$CONTENTS"
+    fi
+}
+
+install_cabalplan() {
+    put_info "installing cabal-plan"
+
+    if [ ! -e $CABAL_REPOCACHE/downloads/cabal-plan ]; then
+        curl -L https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > /tmp/cabal-plan.xz || exit 1
+        (cd /tmp && echo "de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc  cabal-plan.xz" | sha256sum -c -)|| exit 1
+        mkdir -p $CABAL_REPOCACHE/downloads
+        xz -d < /tmp/cabal-plan.xz > $CABAL_REPOCACHE/downloads/cabal-plan || exit 1
+        chmod a+x $CABAL_REPOCACHE/downloads/cabal-plan || exit 1
+    fi
+
+    mkdir -p $CABAL_DIR/bin || exit 1
+    ln -s $CABAL_REPOCACHE/downloads/cabal-plan $CABAL_DIR/bin/cabal-plan || exit 1
+}
+
+# Help
+##############################################################################
+
+show_usage() {
+cat <<EOF
+./haskell-ci.sh - build & test
+
+Usage: ./haskell-ci.sh [options]
+  A script to run automated checks locally (using Docker)
+
+Available options:
+  --jobs JOBS               Jobs to run (default: $CFG_JOBS)
+  --cabal-store-cache PATH  Directory to use for cabal-store-cache
+  --cabal-repo-cache PATH   Directory to use for cabal-repo-cache
+  --skip-cabal-update       Skip cabal update (useful with --cabal-repo-cache)
+  --no-skip-cabal-update
+  --help                    Print this message
+
+EOF
+}
+
+# getopt
+#######################################################################
+
+process_cli_options() {
+    while [ $# -gt 0 ]; do
+        arg=$1
+        case $arg in
+            --help)
+                show_usage
+                exit
+                ;;
+            --jobs)
+                CFG_JOBS=$2
+                shift
+                shift
+                ;;
+            --cabal-store-cache)
+                CFG_CABAL_STORE_CACHE=$2
+                shift
+                shift
+                ;;
+            --cabal-repo-cache)
+                CFG_CABAL_REPO_CACHE=$2
+                shift
+                shift
+                ;;
+            --skip-cabal-update)
+                CFG_CABAL_UPDATE=false
+                shift
+                ;;
+            --no-skip-cabal-update)
+                CFG_CABAL_UPDATE=true
+                shift
+                ;;
+            *)
+                echo "Unknown option $arg"
+                exit 1
+        esac
+    done
+}
+
+process_indocker_options () {
+    while [ $# -gt 0 ]; do
+        arg=$1
+
+        case $arg in
+            --ghc-version)
+                GHC_VERSION=$2
+                shift
+                shift
+                ;;
+            --cabal-version)
+                CABAL_VERSION=$2
+                shift
+                shift
+                ;;
+            --start-time)
+                START_TIME=$2
+                shift
+                shift
+                ;;
+            --cabal-update)
+                CABAL_UPDATE=$2
+                shift
+                shift
+                ;;
+            *)
+                echo "Unknown option $arg"
+                exit 1
+        esac
+    done
+}
+
+if $INDOCKER; then
+    process_indocker_options "$@"
+
+else
+    if [ -f "$XDG_CONFIG_HOME/haskell-ci/bash.config" ]; then
+        process_cli_options $(cat "$XDG_CONFIG_HOME/haskell-ci/bash.config")
+    fi
+
+    process_cli_options "$@"
+
+    put_info "jobs:              $CFG_JOBS"
+    put_info "cabal-store-cache: $CFG_CABAL_STORE_CACHE"
+    put_info "cabal-repo-cache:  $CFG_CABAL_REPO_CACHE"
+    put_info "cabal-update:      $CFG_CABAL_UPDATE"
+fi
+
+# Constants
+##############################################################################
+
+SRCDIR=/hsci/src
+BUILDDIR=/hsci/build
+CABAL_DIR="$BUILDDIR/cabal"
+CABAL_REPOCACHE=/hsci/cabal-repocache
+CABAL_STOREDIR=/hsci/store
+
+# Docker invoke
+##############################################################################
+
+# if cache directory is specified, use it.
+# Otherwise use another tmpfs host
+if [ -z "$CFG_CABAL_STORE_CACHE" ]; then
+    CABALSTOREARG="--tmpfs $CABAL_STOREDIR:exec"
+else
+    CABALSTOREARG="--volume $CFG_CABAL_STORE_CACHE:$CABAL_STOREDIR"
+fi
+
+if [ -z "$CFG_CABAL_REPO_CACHE" ]; then
+    CABALREPOARG="--tmpfs $CABAL_REPOCACHE:exec"
+else
+    CABALREPOARG="--volume $CFG_CABAL_REPO_CACHE:$CABAL_REPOCACHE"
+fi
+
+echo_docker_cmd() {
+    local GHCVER=$1
+
+    # TODO: mount /hsci/src:ro (readonly)
+    echo docker run \
+        --tty \
+        --interactive \
+        --rm \
+        --label haskell-ci \
+        --volume "$(pwd):/hsci/src" \
+        $CABALSTOREARG \
+        $CABALREPOARG \
+        --tmpfs /tmp:exec \
+        --tmpfs /hsci/build:exec \
+        --workdir /hsci/build \
+        "phadej/ghc:$GHCVER-bionic" \
+        "/bin/bash" "/hsci/src/$SCRIPT_NAME" indocker \
+        --ghc-version "$GHCVER" \
+        --cabal-update "$CFG_CABAL_UPDATE" \
+        --start-time "$START_TIME"
+}
+
+# if we are not in docker, loop through jobs
+if ! $INDOCKER; then
+    for JOB in $CFG_JOBS; do
+        put_info "Running in docker: $JOB"
+        run_cmd $(echo_docker_cmd "$JOB")
+    done
+
+    run_cmd echo "ALL OK"
+    exit 0
+fi
+
+# Otherwise we are in docker, and the rest of script executes
+put_info "In docker"
+
+# Environment
+##############################################################################
+
+GHCDIR=/opt/ghc/$GHC_VERSION
+
+HC=$GHCDIR/bin/ghc
+HCPKG=$GHCDIR/bin/ghc-pkg
+HADDOCK=$GHCDIR/bin/haddock
+
+CABAL=/opt/cabal/$CABAL_VERSION/bin/cabal
+
+CABAL="$CABAL -vnormal+nowrap"
+
+export CABAL_DIR
+export CABAL_CONFIG="$BUILDDIR/cabal/config"
+
+PATH="$CABAL_DIR/bin:$PATH"
+
+# HCNUMVER
+HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
+GHCJSARITH=0
+
+put_info "HCNUMVER: $HCNUMVER"
+
+# Args for shorter/nicer commands
+if [ 1 -ne 0 ] ; then ARG_TESTS=--enable-tests; else ARG_TESTS=--disable-tests; fi
+if [ 1 -ne 0 ] ; then ARG_BENCH=--enable-benchmarks; else ARG_BENCH=--disable-benchmarks; fi
+ARG_COMPILER="--ghc --with-compiler=$HC"
+
+put_info "tests/benchmarks: $ARG_TESTS $ARG_BENCH"
+
+# Apt dependencies
+##############################################################################
+
+
+# Cabal config
+##############################################################################
+
+mkdir -p $BUILDDIR/cabal
+
+cat > $BUILDDIR/cabal/config <<EOF
+remote-build-reporting: anonymous
+write-ghc-environment-files: always
+remote-repo-cache: $CABAL_REPOCACHE
+logs-dir:          $CABAL_DIR/logs
+world-file:        $CABAL_DIR/world
+extra-prog-path:   $CABAL_DIR/bin
+symlink-bindir:    $CABAL_DIR/bin
+installdir:        $CABAL_DIR/bin
+build-summary:     $CABAL_DIR/logs/build.log
+store-dir:         $CABAL_STOREDIR
+install-dirs user
+  prefix: $CABAL_DIR
+repository hackage.haskell.org
+  url: http://hackage.haskell.org/
+EOF
+
+if $HEADHACKAGE; then
+    put_error "head.hackage is not implemented"
+    exit 1
+fi
+
+run_cmd cat "$BUILDDIR/cabal/config"
+
+# Version
+##############################################################################
+
+put_info "Versions"
+run_cmd $HC --version
+run_cmd_unchecked $HC --print-project-git-commit-id
+run_cmd $CABAL --version
+
+# Build script
+##############################################################################
+
+# update cabal index
+if $CABAL_UPDATE; then
+    put_info "Updating Hackage index"
+    run_cmd $CABAL v2-update -v
+fi
+
+# install cabal-plan
+install_cabalplan
+run_cmd cabal-plan --version
+
+# initial cabal.project for sdist
+put_info "initial cabal.project for sdist"
+change_dir "$BUILDDIR"
+run_cmd touch cabal.project
+echo_to cabal.project "packages: $SRCDIR/servant"
+run_cmd cat cabal.project
+
+# sdist
+put_info "sdist"
+run_cmd mkdir -p "$BUILDDIR/sdist"
+run_cmd $CABAL sdist all --output-dir "$BUILDDIR/sdist"
+
+# unpack
+put_info "unpack"
+change_dir "$BUILDDIR"
+run_cmd mkdir -p "$BUILDDIR/unpacked"
+run_cmd find "$BUILDDIR/sdist" -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C "$BUILDDIR/unpacked" -xzvf {} \;
+
+# generate cabal.project
+put_info "generate cabal.project"
+PKGDIR_servant="$(find "$BUILDDIR/unpacked" -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+run_cmd touch cabal.project
+run_cmd touch cabal.project.local
+echo_to cabal.project "packages: ${PKGDIR_servant}"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "package servant"
+echo_if_to $((HCNUMVER >= 80200)) cabal.project "    ghc-options: -Werror=missing-methods"
+cat >> cabal.project <<EOF
+EOF
+$HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(servant)$/; }' >> cabal.project.local
+run_cmd cat cabal.project
+run_cmd cat cabal.project.local
+
+# dump install plan
+put_info "dump install plan"
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
+run_cmd cabal-plan
+
+# install dependencies
+put_info "install dependencies"
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j all
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j all
+
+# build w/o tests
+put_info "build w/o tests"
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+
+# build
+put_info "build"
+run_cmd $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all
+
+# tests
+put_info "tests"
+run_cmd $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
+
+# cabal check
+put_info "cabal check"
+change_dir "${PKGDIR_servant}"
+run_cmd ${CABAL} -vnormal check
+change_dir "$BUILDDIR"
+
+# haddock
+put_info "haddock"
+run_cmd $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
+
+# unconstrained build
+put_info "unconstrained build"
+run_cmd rm -f cabal.project.local
+run_cmd $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+
+
+# Done
+run_cmd echo OK
diff --git a/fixtures/travis-patch.github b/fixtures/travis-patch.github
new file mode 100644
--- /dev/null
+++ b/fixtures/travis-patch.github
@@ -0,0 +1,222 @@
+# SUCCESS
+# *INFO* Generating GitHub config for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+# This GitHub workflow config has been generated by a script via
+#
+#   haskell-ci '--travis-patches=travis-patch.patch' 'github' 'travis-patch.project'
+#
+# To regenerate the script (for example after adjusting tested-with) run
+#
+#   haskell-ci regenerate
+#
+# For more information, see https://github.com/haskell-CI/haskell-ci
+#
+# REGENDATA ["--travis-patches=travis-patch.patch","github","travis-patch.project"]
+#
+name: Haskell-CI
+on:
+  - push
+  - pull_request
+jobs:
+  linux:
+    name: Haskell-CI - Linux - ${{ matrix.compiler }}
+    runs-on: ubuntu-18.04
+    container:
+      image: buildpack-deps:bionic
+    continue-on-error: ${{ matrix.allow-failure }}
+    strategy:
+      matrix:
+        include:
+          - compiler: ghc-8.10.4
+            allow-failure: false
+          - compiler: ghc-8.10.3
+            allow-failure: false
+          - compiler: ghc-8.10.2
+            allow-failure: false
+          - compiler: ghc-8.10.1
+            allow-failure: false
+          - compiler: ghc-8.8.4
+            allow-failure: false
+          - compiler: ghc-8.8.3
+            allow-failure: false
+          - compiler: ghc-8.8.2
+            allow-failure: false
+          - compiler: ghc-8.8.1
+            allow-failure: false
+          - compiler: ghc-8.6.5
+            allow-failure: false
+          - compiler: ghc-8.6.4
+            allow-failure: false
+          - compiler: ghc-8.6.3
+            allow-failure: false
+          - compiler: ghc-8.6.2
+            allow-failure: false
+          - compiler: ghc-8.6.1
+            allow-failure: false
+          - compiler: ghc-8.4.4
+            allow-failure: false
+          - compiler: ghc-8.4.3
+            allow-failure: false
+          - compiler: ghc-8.4.2
+            allow-failure: false
+          - compiler: ghc-8.4.1
+            allow-failure: false
+          - compiler: ghc-8.2.2
+            allow-failure: false
+          - compiler: ghc-8.2.1
+            allow-failure: false
+          - compiler: ghc-8.0.2
+            allow-failure: false
+          - compiler: ghc-8.0.1
+            allow-failure: false
+          - compiler: ghc-7.10.3
+            allow-failure: false
+          - compiler: ghc-7.10.2
+            allow-failure: false
+          - compiler: ghc-7.10.1
+            allow-failure: false
+          - compiler: ghc-7.8.4
+            allow-failure: false
+          - compiler: ghc-7.8.3
+            allow-failure: false
+          - compiler: ghc-7.8.2
+            allow-failure: false
+          - compiler: ghc-7.8.1
+            allow-failure: false
+      fail-fast: false
+    steps:
+      - name: apt
+        run: |
+          apt-get update
+          apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common
+          apt-add-repository -y 'ppa:hvr/ghc'
+          apt-get update
+          apt-get install -y $CC cabal-install-3.4
+        env:
+          CC: ${{ matrix.compiler }}
+      - name: Set PATH and environment variables
+        run: |
+          echo "$HOME/.cabal/bin" >> $GITHUB_PATH
+          echo "LANG=C.UTF-8" >> $GITHUB_ENV
+          echo "CABAL_DIR=$HOME/.cabal" >> $GITHUB_ENV
+          echo "CABAL_CONFIG=$HOME/.cabal/config" >> $GITHUB_ENV
+          HCDIR=$(echo "/opt/$CC" | sed 's/-/\//')
+          HCNAME=ghc
+          HC=$HCDIR/bin/$HCNAME
+          echo "HC=$HC" >> $GITHUB_ENV
+          echo "HCPKG=$HCDIR/bin/$HCNAME-pkg" >> $GITHUB_ENV
+          echo "HADDOCK=$HCDIR/bin/haddock" >> $GITHUB_ENV
+          echo "CABAL=/opt/cabal/3.4/bin/cabal -vnormal+nowrap" >> $GITHUB_ENV
+          HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
+          echo "HCNUMVER=$HCNUMVER" >> $GITHUB_ENV
+          echo "ARG_TESTS=--enable-tests" >> $GITHUB_ENV
+          echo "ARG_BENCH=--enable-benchmarks" >> $GITHUB_ENV
+          echo "HEADHACKAGE=false" >> $GITHUB_ENV
+          echo "ARG_COMPILER=--$HCNAME --with-compiler=$HC" >> $GITHUB_ENV
+          echo "GHCJSARITH=0" >> $GITHUB_ENV
+        env:
+          CC: ${{ matrix.compiler }}
+      - name: env
+        run: |
+          env
+      - name: write cabal config
+        run: |
+          mkdir -p $CABAL_DIR
+          cat >> $CABAL_CONFIG <<EOF
+          remote-build-reporting: anonymous
+          write-ghc-environment-files: never
+          remote-repo-cache: $CABAL_DIR/packages
+          logs-dir:          $CABAL_DIR/logs
+          world-file:        $CABAL_DIR/world
+          extra-prog-path:   $CABAL_DIR/bin
+          symlink-bindir:    $CABAL_DIR/bin
+          installdir:        $CABAL_DIR/bin
+          build-summary:     $CABAL_DIR/logs/build.log
+          store-dir:         $CABAL_DIR/store
+          install-dirs user
+            prefix: $CABAL_DIR
+          repository hackage.haskell.org
+            url: http://hackage.haskell.org/
+          EOF
+          cat $CABAL_CONFIG
+      - name: versions
+        run: |
+          $HC --version || true
+          $HC --print-project-git-commit-id || true
+          $CABAL --version || true
+      - name: update cabal index
+        run: |
+          $CABAL v2-update -v
+      - name: install cabal-plan
+        run: |
+          mkdir -p $HOME/.cabal/bin
+          curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > cabal-plan.xz
+          echo 'de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc  cabal-plan.xz' | sha256sum -c -
+          xz -d < cabal-plan.xz > $HOME/.cabal/bin/cabal-plan
+          rm -f cabal-plan.xz
+          chmod a+x $HOME/.cabal/bin/cabal-plan
+          cabal-plan --version
+      - name: checkout
+        uses: actions/checkout@v2
+        with:
+          path: source
+      - name: initial cabal.project for sdist
+        run: |
+          touch cabal.project
+          echo "packages: $GITHUB_WORKSPACE/source/servant" >> cabal.project
+          cat cabal.project
+      - name: sdist
+        run: |
+          mkdir -p sdist
+          $CABAL sdist all --output-dir $GITHUB_WORKSPACE/sdist
+      - name: unpack
+        run: |
+          mkdir -p unpacked
+          find sdist -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C $GITHUB_WORKSPACE/unpacked -xzvf {} \;
+      - name: generate cabal.project
+        run: |
+          PKGDIR_servant="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+          echo "PKGDIR_servant=${PKGDIR_servant}" >> $GITHUB_ENV
+          touch cabal.project
+          touch cabal.project.local
+          echo "packages: ${PKGDIR_servant}" >> cabal.project
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package servant" >> cabal.project ; fi
+          if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "    ghc-options: -Werror=missing-methods" >> cabal.project ; fi
+          cat >> cabal.project <<EOF
+          EOF
+          $HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(servant)$/; }' >> cabal.project.local
+          cat cabal.project
+          cat cabal.project.local
+      - name: dump install plan
+        run: |
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
+          cabal-plan
+      - name: cache
+        uses: actions/cache@v2
+        with:
+          key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
+          path: ~/.cabal/store
+          restore-keys: ${{ runner.os }}-${{ matrix.compiler }}-
+      - name: install dependencies
+        run: |
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j2 all
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j2 all
+      - name: build w/o tests
+        run: |
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+      - name: build
+        run: |
+          $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --write-ghc-environment-files=always
+      - name: tests
+        run: |
+          $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
+      - name: cabal check
+        run: |
+          cd ${PKGDIR_servant} || false
+          ${CABAL} -vnormal check
+      - name: haddock
+        run: |
+          $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
+      - name: unconstrained build
+        run: |
+          rm -f cabal.project.local
+          $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
diff --git a/fixtures/travis-patch.patch b/fixtures/travis-patch.patch
new file mode 100644
--- /dev/null
+++ b/fixtures/travis-patch.patch
@@ -0,0 +1,13 @@
+diff --git a/fixtures/cabal.project.travis-patch.travis.yml b/fixtures/cabal.project.travis-patch.travis.yml
+index 9a725c1..0554fed 100644
+--- a/fixtures/cabal.project.travis-patch.travis.yml
++++ b/fixtures/cabal.project.travis-patch.travis.yml
+@@ -8,7 +8,7 @@
+ #
+ language: c
+ dist: xenial
+-git:
++ git:
+   # whether to recursively clone submodules
+   submodules: false
+ cache:
diff --git a/fixtures/travis-patch.project b/fixtures/travis-patch.project
new file mode 100644
--- /dev/null
+++ b/fixtures/travis-patch.project
@@ -0,0 +1,1 @@
+packages: servant
diff --git a/fixtures/travis-patch.travis b/fixtures/travis-patch.travis
new file mode 100644
--- /dev/null
+++ b/fixtures/travis-patch.travis
@@ -0,0 +1,218 @@
+# SUCCESS
+# *INFO* Generating Travis-CI config for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.8.1 8.8.2 8.8.3 8.8.4 8.10.1 8.10.2 8.10.3 8.10.4
+# This Travis job script has been generated by a script via
+#
+#   haskell-ci '--travis-patches=travis-patch.patch' 'travis' 'travis-patch.project'
+#
+# To regenerate the script (for example after adjusting tested-with) run
+#
+#   haskell-ci regenerate
+#
+# For more information, see https://github.com/haskell-CI/haskell-ci
+#
+version: ~> 1.0
+language: c
+os: linux
+dist: xenial
+ git:
+  # whether to recursively clone submodules
+  submodules: false
+cache:
+  directories:
+    - $HOME/.cabal/packages
+    - $HOME/.cabal/store
+    - $HOME/.hlint
+before_cache:
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log
+  # remove files that are regenerated by 'cabal update'
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx
+  - rm -rfv $CABALHOME/packages/head.hackage
+jobs:
+  include:
+    - compiler: ghc-8.10.4
+      addons: {"apt":{"packages":["ghc-8.10.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.3
+      addons: {"apt":{"packages":["ghc-8.10.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.2
+      addons: {"apt":{"packages":["ghc-8.10.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.10.1
+      addons: {"apt":{"packages":["ghc-8.10.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.4
+      addons: {"apt":{"packages":["ghc-8.8.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.3
+      addons: {"apt":{"packages":["ghc-8.8.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.2
+      addons: {"apt":{"packages":["ghc-8.8.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.8.1
+      addons: {"apt":{"packages":["ghc-8.8.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.5
+      addons: {"apt":{"packages":["ghc-8.6.5","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.4
+      addons: {"apt":{"packages":["ghc-8.6.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.3
+      addons: {"apt":{"packages":["ghc-8.6.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.2
+      addons: {"apt":{"packages":["ghc-8.6.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.6.1
+      addons: {"apt":{"packages":["ghc-8.6.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.4
+      addons: {"apt":{"packages":["ghc-8.4.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.3
+      addons: {"apt":{"packages":["ghc-8.4.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.2
+      addons: {"apt":{"packages":["ghc-8.4.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.4.1
+      addons: {"apt":{"packages":["ghc-8.4.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.2.2
+      addons: {"apt":{"packages":["ghc-8.2.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.2.1
+      addons: {"apt":{"packages":["ghc-8.2.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.0.2
+      addons: {"apt":{"packages":["ghc-8.0.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-8.0.1
+      addons: {"apt":{"packages":["ghc-8.0.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.3
+      addons: {"apt":{"packages":["ghc-7.10.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.2
+      addons: {"apt":{"packages":["ghc-7.10.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.10.1
+      addons: {"apt":{"packages":["ghc-7.10.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.4
+      addons: {"apt":{"packages":["ghc-7.8.4","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.3
+      addons: {"apt":{"packages":["ghc-7.8.3","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.2
+      addons: {"apt":{"packages":["ghc-7.8.2","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+    - compiler: ghc-7.8.1
+      addons: {"apt":{"packages":["ghc-7.8.1","cabal-install-3.4"],"sources":[{"key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286","sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main"}]}}
+      os: linux
+before_install:
+  - HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//')
+  - WITHCOMPILER="-w $HC"
+  - HADDOCK=$(echo "/opt/$CC/bin/haddock" | sed 's/-/\//')
+  - HCPKG="$HC-pkg"
+  - unset CC
+  - CABAL=/opt/ghc/bin/cabal
+  - CABALHOME=$HOME/.cabal
+  - export PATH="$CABALHOME/bin:$PATH"
+  - TOP=$(pwd)
+  - "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')"
+  - echo $HCNUMVER
+  - CABAL="$CABAL -vnormal+nowrap"
+  - set -o pipefail
+  - TEST=--enable-tests
+  - BENCH=--enable-benchmarks
+  - HEADHACKAGE=false
+  - rm -f $CABALHOME/config
+  - |
+    echo "verbose: normal +nowrap +markoutput"          >> $CABALHOME/config
+    echo "remote-build-reporting: anonymous"            >> $CABALHOME/config
+    echo "write-ghc-environment-files: never"           >> $CABALHOME/config
+    echo "remote-repo-cache: $CABALHOME/packages"       >> $CABALHOME/config
+    echo "logs-dir:          $CABALHOME/logs"           >> $CABALHOME/config
+    echo "world-file:        $CABALHOME/world"          >> $CABALHOME/config
+    echo "extra-prog-path:   $CABALHOME/bin"            >> $CABALHOME/config
+    echo "symlink-bindir:    $CABALHOME/bin"            >> $CABALHOME/config
+    echo "installdir:        $CABALHOME/bin"            >> $CABALHOME/config
+    echo "build-summary:     $CABALHOME/logs/build.log" >> $CABALHOME/config
+    echo "store-dir:         $CABALHOME/store"          >> $CABALHOME/config
+    echo "install-dirs user"                            >> $CABALHOME/config
+    echo "  prefix: $CABALHOME"                         >> $CABALHOME/config
+    echo "repository hackage.haskell.org"               >> $CABALHOME/config
+    echo "  url: http://hackage.haskell.org/"           >> $CABALHOME/config
+install:
+  - ${CABAL} --version
+  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
+  - |
+    echo "program-default-options"                >> $CABALHOME/config
+    echo "  ghc-options: $GHCJOBS +RTS -M6G -RTS" >> $CABALHOME/config
+  - cat $CABALHOME/config
+  - rm -fv cabal.project cabal.project.local cabal.project.freeze
+  - travis_retry ${CABAL} v2-update -v
+  # Generate cabal.project
+  - rm -rf cabal.project cabal.project.local cabal.project.freeze
+  - touch cabal.project
+  - |
+    echo "packages: servant" >> cabal.project
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - |
+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
+  - cat cabal.project || true
+  - cat cabal.project.local || true
+  - if [ -f "servant/configure.ac" ]; then (cd "servant" && autoreconf -i); fi
+  - ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH}
+  - "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
+  - rm  cabal.project.freeze
+  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} --dep -j2 all
+  - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --dep -j2 all
+script:
+  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
+  # Packaging...
+  - ${CABAL} v2-sdist all
+  # Unpacking...
+  - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
+  - cd ${DISTDIR} || false
+  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \;
+  - find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm       '{}' \;
+  - PKGDIR_servant="$(find . -maxdepth 1 -type d -regex '.*/servant-[0-9.]*')"
+  # Generate cabal.project
+  - rm -rf cabal.project cabal.project.local cabal.project.freeze
+  - touch cabal.project
+  - |
+    echo "packages: ${PKGDIR_servant}" >> cabal.project
+  - if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo 'package servant' >> cabal.project ; fi
+  - "if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo '  ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
+  - |
+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
+  - cat cabal.project || true
+  - cat cabal.project.local || true
+  # Building...
+  # this builds all libraries and executables (without tests/benchmarks)
+  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
+  # Building with tests and benchmarks...
+  # build & run tests, build benchmarks
+  - ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} all --write-ghc-environment-files=always
+  # Testing...
+  - ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all --test-show-details=direct
+  # cabal check...
+  - (cd ${PKGDIR_servant} && ${CABAL} -vnormal check)
+  # haddock...
+  - ${CABAL} v2-haddock $WITHCOMPILER --with-haddock $HADDOCK ${TEST} ${BENCH} all
+  # Building without installed constraints for packages in global-db...
+  - rm -f cabal.project.local
+  - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
+
+# REGENDATA ["--travis-patches=travis-patch.patch","travis","travis-patch.project"]
+# EOF
diff --git a/haskell-ci.cabal b/haskell-ci.cabal
--- a/haskell-ci.cabal
+++ b/haskell-ci.cabal
@@ -1,9 +1,12 @@
 cabal-version:      2.2
 name:               haskell-ci
-version:            0.10.3
+version:            0.12
 synopsis:           Cabal package script generator for Travis-CI
 description:
-  Script generator (@haskell-ci@) for [Travis-CI](https://travis-ci.org/) for continuous-integration testing of Haskell Cabal packages.
+  Script generator (@haskell-ci@) for
+  [GitHub Actions](https://docs.github.com/en/actions) and
+  [Travis-CI](https://travis-ci.org/)
+  for continuous-integration testing of Haskell Cabal packages.
   .
   Included features (not limited to):
   .
@@ -12,7 +15,6 @@
   * cabal.project support (see [Nix-style local builds documentation](https://cabal.readthedocs.io/en/latest/nix-local-build-overview.html))
   * Runs tests and builds benchmarks
   * Generates Haddocks
-  * macOS (OSX) support
   * GHCJS support
   * building with specific constraints
   .
@@ -31,41 +33,23 @@
 category:           Development
 build-type:         Simple
 tested-with:
-  GHC ==8.2.2 || ==8.4.4 || ==8.6.5 || ==8.8.3 || ==8.10.1
+  GHC ==8.2.2 || ==8.4.4 || ==8.6.5 || ==8.8.4 || ==8.10.4 || ==9.0.1
 
 extra-source-files: CHANGELOG.md
-
--- find fixtures -type f | sort
 extra-source-files:
-  fixtures/cabal.project.copy-fields.all
-  fixtures/cabal.project.copy-fields.all.stderr
-  fixtures/cabal.project.copy-fields.all.travis.yml
-  fixtures/cabal.project.copy-fields.none
-  fixtures/cabal.project.copy-fields.none.stderr
-  fixtures/cabal.project.copy-fields.none.travis.yml
-  fixtures/cabal.project.copy-fields.some
-  fixtures/cabal.project.copy-fields.some.stderr
-  fixtures/cabal.project.copy-fields.some.travis.yml
-  fixtures/cabal.project.empty-line
-  fixtures/cabal.project.empty-line.stderr
-  fixtures/cabal.project.empty-line.travis.yml
-  fixtures/cabal.project.fail-versions
-  fixtures/cabal.project.fail-versions.stderr
-  fixtures/cabal.project.haskell-ci
-  fixtures/cabal.project.messy
-  fixtures/cabal.project.messy.stderr
-  fixtures/cabal.project.messy.travis.yml
-  fixtures/cabal.project.travis-patch
-  fixtures/cabal.project.travis-patch.patch
-  fixtures/cabal.project.travis-patch.stderr
-  fixtures/cabal.project.travis-patch.travis.yml
-  fixtures/doc/tutorial/tutorial.cabal
-  fixtures/servant-client-core/servant-client-core.cabal
+  fixtures/*.args
+  fixtures/*.bash
+  fixtures/*.github
+  fixtures/*.patch
+  fixtures/*.project
+  fixtures/*.travis
+  fixtures/servant/servant.cabal
   fixtures/servant-client/servant-client.cabal
+  fixtures/servant-client-core/servant-client-core.cabal
   fixtures/servant-docs/servant-docs.cabal
   fixtures/servant-foreign/servant-foreign.cabal
   fixtures/servant-server/servant-server.cabal
-  fixtures/servant/servant.cabal
+  fixtures/splitmix/splitmix.cabal
 
 source-repository head
   type:     git
@@ -78,18 +62,24 @@
 library haskell-ci-internal
   default-language:   Haskell2010
   hs-source-dirs:     src
-  ghc-options:        -Wall -Wcompat -Wnoncanonical-monad-instances
+  ghc-options:
+    -Wall -Wincomplete-uni-patterns -Wincomplete-record-updates
+    -Wcompat -Wnoncanonical-monad-instances
 
   if impl(ghc <8.8)
     ghc-options: -Wnoncanonical-monadfail-instances
 
   exposed-modules:
     HaskellCI
+    HaskellCI.Auxiliary
+    HaskellCI.Bash
+    HaskellCI.Bash.Template
     HaskellCI.Cli
     HaskellCI.Compiler
     HaskellCI.Config
     HaskellCI.Config.ConstraintSet
     HaskellCI.Config.CopyFields
+    HaskellCI.Config.Docspec
     HaskellCI.Config.Doctest
     HaskellCI.Config.Dump
     HaskellCI.Config.Folds
@@ -99,6 +89,10 @@
     HaskellCI.Config.PackageScope
     HaskellCI.Config.Ubuntu
     HaskellCI.Diagnostics
+    HaskellCI.GitConfig
+    HaskellCI.GitHub
+    HaskellCI.GitHub.Yaml
+    HaskellCI.HeadHackage
     HaskellCI.Jobs
     HaskellCI.List
     HaskellCI.MonadErr
@@ -136,9 +130,10 @@
     ViewPatterns
 
   build-depends:
-    , base          >=4.10     && <4.15
+    , base          >=4.10     && <4.16
+    , binary        ^>=0.8.5.1
     , bytestring    ^>=0.10.8.1
-    , Cabal         ^>=3.2
+    , Cabal         ^>=3.4
     , containers    ^>=0.5.7.1 || ^>=0.6.0.1
     , deepseq       ^>=1.4.2.0
     , directory     ^>=1.3.0.0
@@ -155,17 +150,24 @@
 
   -- other dependencies
   build-depends:
-    , aeson                  ^>=1.4.2.0 || ^>=1.5.0.0
-    , base-compat            ^>=0.11
-    , cabal-install-parsers  ^>=0.3
-    , exceptions             ^>=0.10.0
-    , generic-lens-lite      ^>=0.1
-    , HsYAML                 ^>=0.2.0.0
-    , lattices               ^>=2
-    , network-uri            ^>=2.6.1.0
-    , optparse-applicative   ^>=0.15
-    , temporary              ^>=1.3
-    , unordered-containers   ^>=0.2.10.0
+    , aeson                          ^>=1.4.2.0 || ^>=1.5.0.0
+    , attoparsec                     ^>=0.13.2.4
+    , base-compat                    ^>=0.11
+    , base16-bytestring              ^>=1.0.1.0
+    , cabal-install-parsers          ^>=0.4.1
+    , cryptohash-sha256              ^>=0.11.101.0
+    , exceptions                     ^>=0.10.0
+    , generic-lens-lite              ^>=0.1
+    , HsYAML                         ^>=0.2.0.0
+    , indexed-traversable            ^>=0.1.1
+    , indexed-traversable-instances  ^>=0.1
+    , ini                            ^>=0.4.1
+    , lattices                       ^>=2
+    , network-uri                    ^>=2.6.1.0
+    , optparse-applicative           ^>=0.16.1.0
+    , temporary                      ^>=1.3
+    , unordered-containers           ^>=0.2.10.0
+    , zinza                          ^>=0.2
 
   -- ShellCheck. Would need newer transformers for older GHC
   if (flag(shellcheck) && impl(ghc >=7.10 && <8.11))
@@ -191,6 +193,7 @@
     , base
     , base-compat
     , bytestring
+    , Cabal
     , directory
     , filepath
     , haskell-ci-internal
@@ -198,7 +201,7 @@
 
   -- dependencies needing explicit constraints
   build-depends:
-    , ansi-terminal  ^>=0.10
+    , ansi-terminal  >=0.10    && <0.12
     , Diff           ^>=0.4.0
-    , tasty          >=1.0     && <1.4
+    , tasty          >=1.0     && <1.5
     , tasty-golden   ^>=2.3.1.1
diff --git a/src/HaskellCI.hs b/src/HaskellCI.hs
--- a/src/HaskellCI.hs
+++ b/src/HaskellCI.hs
@@ -14,29 +14,37 @@
 module HaskellCI (
     main,
     -- * for tests
-    parseTravis,
-    travisFromConfigFile, Options (..), defaultOptions,
+    parseOptions,
+    Options (..), defaultOptions,
+    Config (..), GitConfig (..),
+    InputType (..),
+    runDiagnosticsT,
+    -- ** Variants
+    bashFromConfigFile,
+    travisFromConfigFile,
+    githubFromConfigFile,
     ) where
 
 import HaskellCI.Prelude
 
+import Control.Exception     (try)
 import Data.List             (nubBy, sort, sortBy, (\\))
-import System.Directory      (canonicalizePath, doesFileExist, makeRelativeToCurrentDirectory, setCurrentDirectory)
+import System.Directory      (createDirectoryIfMissing, doesFileExist, setCurrentDirectory)
 import System.Environment    (getArgs)
 import System.Exit           (ExitCode (..), exitFailure)
-import System.FilePath.Posix (takeDirectory, takeFileName)
-import System.IO             (hClose, hFlush, hPutStr, hPutStrLn, stderr)
+import System.FilePath.Posix (takeDirectory)
+import System.IO             (hClose, hFlush, hPutStrLn, stderr)
 import System.IO.Temp        (withSystemTempFile)
 import System.Process        (readProcessWithExitCode)
 
 import Distribution.PackageDescription (GenericPackageDescription, package, packageDescription, testedWith)
-import Distribution.Simple.Utils       (fromUTF8BS)
+import Distribution.Simple.Utils       (fromUTF8BS, toUTF8BS)
 import Distribution.Text
 import Distribution.Version
 
 import qualified Data.ByteString       as BS
-import qualified Data.Map as Map
 import qualified Data.List.NonEmpty    as NE
+import qualified Data.Map              as Map
 import qualified Data.Set              as S
 import qualified Data.Traversable      as T
 import qualified Distribution.Compiler as Compiler
@@ -45,18 +53,23 @@
 
 import Cabal.Parse
 import Cabal.Project
+import HaskellCI.Bash
 import HaskellCI.Cli
 import HaskellCI.Compiler
 import HaskellCI.Config
 import HaskellCI.Config.Dump
 import HaskellCI.Diagnostics
+import HaskellCI.GitConfig
+import HaskellCI.GitHub
 import HaskellCI.Jobs
 import HaskellCI.Package
 import HaskellCI.TestedWith
 import HaskellCI.Travis
-import HaskellCI.YamlSyntax
 import HaskellCI.VersionInfo
+import HaskellCI.YamlSyntax
 
+import qualified HaskellCI.Bash.Template as Bash
+
 -------------------------------------------------------------------------------
 -- Main
 -------------------------------------------------------------------------------
@@ -64,53 +77,31 @@
 main :: IO ()
 main = do
     argv0 <- getArgs
-    (cmd, opts) <- O.execParser cliParserInfo
+    (cmd, opts) <- O.customExecParser (O.prefs O.subparserInline) cliParserInfo
     case cmd of
         CommandListGHC -> do
             putStrLn $ "Supported GHC versions:"
             for_ groupedVersions $ \(v, vs) -> do
                 putStr $ prettyMajVersion v ++ ": "
                 putStrLn $ intercalate ", " (map display $ toList vs)
+
         CommandDumpConfig -> do
             putStr $ unlines $ runDG configGrammar
 
         CommandRegenerate -> do
-            let fp = case optOutput opts of
-                    Just (OutputFile fp') -> fp'
-                    _                     -> defaultTravisPath
-
-            -- read, and then change to the directory
-            contents <- fromUTF8BS <$> BS.readFile fp
-            absFp <- canonicalizePath fp
-            let dir = takeDirectory fp
-            setCurrentDirectory dir
-            newFp <- makeRelativeToCurrentDirectory absFp
-
-            case findArgv (lines contents) of
-                Nothing     -> do
-                    hPutStrLn stderr $ "Error: expected REGENDATA line in " ++ fp
-                    exitFailure
-                Just (mversion, argv) -> do
-                    -- warn if we regenerate using older haskell-ci
-                    for_ mversion $ \version -> for_ (simpleParsec haskellCIVerStr) $ \haskellCIVer ->
-                        when (haskellCIVer < version) $ do
-                            hPutStrLn stderr $ "Regenerating using older haskell-ci-" ++ haskellCIVerStr
-                            hPutStrLn stderr $ "File generated using haskell-ci-" ++ prettyShow version
+            regenerateBash opts
+            regenerateGitHub opts
+            regenerateTravis opts
 
-                    (f, opts') <- parseTravis argv
-                    doTravis argv f (optionsWithOutputFile newFp <> opts' <> opts)
+        CommandBash   f -> doBash argv0 f opts
+        CommandGitHub f -> doGitHub argv0 f opts
         CommandTravis f -> doTravis argv0 f opts
+
         CommandVersionInfo -> do
             putStrLn $ "haskell-ci " ++ haskellCIVerStr ++ " with dependencies"
             ifor_ dependencies $ \p v -> do
                 putStrLn $ "  " ++ p ++ "-" ++ v
   where
-    findArgv :: [String] -> Maybe (Maybe Version, [String])
-    findArgv ls = do
-        l <- findMaybe (afterInfix "REGENDATA") ls
-        first simpleParsec <$> (readMaybe l :: Maybe (String, [String]))
-            <|> (,) Nothing <$> (readMaybe l :: Maybe [String])
-
     groupedVersions :: [(Version, NonEmpty Version)]
     groupedVersions = map ((\vs -> (head vs, vs)) . NE.sortBy (flip compare))
                     . groupBy ((==) `on` ghcMajVer)
@@ -123,27 +114,31 @@
     ifor_ :: Map.Map k v -> (k -> v -> IO a) -> IO ()
     ifor_ xs f = Map.foldlWithKey' (\m k a -> m >> void (f k a)) (return ()) xs
 
+-------------------------------------------------------------------------------
+-- Travis
+-------------------------------------------------------------------------------
+
 defaultTravisPath :: FilePath
 defaultTravisPath = ".travis.yml"
 
 doTravis :: [String] -> FilePath -> Options -> IO ()
 doTravis args path opts = do
-    ls <- travisFromConfigFile args opts path
-    let contents = unlines ls
+    contents <- travisFromConfigFile args opts path
     case optOutput opts of
-        Nothing              -> writeFile defaultTravisPath contents
-        Just OutputStdout    -> putStr contents
-        Just (OutputFile fp) -> writeFile fp contents
+        Nothing              -> BS.writeFile defaultTravisPath contents
+        Just OutputStdout    -> BS.putStr contents
+        Just (OutputFile fp) -> BS.writeFile fp contents
 
 travisFromConfigFile
     :: forall m. (MonadIO m, MonadDiagnostics m, MonadMask m)
     => [String]
     -> Options
     -> FilePath
-    -> m [String]
+    -> m ByteString
 travisFromConfigFile args opts path = do
-    cabalFiles <- getCabalFiles
-    config' <- maybe (return emptyConfig) readConfigFile (optConfig opts)
+    gitconfig <- liftIO readGitConfig
+    cabalFiles <- getCabalFiles (optInputType' opts path) path
+    config' <- findConfigFile (optConfig opts)
     let config = optConfigMorphism opts config'
     pkgs <- T.mapM (configFromCabalFile config) cabalFiles
     (ghcs, prj) <- case checkVersions (cfgTestedWith config) pkgs of
@@ -154,65 +149,268 @@
     let prj' | cfgGhcHead config = over (mapped . field @"pkgJobs") (S.insert GHCHead) prj
              | otherwise         = prj
 
-    ls <- genTravisFromConfigs args config prj' ghcs
+    ls <- genTravisFromConfigs args config gitconfig prj' ghcs
     patchTravis config ls
-  where
-    isCabalProject :: Maybe FilePath
-    isCabalProject
-        | "cabal.project" `isPrefixOf` takeFileName path = Just path
-        | otherwise = Nothing
 
-    getCabalFiles :: m (Project URI Void (FilePath, GenericPackageDescription))
-    getCabalFiles
-        | isNothing isCabalProject = do
-            e <- liftIO $ readPackagesOfProject (emptyProject & field @"prjPackages" .~ [path])
-            either (putStrLnErr . renderParseError) return e
-        | otherwise = do
-            contents <- liftIO $ BS.readFile path
-            prj0 <- either (putStrLnErr . renderParseError) return $ parseProject path contents
-            prj1 <- either (putStrLnErr . renderResolveError) return =<< liftIO (resolveProject path prj0)
-            either (putStrLnErr . renderParseError) return =<< liftIO (readPackagesOfProject prj1)
-
 genTravisFromConfigs
     :: (Monad m, MonadDiagnostics m)
     => [String]
     -> Config
+    -> GitConfig
     -> Project URI Void Package
     -> Set CompilerVersion
-    -> m [String]
-genTravisFromConfigs argv config prj vs = do
+    -> m ByteString
+genTravisFromConfigs argv config _gitconfig prj vs = do
     let jobVersions = makeJobVersions config vs
     case makeTravis argv config prj jobVersions of
         Left err     -> putStrLnErr $ displayException err
         Right travis -> do
-            describeJobs (cfgTestedWith config) jobVersions (prjPackages prj)
-            return $
-                lines (prettyYaml id $ reann (travisHeader (cfgInsertVersion config) argv ++) $ toYaml travis)
-                ++
+            describeJobs "Travis-CI config" (cfgTestedWith config) jobVersions (prjPackages prj)
+            return $ toUTF8BS $
+                prettyYaml id (reann (travisHeader (cfgInsertVersion config) argv ++) $ toYaml travis)
+                ++ unlines
                 [ ""
                 , "# REGENDATA " ++ if cfgInsertVersion config then show (haskellCIVerStr, argv) else show argv
                 , "# EOF"
                 ]
 
--- | Adjust the generated Travis YAML output with patch files, if specified.
+regenerateTravis :: Options -> IO ()
+regenerateTravis opts = do
+    let fp = defaultTravisPath
+
+    -- change the directory
+    for_ (optCwd opts) setCurrentDirectory
+
+    -- read, and then change to the directory
+    withContents fp noTravisYml $ \contents -> case findRegendataArgv contents of
+        Nothing     -> do
+            hPutStrLn stderr $ "Error: expected REGENDATA line in " ++ fp
+            exitFailure
+
+        Just (mversion, argv) -> do
+            -- warn if we regenerate using older haskell-ci
+            for_ mversion $ \version -> for_ (simpleParsec haskellCIVerStr) $ \haskellCIVer ->
+                when (haskellCIVer < version) $ do
+                    hPutStrLn stderr $ "Regenerating using older haskell-ci-" ++ haskellCIVerStr
+                    hPutStrLn stderr $ "File generated using haskell-ci-" ++ prettyShow version
+
+            (f, opts') <- parseOptions argv
+            doTravis argv f ( optionsWithOutputFile fp <> opts' <> opts)
+  where
+    noTravisYml :: IO ()
+    noTravisYml = putStrLn "No .travis.yml, skipping travis regeneration"
+
+-------------------------------------------------------------------------------
+-- Bash
+-------------------------------------------------------------------------------
+
+defaultBashPath :: FilePath
+defaultBashPath = "haskell-ci.sh"
+
+doBash :: [String] -> FilePath -> Options -> IO ()
+doBash args path opts = do
+    contents <- bashFromConfigFile args opts path
+    case optOutput opts of
+        Nothing              -> BS.writeFile defaultBashPath contents
+        Just OutputStdout    -> BS.putStr contents
+        Just (OutputFile fp) -> BS.writeFile fp contents
+
+bashFromConfigFile
+    :: forall m. (MonadIO m, MonadDiagnostics m, MonadMask m)
+    => [String]
+    -> Options
+    -> FilePath
+    -> m ByteString
+bashFromConfigFile args opts path = do
+    gitconfig <- liftIO readGitConfig
+    cabalFiles <- getCabalFiles (optInputType' opts path) path
+    config' <- findConfigFile (optConfig opts)
+    let config = optConfigMorphism opts config'
+    pkgs <- T.mapM (configFromCabalFile config) cabalFiles
+    (ghcs, prj) <- case checkVersions (cfgTestedWith config) pkgs of
+        Right x     -> return x
+        Left []     -> putStrLnErr "panic: checkVersions failed without errors"
+        Left (e:es) -> putStrLnErrs (e :| es)
+
+    let prj' | cfgGhcHead config = over (mapped . field @"pkgJobs") (S.insert GHCHead) prj
+             | otherwise         = prj
+
+    genBashFromConfigs args config gitconfig prj' ghcs
+
+genBashFromConfigs
+    :: (Monad m, MonadIO m, MonadDiagnostics m)
+    => [String]
+    -> Config
+    -> GitConfig
+    -> Project URI Void Package
+    -> Set CompilerVersion
+    -> m ByteString
+genBashFromConfigs argv config _gitconfig prj vs = do
+    let jobVersions = makeJobVersions config vs
+    case makeBash argv config prj jobVersions of
+        Left err    -> putStrLnErr $ displayException err
+        Right bashZ -> do
+            describeJobs "Bash script" (cfgTestedWith config) jobVersions (prjPackages prj)
+            fmap toUTF8BS $ liftIO $ Bash.renderIO bashZ
+                { Bash.zRegendata = if cfgInsertVersion config then show (haskellCIVerStr, argv) else show argv
+                }
+
+regenerateBash :: Options -> IO ()
+regenerateBash opts = do
+    let fp = defaultBashPath
+
+    -- change the directory
+    for_ (optCwd opts) setCurrentDirectory
+
+    -- read, and then change to the directory
+    withContents fp noBashScript $ \contents -> case findRegendataArgv contents of
+        Nothing     -> do
+            hPutStrLn stderr $ "Error: expected REGENDATA line in " ++ fp
+            exitFailure
+
+        Just (mversion, argv) -> do
+            -- warn if we regenerate using older haskell-ci
+            for_ mversion $ \version -> for_ (simpleParsec haskellCIVerStr) $ \haskellCIVer ->
+                when (haskellCIVer < version) $ do
+                    hPutStrLn stderr $ "Regenerating using older haskell-ci-" ++ haskellCIVerStr
+                    hPutStrLn stderr $ "File generated using haskell-ci-" ++ prettyShow version
+
+            (f, opts') <- parseOptions argv
+            doBash argv f ( optionsWithOutputFile fp <> opts' <> opts)
+  where
+    noBashScript :: IO ()
+    noBashScript = putStrLn "No haskell-ci.sh, skipping bash regeneration"
+
+-------------------------------------------------------------------------------
+-- GitHub actions
+-------------------------------------------------------------------------------
+
+defaultGitHubPath :: FilePath
+defaultGitHubPath = ".github/workflows/haskell-ci.yml"
+
+doGitHub :: [String] -> FilePath -> Options -> IO ()
+doGitHub args path opts = do
+    contents <- githubFromConfigFile args opts path
+    case optOutput opts of
+        Nothing              -> do
+            createDir defaultGitHubPath
+            BS.writeFile defaultGitHubPath contents
+        Just OutputStdout    -> BS.putStr contents
+        Just (OutputFile fp) -> do
+            createDir fp
+            BS.writeFile fp contents
+  where
+    createDir p = createDirectoryIfMissing True (takeDirectory p)
+
+githubFromConfigFile
+    :: forall m. (MonadIO m, MonadDiagnostics m, MonadMask m)
+    => [String]
+    -> Options
+    -> FilePath
+    -> m ByteString
+githubFromConfigFile args opts path = do
+    gitconfig <- liftIO readGitConfig
+    cabalFiles <- getCabalFiles (optInputType' opts path) path
+    config' <- findConfigFile (optConfig opts)
+    let config = optConfigMorphism opts config'
+    pkgs <- T.mapM (configFromCabalFile config) cabalFiles
+    (ghcs, prj) <- case checkVersions (cfgTestedWith config) pkgs of
+        Right x     -> return x
+        Left []     -> putStrLnErr "panic: checkVersions failed without errors"
+        Left (e:es) -> putStrLnErrs (e :| es)
+
+    let prj' | cfgGhcHead config = over (mapped . field @"pkgJobs") (S.insert GHCHead) prj
+             | otherwise         = prj
+
+    ls <- genGitHubFromConfigs args config gitconfig prj' ghcs
+    patchGitHub config ls
+
+genGitHubFromConfigs
+    :: (Monad m, MonadIO m, MonadDiagnostics m)
+    => [String]
+    -> Config
+    -> GitConfig
+    -> Project URI Void Package
+    -> Set CompilerVersion
+    -> m ByteString
+genGitHubFromConfigs argv config gitconfig prj vs = do
+    let jobVersions = makeJobVersions config vs
+    case makeGitHub argv config gitconfig prj jobVersions of
+        Left err     -> putStrLnErr $ displayException err
+        Right github -> do
+            describeJobs "GitHub config" (cfgTestedWith config) jobVersions (prjPackages prj)
+            return $ toUTF8BS $ prettyYaml id $ reann (githubHeader (cfgInsertVersion config) argv ++) $ toYaml github
+
+regenerateGitHub :: Options -> IO ()
+regenerateGitHub opts = do
+    -- change the directory
+    for_ (optCwd opts) setCurrentDirectory
+
+    -- read, and then change to the directory
+    withContents fp noGitHubScript $ \contents -> case findRegendataArgv contents of
+        Nothing     -> do
+            hPutStrLn stderr $ "Error: expected REGENDATA line in " ++ fp
+            exitFailure
+
+        Just (mversion, argv) -> do
+            -- warn if we regenerate using older haskell-ci
+            for_ mversion $ \version -> for_ (simpleParsec haskellCIVerStr) $ \haskellCIVer ->
+                when (haskellCIVer < version) $ do
+                    hPutStrLn stderr $ "Regenerating using older haskell-ci-" ++ haskellCIVerStr
+                    hPutStrLn stderr $ "File generated using haskell-ci-" ++ prettyShow version
+
+            (f, opts') <- parseOptions argv
+            doGitHub argv f ( optionsWithOutputFile fp <> opts' <> opts)
+  where
+    fp = defaultGitHubPath
+
+    noGitHubScript :: IO ()
+    noGitHubScript = putStrLn $ "No " ++ fp ++ ", skipping GitHub config regeneration"
+
+-------------------------------------------------------------------------------
+-- Config file
+-------------------------------------------------------------------------------
+
+findConfigFile :: MonadIO m => ConfigOpt -> m Config
+findConfigFile ConfigOptNo    = return emptyConfig
+findConfigFile (ConfigOpt fp) = readConfigFile fp
+findConfigFile ConfigOptAuto  = do
+    let defaultPath = "cabal.haskell-ci"
+    exists <- liftIO (doesFileExist defaultPath)
+    if exists
+    then readConfigFile defaultPath
+    else return emptyConfig
+
+-------------------------------------------------------------------------------
+-- Patches
+-------------------------------------------------------------------------------
+
+patchTravis
+    :: (MonadIO m, MonadMask m)
+    => Config -> ByteString -> m ByteString
+patchTravis = patchYAML . cfgTravisPatches
+
+patchGitHub
+    :: (MonadIO m, MonadMask m)
+    => Config -> ByteString -> m ByteString
+patchGitHub = patchYAML . cfgGitHubPatches
+
+-- | Adjust the generated YAML output with patch files, if specified.
 -- We do this in a temporary file in case the user did not pass --output (as
 -- it would be awkward to patch the generated output otherwise).
-patchTravis
+patchYAML
     :: (MonadIO m, MonadMask m)
-    => Config -> [String] -> m [String]
-patchTravis cfg ls
-  | null patches = pure ls
+    => [FilePath] -> ByteString -> m ByteString
+patchYAML patches input
+  | null patches = pure input
   | otherwise =
-      withSystemTempFile ".travis.yml.tmp" $ \fp h -> liftIO $ do
-        hPutStr h $ unlines ls
+      withSystemTempFile "yml.tmp" $ \fp h -> liftIO $ do
+        BS.hPutStr h input
         hFlush h
         for_ patches $ applyPatch fp
         hClose h
-        lines . fromUTF8BS <$> BS.readFile fp
+        BS.readFile fp
   where
-    patches :: [FilePath]
-    patches = cfgTravisPatches cfg
-
     applyPatch :: FilePath -- ^ The temporary file path to patch
                -> FilePath -- ^ The path of the .patch file
                -> IO ()
@@ -231,6 +429,47 @@
                 , "Stdout: " ++ stdOut
                 , "Stderr: " ++ stdErr
                 ]
+
+-------------------------------------------------------------------------------
+-- Utilities
+-------------------------------------------------------------------------------
+
+withContents
+    :: FilePath            -- ^ filepath
+    -> IO r                -- ^ what to do when file don't exist
+    -> (String -> IO r)    -- ^ continuation
+    -> IO r
+withContents path no kont = do
+    e <- try (BS.readFile path) :: IO (Either IOError BS.ByteString)
+    case e of
+        Left _         -> no
+        Right contents -> kont (fromUTF8BS contents)
+
+-- | Find @REGENDATA@ in a string
+findRegendataArgv :: String -> Maybe (Maybe Version, [String])
+findRegendataArgv contents = do
+    l <- findMaybe (afterInfix "REGENDATA") (lines contents)
+    first simpleParsec <$> (readMaybe l :: Maybe (String, [String]))
+        <|> (,) Nothing <$> (readMaybe l :: Maybe [String])
+
+-- | Read project file and associated .cabal files.
+getCabalFiles
+    :: (MonadDiagnostics m, MonadIO m)
+    => InputType
+    -> FilePath
+    -> m (Project URI Void (FilePath, GenericPackageDescription))
+getCabalFiles InputTypeProject path = do
+    contents <- liftIO $ BS.readFile path
+    prj0 <- either (putStrLnErr . renderParseError) return $ parseProject path contents
+    prj1 <- either (putStrLnErr . renderResolveError) return =<< liftIO (resolveProject path prj0)
+    either (putStrLnErr . renderParseError) return =<< liftIO (readPackagesOfProject prj1)
+getCabalFiles InputTypePackage path = do
+    e <- liftIO $ readPackagesOfProject (emptyProject & field @"prjPackages" .~ [path])
+    either (putStrLnErr . renderParseError) return e
+
+-------------------------------------------------------------------------------
+-- Config
+-------------------------------------------------------------------------------
 
 configFromCabalFile
     :: (MonadIO m, MonadDiagnostics m)
diff --git a/src/HaskellCI/Auxiliary.hs b/src/HaskellCI/Auxiliary.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellCI/Auxiliary.hs
@@ -0,0 +1,124 @@
+{-# LANGUAGE NamedFieldPuns    #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards   #-}
+module HaskellCI.Auxiliary (
+    Auxiliary (..),
+    auxiliary,
+    pkgNameDirVariable',
+    pkgNameDirVariable,
+) where
+
+import HaskellCI.Prelude
+import Prelude           (head)
+
+import qualified Data.Set                                     as S
+import qualified Distribution.CabalSpecVersion                as C
+import qualified Distribution.FieldGrammar.Pretty             as C
+import qualified Distribution.Fields.Pretty                   as C
+import qualified Distribution.Pretty                          as C
+import qualified Distribution.Types.GenericPackageDescription as C
+import qualified Distribution.Types.VersionRange              as C
+import qualified Text.PrettyPrint                             as PP
+
+import Cabal.Optimization
+import Cabal.Project
+import Cabal.SourceRepo
+import HaskellCI.Compiler
+import HaskellCI.Config
+import HaskellCI.Config.CopyFields
+import HaskellCI.Config.Doctest
+import HaskellCI.Config.Docspec
+import HaskellCI.Jobs
+import HaskellCI.List
+import HaskellCI.Package
+
+-- | Auxiliary definitions, probably useful for all backends
+data Auxiliary = Auxiliary
+    { pkgs                    :: [Package]
+    , uris                    :: [URI]
+    , projectName             :: String
+    , doctestEnabled          :: Bool
+    , docspecEnabled          :: Bool
+    , hasTests                :: CompilerRange
+    , hasLibrary              :: Bool
+    , extraCabalProjectFields :: [C.PrettyField ()]
+    , testShowDetails         :: String
+    }
+
+auxiliary :: Config -> Project URI Void Package -> JobVersions -> Auxiliary
+auxiliary Config {..} prj JobVersions {..} = Auxiliary {..}
+  where
+    pkgs = prjPackages prj
+    uris = prjUriPackages prj
+    projectName = fromMaybe (pkgName $ Prelude.head pkgs) cfgProjectName
+
+    doctestEnabled = any (maybeGHC False (`C.withinRange` cfgDoctestEnabled cfgDoctest)) versions
+    docspecEnabled = any (maybeGHC False (`C.withinRange` cfgDocspecEnabled cfgDocspec)) versions
+
+    testShowDetails
+        | cfgTestOutputDirect = " --test-show-details=direct"
+        | otherwise           = ""
+
+    -- version range which has tests
+    hasTests :: CompilerRange
+    hasTests = RangePoints $ S.unions
+        [ pkgJobs
+        | Pkg{pkgGpd,pkgJobs} <- pkgs
+        , not $ null $ C.condTestSuites pkgGpd
+        ]
+
+    hasLibrary = any (\Pkg{pkgGpd} -> isJust $ C.condLibrary pkgGpd) pkgs
+
+    extraCabalProjectFields :: [C.PrettyField ()]
+    extraCabalProjectFields = buildList $ do
+        -- generate package fields for URI packages.
+        for_ uris $ \uri ->
+            item $ C.PrettyField () "packages" $ PP.text $ uriToString id uri ""
+
+        -- copy fields from original cabal.project
+        case cfgCopyFields of
+            CopyFieldsNone -> pure ()
+            CopyFieldsSome -> copyFieldsSome
+            CopyFieldsAll  -> copyFieldsSome *> traverse_ item (prjOtherFields prj)
+
+        -- local ghc-options
+        unless (null cfgLocalGhcOptions) $ for_ pkgs $ \Pkg{pkgName} -> do
+            let s = unwords $ map (show . C.showToken) cfgLocalGhcOptions
+            item $ C.PrettySection () "package" [PP.text pkgName] $ buildList $
+                item $ C.PrettyField () "ghc-options" $ PP.text s
+
+        -- raw-project is after local-ghc-options so we can override per package.
+        traverse_ item cfgRawProject
+      where
+        copyFieldsSome :: ListBuilder (C.PrettyField ()) ()
+        copyFieldsSome = do
+            for_ (prjConstraints prj) $ \xs -> do
+                let s = concat (lines xs)
+                item $ C.PrettyField () "constraints" $ PP.text s
+
+            for_ (prjAllowNewer prj) $ \xs -> do
+                let s = concat (lines xs)
+                item $ C.PrettyField () "allow-newer" $ PP.text s
+
+            when (prjReorderGoals prj) $
+                item $ C.PrettyField () "reorder-goals" $ PP.text "True"
+
+            for_ (prjMaxBackjumps prj) $ \bj ->
+                item $ C.PrettyField () "max-backjumps" $ PP.text $ show bj
+
+            case prjOptimization prj of
+                OptimizationOn      -> return ()
+                OptimizationOff     -> item $ C.PrettyField () "optimization" $ PP.text "False"
+                OptimizationLevel l -> item $ C.PrettyField () "optimization" $ PP.text $ show l
+
+            for_ (prjSourceRepos prj) $ \repo ->
+                item $ C.PrettySection () "source-repository-package" [] $
+                    C.prettyFieldGrammar C.cabalSpecLatest sourceRepositoryPackageGrammar (srpHoist toList repo)
+
+pkgNameDirVariable' :: String -> String
+pkgNameDirVariable' n = "PKGDIR_" ++ map f n where
+    f '-' = '_'
+    f c   = c
+
+pkgNameDirVariable :: String -> String
+pkgNameDirVariable n = "${" ++ pkgNameDirVariable' n ++ "}"
diff --git a/src/HaskellCI/Bash.hs b/src/HaskellCI/Bash.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellCI/Bash.hs
@@ -0,0 +1,308 @@
+{-# LANGUAGE NamedFieldPuns  #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# OPTIONS_GHC -Wno-unused-matches #-}
+module HaskellCI.Bash (
+    makeBash
+) where
+
+import HaskellCI.Prelude
+
+import qualified Data.Set                        as S
+import qualified Distribution.Fields.Pretty      as C
+import qualified Distribution.Package            as C
+import qualified Distribution.Types.VersionRange as C
+import qualified Distribution.Version            as C
+
+import Cabal.Project
+import HaskellCI.Auxiliary
+import HaskellCI.Bash.Template
+import HaskellCI.Compiler
+import HaskellCI.Config
+import HaskellCI.Config.ConstraintSet
+import HaskellCI.Config.Doctest
+import HaskellCI.Config.Installed
+import HaskellCI.Config.PackageScope
+import HaskellCI.Jobs
+import HaskellCI.List
+import HaskellCI.Package
+import HaskellCI.Sh
+import HaskellCI.ShVersionRange
+import HaskellCI.Tools
+
+{-
+Bash-specific notes:
+
+* We use -j for parallelism, as the exact number of cores depends on the
+  particular machine the script is being run on.
+-}
+
+makeBash
+    :: [String]
+    -> Config
+    -> Project URI Void Package
+    -> JobVersions
+    -> Either ShError Z -- TODO: writer
+makeBash _argv config@Config {..} prj jobs@JobVersions {..} = do
+    blocks <- traverse (fmap shsToList) $ buildList $ do
+        -- install doctest
+        when doctestEnabled $ step "install doctest" $ do
+            let range = Range (cfgDoctestEnabled cfgDoctest) /\ doctestJobVersionRange
+            comment "install doctest"
+            run_cmd_if range "$CABAL v2-install $ARG_COMPILER --ignore-project -j doctest --constraint='doctest ^>=0.17'"
+            run_cmd_if range "doctest --version"
+
+        -- install hlint
+        -- TODO
+
+        -- autoreconf ...
+        -- hmm, source is read-only...
+
+        step "initial cabal.project for sdist" $ do
+            change_dir "$BUILDDIR"
+            run_cmd "touch cabal.project"
+            for_ pkgs $ \pkg ->
+                echo_if_to (RangePoints $ pkgJobs pkg) "cabal.project" $ "packages: $SRCDIR/" ++ pkgDir pkg
+            run_cmd "cat cabal.project"
+
+        -- sdist
+        step "sdist" $ do
+            run_cmd "mkdir -p \"$BUILDDIR/sdist\""
+            -- TODO: check if cabal-install-3.4 can be run on read only system
+            run_cmd "$CABAL sdist all --output-dir \"$BUILDDIR/sdist\""
+
+        -- find and unpack sdist
+        step "unpack" $ do
+            change_dir "$BUILDDIR"
+            run_cmd "mkdir -p \"$BUILDDIR/unpacked\""
+            run_cmd "find \"$BUILDDIR/sdist\" -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C \"$BUILDDIR/unpacked\" -xzvf {} \\;"
+
+        -- write cabal.project
+        step "generate cabal.project" $ do
+            for_ pkgs $ \Pkg{pkgName} -> do
+                sh $ pkgNameDirVariable' pkgName ++ "=\"$(find \"$BUILDDIR/unpacked\" -maxdepth 1 -type d -regex '.*/" ++ pkgName ++ "-[0-9.]*')\""
+
+            run_cmd "touch cabal.project"
+            run_cmd "touch cabal.project.local"
+
+            for_ pkgs $ \pkg ->
+                echo_if_to (RangePoints $ pkgJobs pkg) "cabal.project" $ "packages: " ++ pkgNameDirVariable (pkgName pkg)
+
+            -- per package options
+            case cfgErrorMissingMethods of
+                PackageScopeNone  -> pure ()
+                PackageScopeLocal -> for_ pkgs $ \Pkg{pkgName,pkgJobs} -> do
+                    let range = Range (C.orLaterVersion (C.mkVersion [8,2])) /\ RangePoints pkgJobs
+                    echo_if_to range "cabal.project" $ "package " ++ pkgName
+                    echo_if_to range "cabal.project" $ "    ghc-options: -Werror=missing-methods"
+                PackageScopeAll   -> cat "cabal.project" $ unlines
+                    [ "package *"
+                    , "  ghc-options: -Werror=missing-methods"
+                    ]
+
+            -- extra cabal.project fields
+            cat "cabal.project" $ C.showFields' (const []) (const id) 2 extraCabalProjectFields
+
+            -- also write cabal.project.local file with
+            -- @
+            -- constraints: base installed
+            -- constraints: array installed
+            -- ...
+            --
+            -- omitting any local package names
+            case normaliseInstalled cfgInstalled of
+                InstalledDiff pns -> sh $ unwords
+                    [ "$HCPKG list --simple-output --names-only"
+                    , "| perl -ne 'for (split /\\s+/) { print \"constraints: $_ installed\\n\" unless /" ++ re ++ "/; }'"
+                    , ">> cabal.project.local"
+                    ]
+                  where
+                    pns' = S.map C.unPackageName pns `S.union` foldMap (S.singleton . pkgName) pkgs
+                    re = "^(" ++ intercalate "|" (S.toList pns') ++ ")$"
+
+                InstalledOnly pns | not (null pns') -> cat "cabal.project.local" $ unlines
+                    [ "constraints: " ++ pkg ++ " installed"
+                    | pkg <- S.toList pns'
+                    ]
+                  where
+                    pns' = S.map C.unPackageName pns `S.difference` foldMap (S.singleton . pkgName) pkgs
+
+                -- otherwise: nothing
+                _ -> pure ()
+
+            run_cmd "cat cabal.project"
+            run_cmd "cat cabal.project.local"
+
+        -- dump install plan
+        step "dump install plan" $ do
+            run_cmd "$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all"
+            run_cmd "cabal-plan"
+
+        -- install dependencies
+        when cfgInstallDeps $ step "install dependencies" $ do
+            run_cmd "$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j all"
+            run_cmd "$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j all"
+
+        unless (equivVersionRanges C.noVersion cfgNoTestsNoBench) $ step "build w/o tests" $ do
+            run_cmd "$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all"
+
+        -- build
+        step "build" $ do
+            run_cmd "$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all"
+
+        -- tests
+        step "tests" $ do
+            let range = RangeGHC /\ Range (cfgTests /\ cfgRunTests) /\ hasTests
+            run_cmd_if range $ "$CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all" ++ testShowDetails
+
+        -- doctest
+        when doctestEnabled $ step "doctest" $ do
+            let doctestOptions = unwords $ cfgDoctestOptions cfgDoctest
+
+            unless (null $ cfgDoctestFilterEnvPkgs cfgDoctest) $ do
+                -- cabal-install mangles unit ids on the OSX,
+                -- removing the vowels to make filepaths shorter
+                let manglePkgNames :: String -> [String]
+                    manglePkgNames n
+                        | null cfgOsx = [n]
+                        | otherwise   = [n, filter notVowel n]
+                      where
+                        notVowel c = notElem c ("aeiou" :: String)
+                let filterPkgs = intercalate "|" $ concatMap (manglePkgNames . C.unPackageName) $ cfgDoctestFilterEnvPkgs cfgDoctest
+                run_cmd $ "perl -i -e 'while (<ARGV>) { print unless /package-id\\s+(" ++ filterPkgs ++ ")-\\d+(\\.\\d+)*/; }' .ghc.environment.*"
+
+            for_ pkgs $ \Pkg{pkgName,pkgGpd,pkgJobs} ->
+                when (C.mkPackageName pkgName `notElem` cfgDoctestFilterSrcPkgs cfgDoctest) $ do
+                    for_ (doctestArgs pkgGpd) $ \args -> do
+                        let args' = unwords args
+                        let vr = Range (cfgDoctestEnabled cfgDoctest)
+                              /\ doctestJobVersionRange
+                              /\ RangePoints pkgJobs
+
+                        unless (null args) $ do
+                            change_dir_if vr $ pkgNameDirVariable pkgName
+                            run_cmd_if vr $ "doctest " ++ doctestOptions ++ " " ++ args'
+
+        -- hlint
+        -- TODO
+
+        -- cabal check
+        when cfgCheck $ step "cabal check" $ do
+            for_ pkgs $ \Pkg{pkgName,pkgJobs} -> do
+                let range = RangePoints pkgJobs
+                change_dir_if range $ pkgNameDirVariable pkgName
+                run_cmd_if range "${CABAL} -vnormal check"
+            change_dir "$BUILDDIR"
+
+        -- haddock
+        when (hasLibrary && not (equivVersionRanges C.noVersion cfgHaddock)) $ step "haddock" $ do
+            let range = RangeGHC /\ Range cfgHaddock
+            run_cmd_if range "$CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all"
+
+        -- unconstrained build
+        unless (equivVersionRanges C.noVersion cfgUnconstrainted) $ step "unconstrained build" $ do
+            let range = Range cfgUnconstrainted
+            run_cmd_if range "rm -f cabal.project.local"
+            run_cmd_if range "$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all"
+
+        -- constraint sets
+        unless (null cfgConstraintSets) $ step "constraint sets" $ do
+            run_cmd "rm -f cabal.project.local"
+
+            for_ cfgConstraintSets $ \cs -> do
+                let name            = csName cs
+                let run_cmd_cs      = run_cmd_if (Range (csGhcVersions cs))
+                let run_cmd_cs' r   = run_cmd_if (Range (csGhcVersions cs) /\ r)
+                let testFlag        = if csTests cs then "--enable-tests" else "--disable-tests"
+                let benchFlag       = if csBenchmarks cs then "--enable-benchmarks" else "--disable-benchmarks"
+                let constraintFlags = map (\x ->  "--constraint='" ++ x ++ "'") (csConstraints cs)
+                let allFlags        = unwords (testFlag : benchFlag : constraintFlags)
+
+                put_info $ "constraint set " ++ name
+                run_cmd_cs $ "$CABAL v2-build $ARG_COMPILER " ++ allFlags ++ " all"
+                when (csRunTests cs) $
+                    run_cmd_cs' hasTests $ "$CABAL v2-test $ARG_COMPILER " ++ allFlags ++ " all"
+                when (hasLibrary && csHaddock cs) $
+                    run_cmd_cs $ "$CABAL v2-haddock $ARG_COMPILER " ++ withHaddock ++ " " ++ allFlags ++ " all"
+
+    return defaultZ
+        { zJobs =
+            [ prettyShow v
+            | GHC v <- reverse $ toList versions
+            ]
+        , zBlocks = blocks
+        , zApt = S.toList cfgApt
+        , zTestsCond = compilerVersionArithPredicate versions $ Range cfgTests
+        , zBenchCond = compilerVersionArithPredicate versions $ Range cfgBenchmarks
+        }
+  where
+    Auxiliary {..} = auxiliary config prj jobs
+
+    -- TODO: this can be smart and do nothing is there are only comments in [Sh]
+    step :: String -> ShM () -> ListBuilder (Either ShError [Sh]) ()
+    step name action = item $ runSh $ do
+        comment name
+        put_info name
+        action
+
+    put_info :: String -> ShM ()
+    put_info s = sh $ "put_info " ++ show s
+
+    change_dir :: String -> ShM ()
+    change_dir dir = sh $ "change_dir " ++ show dir
+
+    change_dir_if :: CompilerRange -> String -> ShM ()
+    change_dir_if vr dir
+        | all (`compilerWithinRange` vr) versions       = change_dir dir
+        | not $ any (`compilerWithinRange` vr) versions = pure ()
+        | otherwise = sh $ unwords
+            [ "change_dir_if"
+            , compilerVersionArithPredicate versions vr
+            , dir
+            ]
+
+    run_cmd :: String -> ShM ()
+    run_cmd cmd = sh $ unwords
+        [ "run_cmd"
+        , cmd
+        ]
+
+    run_cmd_if :: CompilerRange -> String -> ShM ()
+    run_cmd_if vr cmd
+        | all (`compilerWithinRange` vr) versions       = run_cmd cmd
+        | not $ any (`compilerWithinRange` vr) versions = pure ()
+        | otherwise = sh $ unwords
+            [ "run_cmd_if"
+            , compilerVersionArithPredicate versions vr
+            , cmd
+            ]
+
+    echo_if_to :: CompilerRange -> FilePath -> String -> ShM ()
+    echo_if_to vr path contents
+        | all (`compilerWithinRange` vr) versions = sh $ unwords
+            [ "echo_to"
+            , path
+            , show contents
+            ]
+        | not $ any (`compilerWithinRange` vr) versions = pure ()
+        | otherwise = sh $ unwords
+            [ "echo_if_to"
+            , compilerVersionArithPredicate versions vr
+            , path
+            , show contents
+            ]
+
+    -- Needed to work around haskell/cabal#6214
+    withHaddock :: String
+    withHaddock = "--with-haddock $HADDOCK"
+
+shsToList :: [Sh] -> String
+shsToList = unlines . map f where
+    f (Sh x)      = x
+    f (Comment c) = "# " ++ c
+
+cat :: FilePath -> String -> ShM ()
+cat path contents = sh $ concat
+    [ "cat >> " ++ path ++ " <<EOF\n"
+    , contents
+    , "EOF"
+    ]
diff --git a/src/HaskellCI/Bash/Template.hs b/src/HaskellCI/Bash/Template.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellCI/Bash/Template.hs
@@ -0,0 +1,549 @@
+{-# LANGUAGE CPP #-}
+module HaskellCI.Bash.Template (
+    -- * Input
+    Z (..),
+    defaultZ,
+    -- * Rendering
+    renderIO,
+    render,
+) where
+
+import HaskellCI.Prelude
+
+import Control.Monad (forM_)
+
+import qualified Zinza
+
+data Z = Z
+    { zJobs      :: [String]
+    , zRegendata :: String
+    , zBlocks    :: [String]
+    , zTestsCond :: String
+    , zBenchCond :: String
+    , zApt       :: [String]
+    , zNotNull   :: [String] -> Bool
+    , zUnwords   :: [String] -> String
+    }
+  deriving (Generic)
+
+defaultZ :: Z
+defaultZ = Z
+    { zJobs      = []
+    , zRegendata = "[]"
+    , zBlocks    = []
+    , zTestsCond = "1"
+    , zBenchCond = "1"
+    , zApt       = []
+    , zNotNull   = not . null
+    , zUnwords   = unwords
+    }
+
+instance Zinza.Zinza Z where
+    toType    = Zinza.genericToTypeSFP
+    toValue   = Zinza.genericToValueSFP
+    fromValue = Zinza.genericFromValueSFP
+
+-------------------------------------------------------------------------------
+-- Development
+-------------------------------------------------------------------------------
+
+-- #define DEVELOPMENT 1
+
+#ifdef DEVELOPMENT
+
+renderIO :: Z -> IO String
+renderIO z = do
+    template <- Zinza.parseAndCompileTemplateIO "haskell-ci.sh.zinza"
+    template z
+
+#endif
+
+-------------------------------------------------------------------------------
+-- Production
+-------------------------------------------------------------------------------
+
+#ifndef DEVELOPMENT
+renderIO :: Z -> IO String
+renderIO = return . render
+#endif
+
+type Writer a = (String, a)
+tell :: String -> Writer (); tell x = (x, ())
+execWriter :: Writer a -> String; execWriter = fst
+
+-- To generate:
+--
+-- :m *HaskellCI.Bash.Template
+-- Zinza.parseAndCompileModuleIO (Zinza.simpleConfig "Module" [] :: Zinza.ModuleConfig Z) "haskell-ci.sh.zinza" >>= putStr
+
+render :: Z -> String
+render z_root = execWriter $ do
+  tell "#!/bin/bash\n"
+  tell "# shellcheck disable=SC2086,SC2016,SC2046\n"
+  tell "# REGENDATA "
+  tell (zRegendata z_root)
+  tell "\n"
+  tell "\n"
+  tell "set -o pipefail\n"
+  tell "\n"
+  tell "# Mode\n"
+  tell "##############################################################################\n"
+  tell "\n"
+  tell "if [ \"$1\" = \"indocker\" ]; then\n"
+  tell "    INDOCKER=true\n"
+  tell "    shift\n"
+  tell "else\n"
+  tell "    INDOCKER=false\n"
+  tell "fi\n"
+  tell "\n"
+  tell "# Run configuration\n"
+  tell "##############################################################################\n"
+  tell "\n"
+  tell "CFG_CABAL_STORE_CACHE=\"\"\n"
+  tell "CFG_CABAL_REPO_CACHE=\"\"\n"
+  tell "CFG_JOBS=\""
+  tell (zUnwords z_root (zJobs z_root))
+  tell "\"\n"
+  tell "CFG_CABAL_UPDATE=false\n"
+  tell "\n"
+  tell "SCRIPT_NAME=$(basename \"$0\")\n"
+  tell "START_TIME=\"$(date +'%s')\"\n"
+  tell "\n"
+  tell "XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config}\n"
+  tell "\n"
+  tell "# Job configuration\n"
+  tell "##############################################################################\n"
+  tell "\n"
+  tell "GHC_VERSION=\"non-existing\"\n"
+  tell "CABAL_VERSION=3.2\n"
+  tell "HEADHACKAGE=false\n"
+  tell "\n"
+  tell "# Locale\n"
+  tell "##############################################################################\n"
+  tell "\n"
+  tell "export LC_ALL=C.UTF-8\n"
+  tell "\n"
+  tell "# Utilities\n"
+  tell "##############################################################################\n"
+  tell "\n"
+  tell "SGR_RED='\\033[1;31m'\n"
+  tell "SGR_GREEN='\\033[1;32m'\n"
+  tell "SGR_BLUE='\\033[1;34m'\n"
+  tell "SGR_CYAN='\\033[1;96m'\n"
+  tell "SGR_RESET='\\033[0m' # No Color\n"
+  tell "\n"
+  tell "put_info() {\n"
+  tell "    printf \"$SGR_CYAN%s$SGR_RESET\\n\" \"### $*\"\n"
+  tell "}\n"
+  tell "\n"
+  tell "put_error() {\n"
+  tell "    printf \"$SGR_RED%s$SGR_RESET\\n\" \"!!! $*\"\n"
+  tell "}\n"
+  tell "\n"
+  tell "run_cmd() {\n"
+  tell "    local PRETTYCMD=\"$*\"\n"
+  tell "    local PROMPT\n"
+  tell "    if $INDOCKER; then\n"
+  tell "        PROMPT=\"$(pwd) >>>\"\n"
+  tell "    else\n"
+  tell "        PROMPT=\">>>\"\n"
+  tell "    fi\n"
+  tell "\n"
+  tell "    printf \"$SGR_BLUE%s %s$SGR_RESET\\n\" \"$PROMPT\" \"$PRETTYCMD\"\n"
+  tell "\n"
+  tell "    local start_time end_time cmd_duration total_duration\n"
+  tell "    start_time=$(date +'%s')\n"
+  tell "\n"
+  tell "    \"$@\"\n"
+  tell "    local RET=$?\n"
+  tell "\n"
+  tell "    end_time=$(date +'%s')\n"
+  tell "    cmd_duration=$((end_time - start_time))\n"
+  tell "    total_duration=$((end_time - START_TIME))\n"
+  tell "\n"
+  tell "    cmd_min=$((cmd_duration / 60))\n"
+  tell "    cmd_sec=$((cmd_duration % 60))\n"
+  tell "\n"
+  tell "    total_min=$((total_duration / 60))\n"
+  tell "    total_sec=$((total_duration % 60))\n"
+  tell "\n"
+  tell "    if [ $RET -eq 0 ]; then\n"
+  tell "        printf \"$SGR_GREEN%s$SGR_RESET (%dm%02ds; %dm%02ds)\\n\" \"<<< $PRETTYCMD\" \"$cmd_min\" \"$cmd_sec\" \"$total_min\" \"$total_sec\"\n"
+  tell "    else\n"
+  tell "        printf \"$SGR_RED%s$SGR_RESET\\n\" \"!!! $PRETTYCMD\"\n"
+  tell "        exit 1\n"
+  tell "    fi\n"
+  tell "}\n"
+  tell "\n"
+  tell "run_cmd_if() {\n"
+  tell "    local COND=$1\n"
+  tell "    shift\n"
+  tell "\n"
+  tell "    if [ $COND -eq 1 ]; then\n"
+  tell "        run_cmd \"$@\"\n"
+  tell "    else\n"
+  tell "        local PRETTYCMD=\"$*\"\n"
+  tell "        local PROMPT\n"
+  tell "        PROMPT=\"$(pwd) (skipping) >>>\"\n"
+  tell "\n"
+  tell "        printf \"$SGR_BLUE%s %s$SGR_RESET\\n\" \"$PROMPT\" \"$PRETTYCMD\"\n"
+  tell "    fi\n"
+  tell "}\n"
+  tell "\n"
+  tell "run_cmd_unchecked() {\n"
+  tell "    local PRETTYCMD=\"$*\"\n"
+  tell "    local PROMPT\n"
+  tell "    if $INDOCKER; then\n"
+  tell "        PROMPT=\"$(pwd) >>>\"\n"
+  tell "    else\n"
+  tell "        PROMPT=\">>>\"\n"
+  tell "    fi\n"
+  tell "\n"
+  tell "    printf \"$SGR_BLUE%s %s$SGR_RESET\\n\" \"$PROMPT\" \"$PRETTYCMD\"\n"
+  tell "\n"
+  tell "    local start_time end_time cmd_duration total_duration cmd_min cmd_sec total_min total_sec\n"
+  tell "    start_time=$(date +'%s')\n"
+  tell "\n"
+  tell "    \"$@\"\n"
+  tell "\n"
+  tell "    end_time=$(date +'%s')\n"
+  tell "    cmd_duration=$((end_time - start_time))\n"
+  tell "    total_duration=$((end_time - START_TIME))\n"
+  tell "\n"
+  tell "    cmd_min=$((cmd_duration / 60))\n"
+  tell "    cmd_sec=$((cmd_duration % 60))\n"
+  tell "\n"
+  tell "    total_min=$((total_duration / 60))\n"
+  tell "    total_sec=$((total_duration % 60))\n"
+  tell "\n"
+  tell "    printf \"$SGR_GREEN%s$SGR_RESET (%dm%02ds; %dm%02ds)\\n\" \"<<< $PRETTYCMD\" \"$cmd_min\" \"$cmd_sec\" \"$total_min\" \"$total_sec\"\n"
+  tell "}\n"
+  tell "\n"
+  tell "change_dir() {\n"
+  tell "    local DIR=$1\n"
+  tell "    if [ -d \"$DIR\" ]; then\n"
+  tell "        printf \"$SGR_BLUE%s$SGR_RESET\\n\" \"change directory to $DIR\"\n"
+  tell "        cd \"$DIR\" || exit 1\n"
+  tell "    else\n"
+  tell "        printf \"$SGR_RED%s$SGR_RESET\\n\" \"!!! cd $DIR\"\n"
+  tell "        exit 1\n"
+  tell "    fi\n"
+  tell "}\n"
+  tell "\n"
+  tell "change_dir_if() {\n"
+  tell "    local COND=$1\n"
+  tell "    local DIR=$2\n"
+  tell "\n"
+  tell "    if [ $COND -ne 0 ]; then\n"
+  tell "        change_dir \"$DIR\"\n"
+  tell "    fi\n"
+  tell "}\n"
+  tell "\n"
+  tell "echo_to() {\n"
+  tell "    local DEST=$1\n"
+  tell "    local CONTENTS=$2\n"
+  tell "\n"
+  tell "    echo \"$CONTENTS\" >> \"$DEST\"\n"
+  tell "}\n"
+  tell "\n"
+  tell "echo_if_to() {\n"
+  tell "    local COND=$1\n"
+  tell "    local DEST=$2\n"
+  tell "    local CONTENTS=$3\n"
+  tell "\n"
+  tell "    if [ $COND -ne 0 ]; then\n"
+  tell "        echo_to \"$DEST\" \"$CONTENTS\"\n"
+  tell "    fi\n"
+  tell "}\n"
+  tell "\n"
+  tell "install_cabalplan() {\n"
+  tell "    put_info \"installing cabal-plan\"\n"
+  tell "\n"
+  tell "    if [ ! -e $CABAL_REPOCACHE/downloads/cabal-plan ]; then\n"
+  tell "        curl -L https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > /tmp/cabal-plan.xz || exit 1\n"
+  tell "        (cd /tmp && echo \"de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc  cabal-plan.xz\" | sha256sum -c -)|| exit 1\n"
+  tell "        mkdir -p $CABAL_REPOCACHE/downloads\n"
+  tell "        xz -d < /tmp/cabal-plan.xz > $CABAL_REPOCACHE/downloads/cabal-plan || exit 1\n"
+  tell "        chmod a+x $CABAL_REPOCACHE/downloads/cabal-plan || exit 1\n"
+  tell "    fi\n"
+  tell "\n"
+  tell "    mkdir -p $CABAL_DIR/bin || exit 1\n"
+  tell "    ln -s $CABAL_REPOCACHE/downloads/cabal-plan $CABAL_DIR/bin/cabal-plan || exit 1\n"
+  tell "}\n"
+  tell "\n"
+  tell "# Help\n"
+  tell "##############################################################################\n"
+  tell "\n"
+  tell "show_usage() {\n"
+  tell "cat <<EOF\n"
+  tell "./haskell-ci.sh - build & test\n"
+  tell "\n"
+  tell "Usage: ./haskell-ci.sh [options]\n"
+  tell "  A script to run automated checks locally (using Docker)\n"
+  tell "\n"
+  tell "Available options:\n"
+  tell "  --jobs JOBS               Jobs to run (default: $CFG_JOBS)\n"
+  tell "  --cabal-store-cache PATH  Directory to use for cabal-store-cache\n"
+  tell "  --cabal-repo-cache PATH   Directory to use for cabal-repo-cache\n"
+  tell "  --skip-cabal-update       Skip cabal update (useful with --cabal-repo-cache)\n"
+  tell "  --no-skip-cabal-update\n"
+  tell "  --help                    Print this message\n"
+  tell "\n"
+  tell "EOF\n"
+  tell "}\n"
+  tell "\n"
+  tell "# getopt\n"
+  tell "#######################################################################\n"
+  tell "\n"
+  tell "process_cli_options() {\n"
+  tell "    while [ $# -gt 0 ]; do\n"
+  tell "        arg=$1\n"
+  tell "        case $arg in\n"
+  tell "            --help)\n"
+  tell "                show_usage\n"
+  tell "                exit\n"
+  tell "                ;;\n"
+  tell "            --jobs)\n"
+  tell "                CFG_JOBS=$2\n"
+  tell "                shift\n"
+  tell "                shift\n"
+  tell "                ;;\n"
+  tell "            --cabal-store-cache)\n"
+  tell "                CFG_CABAL_STORE_CACHE=$2\n"
+  tell "                shift\n"
+  tell "                shift\n"
+  tell "                ;;\n"
+  tell "            --cabal-repo-cache)\n"
+  tell "                CFG_CABAL_REPO_CACHE=$2\n"
+  tell "                shift\n"
+  tell "                shift\n"
+  tell "                ;;\n"
+  tell "            --skip-cabal-update)\n"
+  tell "                CFG_CABAL_UPDATE=false\n"
+  tell "                shift\n"
+  tell "                ;;\n"
+  tell "            --no-skip-cabal-update)\n"
+  tell "                CFG_CABAL_UPDATE=true\n"
+  tell "                shift\n"
+  tell "                ;;\n"
+  tell "            *)\n"
+  tell "                echo \"Unknown option $arg\"\n"
+  tell "                exit 1\n"
+  tell "        esac\n"
+  tell "    done\n"
+  tell "}\n"
+  tell "\n"
+  tell "process_indocker_options () {\n"
+  tell "    while [ $# -gt 0 ]; do\n"
+  tell "        arg=$1\n"
+  tell "\n"
+  tell "        case $arg in\n"
+  tell "            --ghc-version)\n"
+  tell "                GHC_VERSION=$2\n"
+  tell "                shift\n"
+  tell "                shift\n"
+  tell "                ;;\n"
+  tell "            --cabal-version)\n"
+  tell "                CABAL_VERSION=$2\n"
+  tell "                shift\n"
+  tell "                shift\n"
+  tell "                ;;\n"
+  tell "            --start-time)\n"
+  tell "                START_TIME=$2\n"
+  tell "                shift\n"
+  tell "                shift\n"
+  tell "                ;;\n"
+  tell "            --cabal-update)\n"
+  tell "                CABAL_UPDATE=$2\n"
+  tell "                shift\n"
+  tell "                shift\n"
+  tell "                ;;\n"
+  tell "            *)\n"
+  tell "                echo \"Unknown option $arg\"\n"
+  tell "                exit 1\n"
+  tell "        esac\n"
+  tell "    done\n"
+  tell "}\n"
+  tell "\n"
+  tell "if $INDOCKER; then\n"
+  tell "    process_indocker_options \"$@\"\n"
+  tell "\n"
+  tell "else\n"
+  tell "    if [ -f \"$XDG_CONFIG_HOME/haskell-ci/bash.config\" ]; then\n"
+  tell "        process_cli_options $(cat \"$XDG_CONFIG_HOME/haskell-ci/bash.config\")\n"
+  tell "    fi\n"
+  tell "\n"
+  tell "    process_cli_options \"$@\"\n"
+  tell "\n"
+  tell "    put_info \"jobs:              $CFG_JOBS\"\n"
+  tell "    put_info \"cabal-store-cache: $CFG_CABAL_STORE_CACHE\"\n"
+  tell "    put_info \"cabal-repo-cache:  $CFG_CABAL_REPO_CACHE\"\n"
+  tell "    put_info \"cabal-update:      $CFG_CABAL_UPDATE\"\n"
+  tell "fi\n"
+  tell "\n"
+  tell "# Constants\n"
+  tell "##############################################################################\n"
+  tell "\n"
+  tell "SRCDIR=/hsci/src\n"
+  tell "BUILDDIR=/hsci/build\n"
+  tell "CABAL_DIR=\"$BUILDDIR/cabal\"\n"
+  tell "CABAL_REPOCACHE=/hsci/cabal-repocache\n"
+  tell "CABAL_STOREDIR=/hsci/store\n"
+  tell "\n"
+  tell "# Docker invoke\n"
+  tell "##############################################################################\n"
+  tell "\n"
+  tell "# if cache directory is specified, use it.\n"
+  tell "# Otherwise use another tmpfs host\n"
+  tell "if [ -z \"$CFG_CABAL_STORE_CACHE\" ]; then\n"
+  tell "    CABALSTOREARG=\"--tmpfs $CABAL_STOREDIR:exec\"\n"
+  tell "else\n"
+  tell "    CABALSTOREARG=\"--volume $CFG_CABAL_STORE_CACHE:$CABAL_STOREDIR\"\n"
+  tell "fi\n"
+  tell "\n"
+  tell "if [ -z \"$CFG_CABAL_REPO_CACHE\" ]; then\n"
+  tell "    CABALREPOARG=\"--tmpfs $CABAL_REPOCACHE:exec\"\n"
+  tell "else\n"
+  tell "    CABALREPOARG=\"--volume $CFG_CABAL_REPO_CACHE:$CABAL_REPOCACHE\"\n"
+  tell "fi\n"
+  tell "\n"
+  tell "echo_docker_cmd() {\n"
+  tell "    local GHCVER=$1\n"
+  tell "\n"
+  tell "    # TODO: mount /hsci/src:ro (readonly)\n"
+  tell "    echo docker run \\\n"
+  tell "        --tty \\\n"
+  tell "        --interactive \\\n"
+  tell "        --rm \\\n"
+  tell "        --label haskell-ci \\\n"
+  tell "        --volume \"$(pwd):/hsci/src\" \\\n"
+  tell "        $CABALSTOREARG \\\n"
+  tell "        $CABALREPOARG \\\n"
+  tell "        --tmpfs /tmp:exec \\\n"
+  tell "        --tmpfs /hsci/build:exec \\\n"
+  tell "        --workdir /hsci/build \\\n"
+  tell "        \"phadej/ghc:$GHCVER-bionic\" \\\n"
+  tell "        \"/bin/bash\" \"/hsci/src/$SCRIPT_NAME\" indocker \\\n"
+  tell "        --ghc-version \"$GHCVER\" \\\n"
+  tell "        --cabal-update \"$CFG_CABAL_UPDATE\" \\\n"
+  tell "        --start-time \"$START_TIME\"\n"
+  tell "}\n"
+  tell "\n"
+  tell "# if we are not in docker, loop through jobs\n"
+  tell "if ! $INDOCKER; then\n"
+  tell "    for JOB in $CFG_JOBS; do\n"
+  tell "        put_info \"Running in docker: $JOB\"\n"
+  tell "        run_cmd $(echo_docker_cmd \"$JOB\")\n"
+  tell "    done\n"
+  tell "\n"
+  tell "    run_cmd echo \"ALL OK\"\n"
+  tell "    exit 0\n"
+  tell "fi\n"
+  tell "\n"
+  tell "# Otherwise we are in docker, and the rest of script executes\n"
+  tell "put_info \"In docker\"\n"
+  tell "\n"
+  tell "# Environment\n"
+  tell "##############################################################################\n"
+  tell "\n"
+  tell "GHCDIR=/opt/ghc/$GHC_VERSION\n"
+  tell "\n"
+  tell "HC=$GHCDIR/bin/ghc\n"
+  tell "HCPKG=$GHCDIR/bin/ghc-pkg\n"
+  tell "HADDOCK=$GHCDIR/bin/haddock\n"
+  tell "\n"
+  tell "CABAL=/opt/cabal/$CABAL_VERSION/bin/cabal\n"
+  tell "\n"
+  tell "CABAL=\"$CABAL -vnormal+nowrap\"\n"
+  tell "\n"
+  tell "export CABAL_DIR\n"
+  tell "export CABAL_CONFIG=\"$BUILDDIR/cabal/config\"\n"
+  tell "\n"
+  tell "PATH=\"$CABAL_DIR/bin:$PATH\"\n"
+  tell "\n"
+  tell "# HCNUMVER\n"
+  tell "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')\n"
+  tell "GHCJSARITH=0\n"
+  tell "\n"
+  tell "put_info \"HCNUMVER: $HCNUMVER\"\n"
+  tell "\n"
+  tell "# Args for shorter/nicer commands\n"
+  tell "if [ "
+  tell (zTestsCond z_root)
+  tell " -ne 0 ] ; then ARG_TESTS=--enable-tests; else ARG_TESTS=--disable-tests; fi\n"
+  tell "if [ "
+  tell (zBenchCond z_root)
+  tell " -ne 0 ] ; then ARG_BENCH=--enable-benchmarks; else ARG_BENCH=--disable-benchmarks; fi\n"
+  tell "ARG_COMPILER=\"--ghc --with-compiler=$HC\"\n"
+  tell "\n"
+  tell "put_info \"tests/benchmarks: $ARG_TESTS $ARG_BENCH\"\n"
+  tell "\n"
+  tell "# Apt dependencies\n"
+  tell "##############################################################################\n"
+  tell "\n"
+  if (zNotNull z_root (zApt z_root))
+  then do
+    tell "run_cmd apt-get update\n"
+    tell "run_cmd apt-get install -y --no-install-recommends "
+    tell (zUnwords z_root (zApt z_root))
+    tell "\n"
+    return ()
+  else do
+    return ()
+  tell "\n"
+  tell "# Cabal config\n"
+  tell "##############################################################################\n"
+  tell "\n"
+  tell "mkdir -p $BUILDDIR/cabal\n"
+  tell "\n"
+  tell "cat > $BUILDDIR/cabal/config <<EOF\n"
+  tell "remote-build-reporting: anonymous\n"
+  tell "write-ghc-environment-files: always\n"
+  tell "remote-repo-cache: $CABAL_REPOCACHE\n"
+  tell "logs-dir:          $CABAL_DIR/logs\n"
+  tell "world-file:        $CABAL_DIR/world\n"
+  tell "extra-prog-path:   $CABAL_DIR/bin\n"
+  tell "symlink-bindir:    $CABAL_DIR/bin\n"
+  tell "installdir:        $CABAL_DIR/bin\n"
+  tell "build-summary:     $CABAL_DIR/logs/build.log\n"
+  tell "store-dir:         $CABAL_STOREDIR\n"
+  tell "install-dirs user\n"
+  tell "  prefix: $CABAL_DIR\n"
+  tell "repository hackage.haskell.org\n"
+  tell "  url: http://hackage.haskell.org/\n"
+  tell "EOF\n"
+  tell "\n"
+  tell "if $HEADHACKAGE; then\n"
+  tell "    put_error \"head.hackage is not implemented\"\n"
+  tell "    exit 1\n"
+  tell "fi\n"
+  tell "\n"
+  tell "run_cmd cat \"$BUILDDIR/cabal/config\"\n"
+  tell "\n"
+  tell "# Version\n"
+  tell "##############################################################################\n"
+  tell "\n"
+  tell "put_info \"Versions\"\n"
+  tell "run_cmd $HC --version\n"
+  tell "run_cmd_unchecked $HC --print-project-git-commit-id\n"
+  tell "run_cmd $CABAL --version\n"
+  tell "\n"
+  tell "# Build script\n"
+  tell "##############################################################################\n"
+  tell "\n"
+  tell "# update cabal index\n"
+  tell "if $CABAL_UPDATE; then\n"
+  tell "    put_info \"Updating Hackage index\"\n"
+  tell "    run_cmd $CABAL v2-update -v\n"
+  tell "fi\n"
+  tell "\n"
+  tell "# install cabal-plan\n"
+  tell "install_cabalplan\n"
+  tell "run_cmd cabal-plan --version\n"
+  tell "\n"
+  forM_ (zBlocks z_root) $ \z_var0_block -> do
+    tell z_var0_block
+    tell "\n"
+  tell "\n"
+  tell "# Done\n"
+  tell "run_cmd echo OK\n"
diff --git a/src/HaskellCI/Cli.hs b/src/HaskellCI/Cli.hs
--- a/src/HaskellCI/Cli.hs
+++ b/src/HaskellCI/Cli.hs
@@ -5,8 +5,9 @@
 
 import HaskellCI.Prelude
 
-import System.Exit (exitFailure)
-import System.IO   (hPutStrLn, stderr)
+import System.Exit           (exitFailure)
+import System.FilePath.Posix (takeFileName)
+import System.IO             (hPutStrLn, stderr)
 
 import qualified Options.Applicative as O
 
@@ -20,6 +21,8 @@
 
 data Command
     = CommandTravis FilePath
+    | CommandBash FilePath
+    | CommandGitHub FilePath
     | CommandRegenerate
     | CommandListGHC
     | CommandDumpConfig
@@ -32,20 +35,22 @@
 
 data Options = Options
     { optOutput         :: Maybe Output
-    , optConfig         :: Maybe FilePath
+    , optConfig         :: ConfigOpt
+    , optCwd            :: Maybe FilePath
+    , optInputType      :: Maybe InputType
     , optConfigMorphism :: Config -> Config
     }
 
-data Output = OutputStdout | OutputFile FilePath
-
 instance Semigroup Options where
-    Options b d e <> Options b' d' e' =
-        Options (b <|> b') (d <|> d') (e' . e)
+    Options b d c e f <> Options b' d' c' e' f' =
+        Options (b <|> b') (d <> d') (c <|> c') (e <|> e') (f' . f)
 
 defaultOptions :: Options
 defaultOptions = Options
     { optOutput         = Nothing
-    , optConfig         = Nothing
+    , optConfig         = ConfigOptAuto
+    , optCwd            = Nothing
+    , optInputType      = Nothing
     , optConfigMorphism = id
     }
 
@@ -54,19 +59,55 @@
     { optOutput = Just (OutputFile fp)
     }
 
+data Output = OutputStdout | OutputFile FilePath
+
+data ConfigOpt
+    = ConfigOptAuto
+    | ConfigOpt FilePath
+    | ConfigOptNo
+  deriving (Eq, Show)
+
+instance Semigroup ConfigOpt where
+    a <> ConfigOptAuto = a
+    _ <> b             = b
+
 -------------------------------------------------------------------------------
+-- InputType
+-------------------------------------------------------------------------------
+
+data InputType
+    = InputTypePackage -- ^ @.cabal@
+    | InputTypeProject -- ^ @cabal.project
+  deriving Show
+
+optInputType' :: Options -> FilePath -> InputType
+optInputType' opts path =
+    fromMaybe def (optInputType opts)
+  where
+    def | "cabal.project" `isPrefixOf` takeFileName path = InputTypeProject
+        | otherwise                                      = InputTypePackage
+
+-------------------------------------------------------------------------------
 -- Parsers
 -------------------------------------------------------------------------------
 
 optionsP :: O.Parser Options
 optionsP = Options
     <$> O.optional outputP
-    <*> O.optional (O.strOption (O.long "config" <> O.metavar "CONFIGFILE" <> O.help "Configuration file"))
+    <*> configOptP
+    <*> O.optional (O.strOption (O.long "cwd" <> O.metavar "Dir" <> O.action "directory" <> O.help "Directory to change to"))
+    <*> O.optional inputTypeP
     <*> runOptparseGrammar configGrammar
 
+configOptP :: O.Parser ConfigOpt
+configOptP = file <|> noconfig <|> pure ConfigOptAuto
+  where
+    file = ConfigOpt <$> O.strOption (O.long "config" <> O.metavar "CONFIGFILE" <> O.action "file" <> O.help "Configuration file")
+    noconfig = O.flag' ConfigOptNo (O.long "no-config" <> O.help "Don't read configuration file")
+
 outputP :: O.Parser Output
 outputP =
-    OutputFile <$> O.strOption (O.long "output" <> O.short 'o' <> O.metavar "FILE" <> O.help "Output file") <|>
+    OutputFile <$> O.strOption (O.long "output" <> O.short 'o' <> O.metavar "FILE" <> O.action "file" <> O.help "Output file") <|>
     O.flag' OutputStdout (O.long "stdout" <> O.help "Use stdout output")
 
 versionP :: O.Parser (a -> a)
@@ -76,6 +117,11 @@
     , O.help "Print version information"
     ]
 
+inputTypeP :: O.Parser InputType
+inputTypeP = pkg <|> prj where
+    pkg = O.flag' InputTypePackage $ O.long "package"
+    prj = O.flag' InputTypeProject $ O.long "project"
+
 cliParserInfo :: O.ParserInfo (Command, Options)
 cliParserInfo = O.info ((,) <$> cmdP <*> optionsP O.<**> versionP O.<**> O.helper) $ mconcat
     [ O.fullDesc
@@ -83,28 +129,41 @@
     ]
   where
     cmdP = O.subparser (mconcat
-        [ O.command "regenerate"   $ O.info (pure CommandRegenerate)  $ O.progDesc "Regenerate .travis.yml"
+        [ O.command "regenerate"   $ O.info (pure CommandRegenerate)  $ O.progDesc "Regenerate outputs"
         , O.command "travis"       $ O.info travisP                   $ O.progDesc "Generate travis-ci config"
+        , O.command "bash"         $ O.info bashP                     $ O.progDesc "Generate local-bash-docker script"
+        , O.command "github"       $ O.info githubP                   $ O.progDesc "Generate GitHub Actions config"
         , O.command "list-ghc"     $ O.info (pure CommandListGHC)     $ O.progDesc "List known GHC versions"
         , O.command "dump-config"  $ O.info (pure CommandDumpConfig)  $ O.progDesc "Dump cabal.haskell-ci config with default values"
         , O.command "version-info" $ O.info (pure CommandVersionInfo) $ O.progDesc "Print versions info haskell-ci was compiled with"
         ]) <|> travisP
 
     travisP = CommandTravis
-        <$> O.strArgument (O.metavar "CABAL.FILE" <> O.help "Either <pkg.cabal> or cabal.project")
+        <$> O.strArgument (O.metavar "CABAL.FILE" <> O.action "file" <> O.help "Either <pkg.cabal> or cabal.project")
 
+    bashP = CommandBash
+        <$> O.strArgument (O.metavar "CABAL.FILE" <> O.action "file" <> O.help "Either <pkg.cabal> or cabal.project")
+
+    githubP = CommandGitHub
+        <$> O.strArgument (O.metavar "CABAL.FILE" <> O.action "file" <> O.help "Either <pkg.cabal> or cabal.project")
+
 -------------------------------------------------------------------------------
 -- Parsing helpers
 -------------------------------------------------------------------------------
 
-parseTravis :: [String] -> IO (FilePath, Options)
-parseTravis argv = case res of
-    O.Success x -> return x
+parseOptions :: [String] -> IO (FilePath, Options)
+parseOptions argv = case res of
+    O.Success (cmd, opts) -> do
+        path <- fromCmd cmd
+        return (path, opts)
     O.Failure f -> case O.renderFailure f "haskell-ci" of
         (help, _) -> hPutStrLn stderr help >> exitFailure
     O.CompletionInvoked _ -> exitFailure -- unexpected
   where
-    res = O.execParserPure (O.prefs mempty) (O.info ((,) <$> cmdP <*> optionsP) mempty) argv
-    cmdP = O.strArgument (O.metavar "CABAL.FILE" <> O.help "Either <pkg.cabal> or cabal.project")
-
+    res = O.execParserPure (O.prefs O.subparserInline) cliParserInfo argv
 
+    fromCmd :: Command -> IO FilePath
+    fromCmd (CommandTravis fp) = return fp
+    fromCmd (CommandBash fp)   = return fp
+    fromCmd (CommandGitHub fp) = return fp
+    fromCmd cmd                = fail $ "Command without filepath: " ++ show cmd
diff --git a/src/HaskellCI/Compiler.hs b/src/HaskellCI/Compiler.hs
--- a/src/HaskellCI/Compiler.hs
+++ b/src/HaskellCI/Compiler.hs
@@ -114,7 +114,8 @@
     , [8,4,1],  [8,4,2], [8,4,3], [8,4,4]
     , [8,6,1],  [8,6,2], [8,6,3], [8,6,4], [8,6,5]
     , [8,8,1],  [8,8,2], [8,8,3], [8,8,4]
-    , [8,10,1], [8,10,2]
+    , [8,10,1], [8,10,2], [8,10,3], [8,10,4]
+    , [9,0,1]
     ]
 
 knownGhcjsVersions :: [Version]
@@ -137,7 +138,7 @@
     -> Maybe Version
 correspondingCabalVersion Nothing   _         = Nothing
 correspondingCabalVersion (Just _)  GHCHead   = Nothing
-correspondingCabalVersion (Just _)  (GHCJS _) = Just (mkVersion [3,0])
+correspondingCabalVersion (Just _)  (GHCJS _) = Just (mkVersion [3,4])
 correspondingCabalVersion (Just cv) (GHC gv)
     | gv >= mkVersion [8,10] = Just $ max (mkVersion [3,2]) cv
     | otherwise              = Just $ max (mkVersion [3,0]) cv
diff --git a/src/HaskellCI/Config.hs b/src/HaskellCI/Config.hs
--- a/src/HaskellCI/Config.hs
+++ b/src/HaskellCI/Config.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE ConstraintKinds       #-}
 {-# LANGUAGE DataKinds             #-}
 {-# LANGUAGE FlexibleInstances     #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
@@ -18,7 +19,6 @@
 import qualified Distribution.FieldGrammar       as C
 import qualified Distribution.Fields             as C
 import qualified Distribution.Parsec             as C
-import qualified Distribution.Parsec.Newtypes    as C
 import qualified Distribution.Pretty             as C
 import qualified Distribution.Types.PackageName  as C
 import qualified Distribution.Types.Version      as C
@@ -27,6 +27,7 @@
 
 import HaskellCI.Config.ConstraintSet
 import HaskellCI.Config.CopyFields
+import HaskellCI.Config.Docspec
 import HaskellCI.Config.Doctest
 import HaskellCI.Config.Folds
 import HaskellCI.Config.HLint
@@ -40,7 +41,7 @@
 import HaskellCI.TestedWith
 
 defaultHeadHackage :: VersionRange
-defaultHeadHackage = C.orLaterVersion (C.mkVersion [8,11])
+defaultHeadHackage = C.orLaterVersion (C.mkVersion [9,1])
 
 -- TODO: split other blocks like DoctestConfig
 data Config = Config
@@ -63,10 +64,12 @@
     , cfgHeadHackage         :: !VersionRange
     , cfgGhcjsTests          :: !Bool
     , cfgGhcjsTools          :: ![C.PackageName]
+    , cfgTestOutputDirect    :: !Bool
     , cfgCheck               :: !Bool
     , cfgOnlyBranches        :: [String]
     , cfgIrcChannels         :: [String]
-    , cfgEmailNotifications  :: Bool 
+    , cfgIrcIfInOriginRepo   :: Bool
+    , cfgEmailNotifications  :: Bool
     , cfgProjectName         :: Maybe String
     , cfgFolds               :: S.Set Fold
     , cfgGhcHead             :: !Bool
@@ -78,18 +81,21 @@
     , cfgOsx                 :: S.Set Version
     , cfgApt                 :: S.Set String
     , cfgTravisPatches       :: [FilePath]
+    , cfgGitHubPatches       :: [FilePath]
     , cfgInsertVersion       :: !Bool
     , cfgErrorMissingMethods :: !PackageScope
     , cfgDoctest             :: !DoctestConfig
+    , cfgDocspec             :: !DocspecConfig
     , cfgHLint               :: !HLintConfig
     , cfgConstraintSets      :: [ConstraintSet]
     , cfgRawProject          :: [C.PrettyField ()]
     , cfgRawTravis           :: !String
+    , cfgGitHubActionName    :: !(Maybe String)
     }
   deriving (Generic)
 
 defaultCabalInstallVersion :: Maybe Version
-defaultCabalInstallVersion = Just (C.mkVersion [3,2])
+defaultCabalInstallVersion = Just (C.mkVersion [3,4])
 
 emptyConfig :: Config
 emptyConfig = Config
@@ -98,21 +104,9 @@
     , cfgUbuntu          = Xenial
     , cfgTestedWith      = TestedWithUniform
     , cfgCopyFields      = CopyFieldsSome
-    , cfgDoctest         = DoctestConfig
-        { cfgDoctestEnabled       = noVersion
-        , cfgDoctestOptions       = []
-        , cfgDoctestVersion       = defaultDoctestVersion
-        , cfgDoctestFilterEnvPkgs = []
-        , cfgDoctestFilterSrcPkgs = []
-        }
-    , cfgHLint = HLintConfig
-        { cfgHLintEnabled  = False
-        , cfgHLintJob      = HLintJobLatest
-        , cfgHLintYaml     = Nothing
-        , cfgHLintVersion  = defaultHLintVersion
-        , cfgHLintOptions  = []
-        , cfgHLintDownload = True
-        }
+    , cfgDoctest         = defaultDoctestConfig
+    , cfgDocspec         = defaultDocspecConfig
+    , cfgHLint           = defaultHLintConfig
     , cfgLocalGhcOptions = []
     , cfgConstraintSets  = []
     , cfgSubmodules      = False
@@ -128,9 +122,11 @@
     , cfgHeadHackage     = defaultHeadHackage
     , cfgGhcjsTests      = False
     , cfgGhcjsTools      = []
+    , cfgTestOutputDirect = True
     , cfgCheck           = True
     , cfgOnlyBranches    = []
     , cfgIrcChannels     = []
+    , cfgIrcIfInOriginRepo  = False
     , cfgEmailNotifications = True
     , cfgProjectName     = Nothing
     , cfgFolds           = S.empty
@@ -143,9 +139,11 @@
     , cfgOsx             = S.empty
     , cfgApt             = S.empty
     , cfgTravisPatches   = []
+    , cfgGitHubPatches   = []
     , cfgInsertVersion   = True
     , cfgRawProject      = []
     , cfgRawTravis       = ""
+    , cfgGitHubActionName = Nothing
     , cfgErrorMissingMethods = PackageScopeLocal
     }
 
@@ -154,7 +152,18 @@
 -------------------------------------------------------------------------------
 
 configGrammar
-    :: (OptionsGrammar g, Applicative (g Config), Applicative (g DoctestConfig), Applicative (g HLintConfig))
+    :: ( OptionsGrammar c g, Applicative (g Config)
+       , c (Identity HLintJob)
+       , c (Identity PackageScope)
+       , c (Identity TestedWithJobs)
+       , c (Identity Ubuntu)
+       , c (Identity Jobs)
+       , c (Identity CopyFields)
+       , c Env, c Folds, c CopyFields, c HeadVersion
+       , c (C.List C.FSep (Identity Installed) Installed)
+       , Applicative (g DoctestConfig)
+       , Applicative (g DocspecConfig)
+       , Applicative (g HLintConfig))
     => g Config Config
 configGrammar = Config
     <$> C.optionalFieldDefAla "cabal-install-version"     HeadVersion                         (field @"cfgCabalInstallVersion") defaultCabalInstallVersion
@@ -195,12 +204,16 @@
         ^^^ help "Run tests with GHCJS (experimental, relies on cabal-plan finding test-suites)"
     <*> C.monoidalFieldAla    "ghcjs-tools"               (C.alaList C.FSep)                  (field @"cfgGhcjsTools")
 --        ^^^ metahelp "TOOL" "Additional host tools to install with GHCJS"
+    <*> C.booleanFieldDef "test-output-direct"                                                (field @"cfgTestOutputDirect") True
+        ^^^ help "Use --test-show-details=direct, may cause problems with build-type: Custom"
     <*> C.booleanFieldDef "cabal-check"                                                       (field @"cfgCheck") True
         ^^^ help "Disable cabal check run"
     <*> C.monoidalFieldAla    "branches"                  (C.alaList' C.FSep C.Token')        (field @"cfgOnlyBranches")
         ^^^ metahelp "BRANCH" "Enable builds only for specific branches"
     <*> C.monoidalFieldAla    "irc-channels"              (C.alaList' C.FSep C.Token')        (field @"cfgIrcChannels")
         ^^^ metahelp "IRC" "Enable IRC notifications to given channel (e.g. 'irc.freenode.org#haskell-lens')"
+    <*> C.booleanFieldDef     "irc-if-in-origin-repo"                                         (field @"cfgIrcIfInOriginRepo") False
+        ^^^ help "Only send IRC notifications if run from the original remote (GitHub Actions only)"
     <*> C.booleanFieldDef "email-notifications"                                               (field @"cfgEmailNotifications") True
         ^^^ help "Disable email notifications"
     <*> C.optionalFieldAla    "project-name"              C.Token'                            (field @"cfgProjectName")
@@ -224,17 +237,22 @@
     <*> C.monoidalFieldAla    "apt"                       (alaSet' C.NoCommaFSep C.Token')    (field @"cfgApt")
         ^^^ metahelp "PKG" "Additional apt packages to install"
     <*> C.monoidalFieldAla    "travis-patches"            (C.alaList' C.NoCommaFSep C.Token') (field @"cfgTravisPatches")
-        ^^^ metahelp "PATCH" ".patch files to apply to the generated Travis YAML file"
+        ^^^ metaActionHelp "PATCH" "file" ".patch files to apply to the generated Travis YAML file"
+    <*> C.monoidalFieldAla    "github-patches"            (C.alaList' C.NoCommaFSep C.Token') (field @"cfgGitHubPatches")
+        ^^^ metaActionHelp "PATCH" "file" ".patch files to apply to the generated GitHub Actions YAML file"
     <*> C.booleanFieldDef "insert-version"                                                    (field @"cfgInsertVersion") True
         ^^^ help "Don't insert the haskell-ci version into the generated Travis YAML file"
     <*> C.optionalFieldDef "error-missing-methods"                                            (field @"cfgErrorMissingMethods") PackageScopeLocal
         ^^^ metahelp "PKGSCOPE" "Insert -Werror=missing-methods for package scope (none, local, all)"
     <*> C.blurFieldGrammar (field @"cfgDoctest") doctestConfigGrammar
+    <*> C.blurFieldGrammar (field @"cfgDocspec") docspecConfigGrammar
     <*> C.blurFieldGrammar (field @"cfgHLint")   hlintConfigGrammar
     <*> pure [] -- constraint sets
     <*> pure [] -- raw project fields
     <*> C.freeTextFieldDef "raw-travis"                                                       (field @"cfgRawTravis")
         ^^^ help "Raw travis commands which will be run at the very end of the script"
+    <*> C.freeTextField "github-action-name"                                                  (field @"cfgGitHubActionName")
+        ^^^ help "The name of GitHub Action"
 
 -------------------------------------------------------------------------------
 -- Reading
@@ -247,7 +265,7 @@
 parseConfigFile fields0 = do
     config <- C.parseFieldGrammar C.cabalSpecLatest fields configGrammar
     config' <- traverse parseSection $ concat sections
-    return (foldr (.) id config' config)
+    return (foldl' (&) config config')
   where
     (fields, sections) = C.partitionFields fields0
 
diff --git a/src/HaskellCI/Config/ConstraintSet.hs b/src/HaskellCI/Config/ConstraintSet.hs
--- a/src/HaskellCI/Config/ConstraintSet.hs
+++ b/src/HaskellCI/Config/ConstraintSet.hs
@@ -6,9 +6,9 @@
 import HaskellCI.Prelude
 
 import qualified Distribution.FieldGrammar    as C
-import qualified Distribution.Parsec.Newtypes as C
 
 import HaskellCI.Newtypes
+import HaskellCI.OptionsGrammar
 
 data ConstraintSet = ConstraintSet
     { csName        :: String
@@ -16,25 +16,28 @@
     , csConstraints :: [String] -- we parse these simply as strings
     , csTests       :: Bool
     , csRunTests    :: Bool
+    , csDocspec     :: Bool
     , csBenchmarks  :: Bool
     , csHaddock     :: Bool
     }
   deriving (Show, Generic)
 
 emptyConstraintSet :: String -> ConstraintSet
-emptyConstraintSet n = ConstraintSet n anyVersion [] False False False False
+emptyConstraintSet n = ConstraintSet n anyVersion [] False False False False False
 
 -------------------------------------------------------------------------------
 -- Grammar
 -------------------------------------------------------------------------------
 
 constraintSetGrammar
-    :: (C.FieldGrammar g, Applicative (g ConstraintSet))
+    :: ( OptionsGrammar c g, Applicative (g ConstraintSet)
+       )
     => String -> g ConstraintSet ConstraintSet
 constraintSetGrammar name = ConstraintSet name
     <$> C.optionalFieldDef "ghc"                                           (field @"csGhcVersions") anyVersion
     <*> C.monoidalFieldAla "constraints" (C.alaList' C.CommaVCat NoCommas) (field @"csConstraints")
     <*> C.booleanFieldDef  "tests"                                         (field @"csTests") False
     <*> C.booleanFieldDef  "run-tests"                                     (field @"csRunTests") False
+    <*> C.booleanFieldDef  "docspec"                                       (field @"csDocspec") False
     <*> C.booleanFieldDef  "benchmarks"                                    (field @"csBenchmarks") False
     <*> C.booleanFieldDef  "haddock"                                       (field @"csHaddock") False
diff --git a/src/HaskellCI/Config/Docspec.hs b/src/HaskellCI/Config/Docspec.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellCI/Config/Docspec.hs
@@ -0,0 +1,47 @@
+{-# LANGUAGE DataKinds         #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TypeApplications  #-}
+module HaskellCI.Config.Docspec where
+
+import HaskellCI.Prelude
+
+import qualified Distribution.FieldGrammar    as C
+
+import HaskellCI.OptionsGrammar
+
+data DocspecConfig = DocspecConfig
+    { cfgDocspecEnabled :: !VersionRange
+    , cfgDocspecOptions :: [String]
+    , cfgDocspecUrl     :: String
+    , cfgDocspecHash    :: String
+    }
+  deriving (Show, Generic, Binary)
+
+-------------------------------------------------------------------------------
+-- Default
+-------------------------------------------------------------------------------
+
+defaultDocspecConfig :: DocspecConfig
+defaultDocspecConfig = DocspecConfig
+    { cfgDocspecEnabled = noVersion
+    , cfgDocspecOptions = []
+    , cfgDocspecUrl     = "https://github.com/phadej/cabal-extras/releases/download/cabal-docspec-0.0.0.20210111/cabal-docspec-0.0.0.20210111.xz"
+    , cfgDocspecHash    = "0829bd034fba901cbcfe491d98ed8b28fd54f9cb5c91fa8e1ac62dc4413c9562"
+    }
+
+-------------------------------------------------------------------------------
+-- Grammar
+-------------------------------------------------------------------------------
+
+docspecConfigGrammar
+    :: (OptionsGrammar c g, Applicative (g DocspecConfig))
+    => g DocspecConfig DocspecConfig
+docspecConfigGrammar = DocspecConfig
+    <$> rangeField            "docspec"                                              (field @"cfgDocspecEnabled") noVersion
+        ^^^ help "Enable Docspec job"
+    <*> C.monoidalFieldAla    "docspec-options" (C.alaList' C.NoCommaFSep C.Token')  (field @"cfgDocspecOptions")
+        ^^^ metahelp "OPTS" "Additional Docspec options"
+    <*> C.optionalFieldDefAla "docspec-url"      C.Token'                            (field @"cfgDocspecUrl") (cfgDocspecUrl defaultDocspecConfig)
+        ^^^ metahelp "URL" "URL to download cabal-docspec"
+    <*> C.optionalFieldDefAla "docspec-hash"     C.Token'                            (field @"cfgDocspecHash") (cfgDocspecHash defaultDocspecConfig)
+        ^^^ metahelp "HASH" "SHA256 of cabal-docspec"
diff --git a/src/HaskellCI/Config/Doctest.hs b/src/HaskellCI/Config/Doctest.hs
--- a/src/HaskellCI/Config/Doctest.hs
+++ b/src/HaskellCI/Config/Doctest.hs
@@ -8,7 +8,6 @@
 import Distribution.Version (majorBoundVersion)
 
 import qualified Distribution.FieldGrammar      as C
-import qualified Distribution.Parsec.Newtypes   as C
 import qualified Distribution.Types.PackageName as C
 
 import HaskellCI.OptionsGrammar
@@ -20,17 +19,30 @@
     , cfgDoctestFilterEnvPkgs :: ![C.PackageName]
     , cfgDoctestFilterSrcPkgs :: ![C.PackageName]
     }
-  deriving (Show, Generic)
+  deriving (Show, Generic, Binary)
 
+-------------------------------------------------------------------------------
+-- Default
+-------------------------------------------------------------------------------
+
 defaultDoctestVersion :: VersionRange
 defaultDoctestVersion = majorBoundVersion (mkVersion [0,17])
 
+defaultDoctestConfig :: DoctestConfig
+defaultDoctestConfig = DoctestConfig
+    { cfgDoctestEnabled       = noVersion
+    , cfgDoctestOptions       = []
+    , cfgDoctestVersion       = defaultDoctestVersion
+    , cfgDoctestFilterEnvPkgs = []
+    , cfgDoctestFilterSrcPkgs = []
+    }
+
 -------------------------------------------------------------------------------
 -- Grammar
 -------------------------------------------------------------------------------
 
 doctestConfigGrammar
-    :: (OptionsGrammar g, Applicative (g DoctestConfig))
+    :: (OptionsGrammar c g, Applicative (g DoctestConfig))
     => g DoctestConfig DoctestConfig
 doctestConfigGrammar = DoctestConfig
     <$> rangeField         "doctest"                                              (field @"cfgDoctestEnabled") noVersion
diff --git a/src/HaskellCI/Config/Dump.hs b/src/HaskellCI/Config/Dump.hs
--- a/src/HaskellCI/Config/Dump.hs
+++ b/src/HaskellCI/Config/Dump.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE FunctionalDependencies  #-}
 module HaskellCI.Config.Dump where
 
 import HaskellCI.Prelude
@@ -18,7 +19,7 @@
     pure _ = DG []
     DG f <*> DG x = DG (f ++ x)
 
-instance C.FieldGrammar DumpGrammar where
+instance C.FieldGrammar C.Pretty DumpGrammar where
     blurFieldGrammar _ = coerce
 
     uniqueFieldAla _ _ _ = DG []
@@ -65,7 +66,7 @@
     removedIn _ _        = id
     hiddenField          = id
 
-instance OptionsGrammar DumpGrammar where
+instance OptionsGrammar C.Pretty DumpGrammar where
     metahelp _ = help
 
     help h (DG xs) = DG $
diff --git a/src/HaskellCI/Config/HLint.hs b/src/HaskellCI/Config/HLint.hs
--- a/src/HaskellCI/Config/HLint.hs
+++ b/src/HaskellCI/Config/HLint.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE ConstraintKinds   #-}
 {-# LANGUAGE DataKinds         #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE TypeApplications  #-}
@@ -10,7 +11,6 @@
 import qualified Distribution.Compat.CharParsing as C
 import qualified Distribution.FieldGrammar       as C
 import qualified Distribution.Parsec             as C
-import qualified Distribution.Parsec.Newtypes    as C
 import qualified Distribution.Pretty             as C
 import qualified Text.PrettyPrint                as PP
 
@@ -24,11 +24,25 @@
     , cfgHLintVersion  :: !VersionRange
     , cfgHLintDownload :: !Bool
     }
-  deriving (Show, Generic)
+  deriving (Show, Generic, Binary)
 
+-------------------------------------------------------------------------------
+-- Default
+-------------------------------------------------------------------------------
+
 defaultHLintVersion :: VersionRange
-defaultHLintVersion = withinVersion (mkVersion [3,1])
+defaultHLintVersion = withinVersion (mkVersion [3,2])
 
+defaultHLintConfig :: HLintConfig
+defaultHLintConfig = HLintConfig
+    { cfgHLintEnabled  = False
+    , cfgHLintJob      = HLintJobLatest
+    , cfgHLintYaml     = Nothing
+    , cfgHLintVersion  = defaultHLintVersion
+    , cfgHLintOptions  = []
+    , cfgHLintDownload = True
+    }
+
 -------------------------------------------------------------------------------
 -- HLintJob
 -------------------------------------------------------------------------------
@@ -36,7 +50,7 @@
 data HLintJob
     = HLintJobLatest    -- ^ run with latest GHC
     | HLintJob Version  -- ^ run with specified GHC version
-  deriving (Eq, Show)
+  deriving (Eq, Show, Generic, Binary)
 
 instance C.Parsec HLintJob where
     parsec = HLintJobLatest <$ C.string "latest"
@@ -51,7 +65,7 @@
 -------------------------------------------------------------------------------
 
 hlintConfigGrammar
-    :: (OptionsGrammar g, Applicative (g HLintConfig))
+    :: (OptionsGrammar c g, Applicative (g HLintConfig), c (Identity HLintJob))
     => g HLintConfig HLintConfig
 hlintConfigGrammar = HLintConfig
     <$> C.booleanFieldDef  "hlint"                                             (field @"cfgHLintEnabled") False
@@ -59,7 +73,7 @@
     <*> C.optionalFieldDef "hlint-job"                                         (field @"cfgHLintJob") HLintJobLatest
         ^^^ metahelp "JOB" "Specify HLint job"
     <*> C.optionalFieldAla "hlint-yaml"    C.FilePathNT                        (field @"cfgHLintYaml")
-        ^^^ metahelp "PATH" "Use specific .hlint.yaml"
+        ^^^ metaActionHelp "PATH" "file" "Use specific .hlint.yaml"
     <*> C.monoidalFieldAla "hlint-options" (C.alaList' C.NoCommaFSep C.Token') (field @"cfgHLintOptions")
         ^^^ metahelp "OPTS" "Additional HLint options"
     <*> C.optionalFieldDef "hlint-version"                                     (field @"cfgHLintVersion") defaultHLintVersion
diff --git a/src/HaskellCI/Config/Ubuntu.hs b/src/HaskellCI/Config/Ubuntu.hs
--- a/src/HaskellCI/Config/Ubuntu.hs
+++ b/src/HaskellCI/Config/Ubuntu.hs
@@ -6,7 +6,7 @@
 import qualified Distribution.Pretty as C
 import qualified Text.PrettyPrint    as PP
 
-data Ubuntu = Xenial | Bionic
+data Ubuntu = Xenial | Bionic | Focal
   deriving (Eq, Ord, Show)
 
 instance C.Parsec Ubuntu where
@@ -15,6 +15,7 @@
         case t of
             "xenial" -> return Xenial
             "bionic" -> return Bionic
+            "focal"  -> return Focal
             _        -> fail $ "Unknown ubuntu release " ++ t
 
 instance C.Pretty Ubuntu where
@@ -23,3 +24,4 @@
 showUbuntu :: Ubuntu -> String
 showUbuntu Xenial = "xenial"
 showUbuntu Bionic = "bionic"
+showUbuntu Focal  = "focal"
diff --git a/src/HaskellCI/GitConfig.hs b/src/HaskellCI/GitConfig.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellCI/GitConfig.hs
@@ -0,0 +1,57 @@
+{-# LANGUAGE OverloadedStrings #-}
+module HaskellCI.GitConfig (
+    GitConfig (..),
+    emptyGitConfig,
+    readGitConfig,
+) where
+
+import HaskellCI.Prelude
+
+import Data.Ini
+
+import qualified Data.Attoparsec.Text as Atto
+import qualified Data.Map.Strict      as Map
+
+newtype GitConfig = GitConfig
+    { gitCfgRemotes :: Map.Map Text Text
+    }
+  deriving Show
+
+emptyGitConfig :: GitConfig
+emptyGitConfig = GitConfig
+    { gitCfgRemotes = mempty
+    }
+
+-- | Read 'GitConfig'. On error, return 'emptyGitConfg'.
+readGitConfig :: IO GitConfig
+readGitConfig = handle fallback $ do
+    e <- readIniFile ".git/config"
+    return $ case e of
+        Left _    -> emptyGitConfig
+        Right ini -> elaborateGitConfig ini
+  where
+    fallback :: IOException -> IO GitConfig
+    fallback _ = return emptyGitConfig
+
+elaborateGitConfig :: Ini -> GitConfig
+elaborateGitConfig ini = ifoldr go emptyGitConfig (iniSections ini) where
+    go :: Text -> [(Text, Text)] -> GitConfig -> GitConfig
+    go secname secfields cfg
+        | Right name <- Atto.parseOnly (sectionP <* Atto.endOfInput) secname
+        , Just url   <- lookup "url" secfields
+        = cfg
+            { gitCfgRemotes = Map.insert name url (gitCfgRemotes cfg)
+            }
+
+    go _ _ cfg = cfg
+
+-- We use attoparsec here, because it backtracks
+sectionP :: Atto.Parser Text
+sectionP = do
+    _ <- Atto.string "remote"
+    Atto.skipSpace
+    _ <- Atto.char '"'
+    remote <- Atto.takeWhile (/= '"')
+    _ <- Atto.char '"'
+    return remote
+    
diff --git a/src/HaskellCI/GitHub.hs b/src/HaskellCI/GitHub.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellCI/GitHub.hs
@@ -0,0 +1,747 @@
+{-# LANGUAGE NamedFieldPuns    #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards   #-}
+module HaskellCI.GitHub (
+    makeGitHub,
+    githubHeader,
+) where
+
+import HaskellCI.Prelude
+
+import Control.Applicative (optional)
+
+import qualified Crypto.Hash.SHA256              as SHA256
+import qualified Data.Attoparsec.Text            as Atto
+import qualified Data.Binary                     as Binary
+import qualified Data.Binary.Put                 as Binary
+import qualified Data.ByteString.Base16          as Base16
+import qualified Data.ByteString.Char8           as BS8
+import qualified Data.Map.Strict                 as Map
+import qualified Data.Set                        as S
+import qualified Data.Text                       as T
+import qualified Distribution.Fields.Pretty      as C
+import qualified Distribution.Package            as C
+import qualified Distribution.Pretty             as C
+import qualified Distribution.Types.VersionRange as C
+import qualified Distribution.Version            as C
+
+import Cabal.Project
+import HaskellCI.Auxiliary
+import HaskellCI.Compiler
+import HaskellCI.Config
+import HaskellCI.Config.ConstraintSet
+import HaskellCI.Config.Docspec
+import HaskellCI.Config.Doctest
+import HaskellCI.Config.HLint
+import HaskellCI.Config.Installed
+import HaskellCI.Config.PackageScope
+import HaskellCI.GitConfig
+import HaskellCI.GitHub.Yaml
+import HaskellCI.HeadHackage
+import HaskellCI.Jobs
+import HaskellCI.List
+import HaskellCI.Package
+import HaskellCI.Sh
+import HaskellCI.ShVersionRange
+import HaskellCI.Tools
+import HaskellCI.VersionInfo
+
+-- $setup
+-- >>> :set -XOverloadedStrings
+
+-------------------------------------------------------------------------------
+-- GitHub header
+-------------------------------------------------------------------------------
+
+githubHeader :: Bool -> [String] -> [String]
+githubHeader insertVersion argv =
+    [ "This GitHub workflow config has been generated by a script via"
+    , ""
+    , "  haskell-ci " ++ unwords [ "'" ++ a ++ "'" | a <- argv ]
+    , ""
+    , "To regenerate the script (for example after adjusting tested-with) run"
+    , ""
+    , "  haskell-ci regenerate"
+    , ""
+    , "For more information, see https://github.com/haskell-CI/haskell-ci"
+    , ""
+    ] ++
+    verlines ++
+    [ "REGENDATA " ++ if insertVersion then show (haskellCIVerStr, argv) else show argv
+    , ""
+    ]
+  where
+    verlines
+        | insertVersion = [ "version: " ++ haskellCIVerStr , "" ]
+        | otherwise     = []
+
+-------------------------------------------------------------------------------
+-- GitHub
+-------------------------------------------------------------------------------
+
+{-
+GitHub Actions–specific notes:
+
+* We use -j2 for parallelism, as GitHub's virtual machines use 2 cores, per
+  https://docs.github.com/en/free-pro-team@latest/actions/reference/specifications-for-github-hosted-runners#supported-runners-and-hardware-resources.
+-}
+
+makeGitHub
+    :: [String]
+    -> Config
+    -> GitConfig
+    -> Project URI Void Package
+    -> JobVersions
+    -> Either ShError GitHub
+makeGitHub _argv config@Config {..} gitconfig prj jobs@JobVersions {..} = do
+    let envEnv = Map.fromList
+            [ ("CC", "${{ matrix.compiler }}")
+            ]
+
+    steps <- sequence $ buildList $ do
+        -- This have to be first, since the packages we install depend on
+        -- whether we need GHCJS or not.
+        when anyGHCJS $ githubRun' "Set GHCJS environment variables" envEnv $ sh $ intercalate "\n"
+            [ "if echo $CC | grep -q ghcjs; then"
+            , tell_env' "GHCJS" "true"
+            , tell_env' "GHCJSARITH" "1"
+            , "else"
+            , tell_env' "GHCJS" "false"
+            , tell_env' "GHCJSARITH" "0"
+            , "fi"
+            ]
+
+        githubRun' "apt" envEnv $ do
+            sh "apt-get update"
+            sh "apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common"
+            sh "apt-add-repository -y 'ppa:hvr/ghc'"
+            when anyGHCJS $ do
+                sh_if RangeGHCJS "apt-add-repository -y 'ppa:hvr/ghcjs'"
+                sh_if RangeGHCJS "curl -sSL \"https://deb.nodesource.com/gpgkey/nodesource.gpg.key\" | apt-key add -"
+                sh_if RangeGHCJS "apt-add-repository -y 'deb https://deb.nodesource.com/node_10.x bionic main'" -- TODO: Use cfgUbuntu
+            sh "apt-get update"
+            let basePackages  = ["$CC", "cabal-install-" ++ cabalVer] ++ S.toList cfgApt
+                ghcjsPackages = ["ghc-8.4.4", "nodejs"]
+                baseInstall   = "apt-get install -y " ++ unwords basePackages
+                ghcjsInstall  = "apt-get install -y " ++ unwords (basePackages ++ ghcjsPackages)
+            if anyGHCJS
+                then if_then_else RangeGHCJS ghcjsInstall baseInstall
+                else sh baseInstall
+
+        githubRun' "Set PATH and environment variables" envEnv $ do
+            echo_to "$GITHUB_PATH" "$HOME/.cabal/bin"
+
+            -- Hack: happy needs ghc. Let's install version matching GHCJS.
+            -- At the moment, there is only GHCJS-8.4, so we install GHC-8.4.4
+            when anyGHCJS $
+                echo_if_to RangeGHCJS "$GITHUB_PATH" "/opt/ghc/8.4.4/bin"
+
+            tell_env "LANG" "C.UTF-8"
+
+            tell_env "CABAL_DIR"    "$HOME/.cabal"
+            tell_env "CABAL_CONFIG" "$HOME/.cabal/config"
+
+            let hcdir = "$(echo \"/opt/$CC\" | sed 's/-/\\//')"
+            sh ("HCDIR=" ++ hcdir)
+
+            if_then_else RangeGHCJS
+                "HCNAME=ghcjs"
+                "HCNAME=ghc"
+
+            let hc = "$HCDIR/bin/$HCNAME"
+            sh ("HC=" ++ hc)
+            tell_env "HC" "$HC"
+            tell_env "HCPKG" (hc ++ "-pkg")
+            tell_env "HADDOCK" "$HCDIR/bin/haddock"
+
+            -- TODO: configurable cabal version
+            tell_env "CABAL" $ "/opt/cabal/" ++ cabalVer ++ "/bin/cabal -vnormal+nowrap"
+
+            sh "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')"
+            tell_env "HCNUMVER" "$HCNUMVER"
+
+            if_then_else (Range cfgTests)
+                (tell_env' "ARG_TESTS" "--enable-tests")
+                (tell_env' "ARG_TESTS" "--disable-tests")
+            if_then_else (Range cfgBenchmarks)
+                (tell_env' "ARG_BENCH" "--enable-benchmarks")
+                (tell_env' "ARG_BENCH" "--disable-benchmarks")
+            if_then_else (Range cfgHeadHackage \/ RangePoints (S.singleton GHCHead))
+                (tell_env' "HEADHACKAGE" "true")
+                (tell_env' "HEADHACKAGE" "false")
+
+            tell_env "ARG_COMPILER" "--$HCNAME --with-compiler=$HC"
+
+            unless anyGHCJS $
+                tell_env "GHCJSARITH" "0"
+
+        githubRun "env" $ do
+            sh "env"
+
+        githubRun "write cabal config" $ do
+            sh "mkdir -p $CABAL_DIR"
+            cat "$CABAL_CONFIG" $ unlines
+                [ "remote-build-reporting: anonymous"
+                , "write-ghc-environment-files: never"
+                , "remote-repo-cache: $CABAL_DIR/packages"
+                , "logs-dir:          $CABAL_DIR/logs"
+                , "world-file:        $CABAL_DIR/world"
+                , "extra-prog-path:   $CABAL_DIR/bin"
+                , "symlink-bindir:    $CABAL_DIR/bin"
+                , "installdir:        $CABAL_DIR/bin"
+                , "build-summary:     $CABAL_DIR/logs/build.log"
+                , "store-dir:         $CABAL_DIR/store"
+                , "install-dirs user"
+                , "  prefix: $CABAL_DIR"
+                , "repository hackage.haskell.org"
+                , "  url: http://hackage.haskell.org/"
+                ]
+
+            -- Add head.hackage repository to ~/.cabal/config
+            -- (locally you want to add it to cabal.project)
+            unless (S.null headGhcVers) $ sh $ concat $
+                [ "if $HEADHACKAGE; then\n"
+                , catCmd "$CABAL_CONFIG" $ unlines headHackageRepoStanza
+                , "\nfi"
+                ]
+
+            sh "cat $CABAL_CONFIG"
+
+        githubRun "versions" $ do
+            sh "$HC --version || true"
+            sh "$HC --print-project-git-commit-id || true"
+            sh "$CABAL --version || true"
+            when anyGHCJS $ do
+                sh_if RangeGHCJS "node --version"
+                sh_if RangeGHCJS "echo $GHCJS"
+
+        githubRun "update cabal index" $ do
+            sh "$CABAL v2-update -v"
+
+        let toolsConfigHash :: String
+            toolsConfigHash = take 8 $ BS8.unpack $ Base16.encode $ SHA256.hashlazy $ Binary.runPut $ do
+                Binary.put cfgDoctest
+                Binary.put cfgHLint
+
+        when (doctestEnabled || cfgHLintEnabled cfgHLint) $ githubUses "cache (tools)" "actions/cache@v2"
+            [ ("key", "${{ runner.os }}-${{ matrix.compiler }}-tools-" ++ toolsConfigHash)
+            , ("path", "~/.haskell-ci-tools")
+            ]
+
+        githubRun "install cabal-plan" $ do
+            sh "mkdir -p $HOME/.cabal/bin"
+            sh "curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > cabal-plan.xz"
+            sh "echo 'de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc  cabal-plan.xz' | sha256sum -c -"
+            sh "xz -d < cabal-plan.xz > $HOME/.cabal/bin/cabal-plan"
+            sh "rm -f cabal-plan.xz"
+            sh "chmod a+x $HOME/.cabal/bin/cabal-plan"
+            sh "cabal-plan --version"
+
+        when anyGHCJS $ githubRun "install happy" $ do
+            for_ cfgGhcjsTools $ \t ->
+                sh_if RangeGHCJS $ "$CABAL v2-install -w ghc-8.4.4 --ignore-project -j2" ++ C.prettyShow t
+
+        when docspecEnabled $ githubRun "install cabal-docspec" $ do
+            let hash = cfgDocspecHash cfgDocspec
+                url  = cfgDocspecUrl cfgDocspec
+            sh "mkdir -p $HOME/.cabal/bin"
+            sh $ "curl -sL " ++ url ++ " > cabal-docspec.xz"
+            sh $ "echo '" ++ hash ++ "  cabal-docspec.xz' | sha256sum -c -"
+            sh "xz -d < cabal-docspec.xz > $HOME/.cabal/bin/cabal-docspec"
+            sh "rm -f cabal-docspec.xz"
+            sh "chmod a+x $HOME/.cabal/bin/cabal-docspec"
+            sh "cabal-docspec --version"
+
+        when doctestEnabled $ githubRun "install doctest" $ do
+            let range = Range (cfgDoctestEnabled cfgDoctest) /\ doctestJobVersionRange
+            sh_if range "$CABAL --store-dir=$HOME/.haskell-ci-tools/store v2-install $ARG_COMPILER --ignore-project -j2 doctest --constraint='doctest ^>=0.17'"
+            sh_if range "doctest --version"
+
+        let hlintVersionConstraint
+                | C.isAnyVersion (cfgHLintVersion cfgHLint) = ""
+                | otherwise = " --constraint='hlint " ++ prettyShow (cfgHLintVersion cfgHLint) ++ "'"
+        when (cfgHLintEnabled cfgHLint) $ githubRun "install hlint" $ do
+            let forHLint = sh_if (hlintJobVersionRange versions cfgHeadHackage (cfgHLintJob cfgHLint))
+            if cfgHLintDownload cfgHLint
+            then do
+                -- install --dry-run and use perl regex magic to find a hlint version
+                -- -v is important
+                forHLint $ "HLINTVER=$(cd /tmp && (${CABAL} v2-install -v $ARG_COMPILER --dry-run hlint " ++ hlintVersionConstraint ++ " |  perl -ne 'if (/\\bhlint-(\\d+(\\.\\d+)*)\\b/) { print \"$1\"; last; }')); echo \"HLint version $HLINTVER\""
+                forHLint $ "if [ ! -e $HOME/.haskell-ci-tools/hlint-$HLINTVER/hlint ]; then " ++ unwords
+                    [ "echo \"Downloading HLint version $HLINTVER\";"
+                    , "mkdir -p $HOME/.haskell-ci-tools;"
+                    , "curl --write-out 'Status Code: %{http_code} Redirects: %{num_redirects} Total time: %{time_total} Total Dsize: %{size_download}\\n' --silent --location --output $HOME/.haskell-ci-tools/hlint-$HLINTVER.tar.gz \"https://github.com/ndmitchell/hlint/releases/download/v$HLINTVER/hlint-$HLINTVER-x86_64-linux.tar.gz\";"
+                    , "tar -xzv -f $HOME/.haskell-ci-tools/hlint-$HLINTVER.tar.gz -C $HOME/.haskell-ci-tools;"
+                    , "fi"
+                    ]
+                forHLint "mkdir -p $CABAL_DIR/bin && ln -sf \"$HOME/.haskell-ci-tools/hlint-$HLINTVER/hlint\" $CABAL_DIR/bin/hlint"
+                forHLint "hlint --version"
+
+            else do
+                forHLint $ "$CABAL --store-dir=$HOME/.haskell-ci-tools/store v2-install $ARG_COMPILER --ignore-project -j2 hlint" ++ hlintVersionConstraint
+                forHLint "hlint --version"
+
+        githubUses "checkout" "actions/checkout@v2"
+            [ ("path", "source")
+            ]
+
+        githubRun "initial cabal.project for sdist" $do
+            sh "touch cabal.project"
+            for_ pkgs $ \pkg ->
+                echo_if_to (RangePoints $ pkgJobs pkg) "cabal.project" $ "packages: $GITHUB_WORKSPACE/source/" ++ pkgDir pkg
+            sh "cat cabal.project"
+
+        githubRun "sdist" $ do
+            sh "mkdir -p sdist"
+            sh "$CABAL sdist all --output-dir $GITHUB_WORKSPACE/sdist"
+
+        githubRun "unpack" $ do
+            sh "mkdir -p unpacked"
+            sh "find sdist -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C $GITHUB_WORKSPACE/unpacked -xzvf {} \\;"
+
+        githubRun "generate cabal.project" $ do
+            for_ pkgs $ \Pkg{pkgName} -> do
+                sh $ pkgNameDirVariable' pkgName ++ "=\"$(find \"$GITHUB_WORKSPACE/unpacked\" -maxdepth 1 -type d -regex '.*/" ++ pkgName ++ "-[0-9.]*')\""
+                tell_env (pkgNameDirVariable' pkgName) (pkgNameDirVariable pkgName)
+
+            sh "touch cabal.project"
+            sh "touch cabal.project.local"
+
+            for_ pkgs $ \pkg ->
+                echo_if_to (RangePoints $ pkgJobs pkg) "cabal.project" $ "packages: " ++ pkgNameDirVariable (pkgName pkg)
+
+            -- per package options
+            case cfgErrorMissingMethods of
+                PackageScopeNone  -> pure ()
+                PackageScopeLocal -> for_ pkgs $ \Pkg{pkgName,pkgJobs} -> do
+                    let range = Range (C.orLaterVersion (C.mkVersion [8,2])) /\ RangePoints pkgJobs
+                    echo_if_to range "cabal.project" $ "package " ++ pkgName
+                    echo_if_to range "cabal.project" $ "    ghc-options: -Werror=missing-methods"
+                PackageScopeAll   -> cat "cabal.project" $ unlines
+                    [ "package *"
+                    , "  ghc-options: -Werror=missing-methods"
+                    ]
+
+            -- extra cabal.project fields
+            cat "cabal.project" $ C.showFields' (const []) (const id) 2 extraCabalProjectFields
+
+            -- If using head.hackage, allow building with newer versions of GHC boot libraries.
+            -- Note that we put this in a cabal.project file, not ~/.cabal/config, in order to avoid
+            -- https://github.com/haskell/cabal/issues/7291.
+            unless (S.null headGhcVers) $ sh $ concat $
+                [ "if $HEADHACKAGE; then\n"
+                , "echo \"allow-newer: $($HCPKG list --simple-output | sed -E 's/([a-zA-Z-]+)-[0-9.]+/*:\\1,/g')\" >> cabal.project\n"
+                , "fi"
+                ]
+
+            -- also write cabal.project.local file with
+            -- @
+            -- constraints: base installed
+            -- constraints: array installed
+            -- ...
+            --
+            -- omitting any local package names
+            case normaliseInstalled cfgInstalled of
+                InstalledDiff pns -> sh $ unwords
+                    [ "$HCPKG list --simple-output --names-only"
+                    , "| perl -ne 'for (split /\\s+/) { print \"constraints: $_ installed\\n\" unless /" ++ re ++ "/; }'"
+                    , ">> cabal.project.local"
+                    ]
+                  where
+                    pns' = S.map C.unPackageName pns `S.union` foldMap (S.singleton . pkgName) pkgs
+                    re = "^(" ++ intercalate "|" (S.toList pns') ++ ")$"
+
+                InstalledOnly pns | not (null pns') -> cat "cabal.project.local" $ unlines
+                    [ "constraints: " ++ pkg ++ " installed"
+                    | pkg <- S.toList pns'
+                    ]
+                  where
+                    pns' = S.map C.unPackageName pns `S.difference` foldMap (S.singleton . pkgName) pkgs
+
+                -- otherwise: nothing
+                _ -> pure ()
+
+            sh "cat cabal.project"
+            sh "cat cabal.project.local"
+
+        githubRun "dump install plan" $ do
+            sh "$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all"
+            sh "cabal-plan"
+
+        -- This a hack. https://github.com/actions/cache/issues/109
+        -- Hashing Java - Maven style.
+        githubUses "cache" "actions/cache@v2"
+            [ ("key", "${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}")
+            , ("restore-keys", "${{ runner.os }}-${{ matrix.compiler }}-")
+            , ("path", "~/.cabal/store")
+            ]
+
+        -- install dependencies
+        when cfgInstallDeps $ githubRun "install dependencies" $ do
+            sh "$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j2 all"
+            sh "$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j2 all"
+
+        -- build w/o tests benchs
+        unless (equivVersionRanges C.noVersion cfgNoTestsNoBench) $ githubRun "build w/o tests" $ do
+            sh "$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all"
+
+        -- build
+        githubRun "build" $ do
+            sh "$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --write-ghc-environment-files=always"
+
+        -- tests
+        githubRun "tests" $ do
+            let range = RangeGHC /\ Range (cfgTests /\ cfgRunTests) /\ hasTests
+            sh_if range $ "$CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all" ++ testShowDetails
+
+            when (anyGHCJS && cfgGhcjsTests) $ sh $ unlines $
+                [ "pkgdir() {"
+                , "  case $1 in"
+                ] ++
+                [ "    " ++ pkgName ++ ") echo " ++ pkgNameDirVariable pkgName ++ " ;;"
+                | Pkg{pkgName} <- pkgs
+                ] ++
+                [ "  esac"
+                , "}"
+                ]
+
+            when cfgGhcjsTests $ sh_if (RangeGHCJS /\ hasTests) $ unwords
+                [ "cabal-plan list-bins '*:test:*' | while read -r line; do"
+                , "testpkg=$(echo \"$line\" | perl -pe 's/:.*//');"
+                , "testexe=$(echo \"$line\" | awk '{ print $2 }');"
+                , "echo \"testing $textexe in package $textpkg\";"
+                , "(cd \"$(pkgdir $testpkg)\" && nodejs \"$testexe\".jsexe/all.js);"
+                , "done"
+                ]
+
+        -- doctest
+        when doctestEnabled $ githubRun "doctest" $ do
+            let doctestOptions = unwords $ cfgDoctestOptions cfgDoctest
+
+            unless (null $ cfgDoctestFilterEnvPkgs cfgDoctest) $ do
+                -- cabal-install mangles unit ids on the OSX,
+                -- removing the vowels to make filepaths shorter
+                let manglePkgNames :: String -> [String]
+                    manglePkgNames n
+                        | null cfgOsx = [n]
+                        | otherwise   = [n, filter notVowel n]
+                      where
+                        notVowel c = notElem c ("aeiou" :: String)
+                let filterPkgs = intercalate "|" $ concatMap (manglePkgNames . C.unPackageName) $ cfgDoctestFilterEnvPkgs cfgDoctest
+                sh $ "perl -i -e 'while (<ARGV>) { print unless /package-id\\s+(" ++ filterPkgs ++ ")-\\d+(\\.\\d+)*/; }' .ghc.environment.*"
+
+            for_ pkgs $ \Pkg{pkgName,pkgGpd,pkgJobs} ->
+                when (C.mkPackageName pkgName `notElem` cfgDoctestFilterSrcPkgs cfgDoctest) $ do
+                    for_ (doctestArgs pkgGpd) $ \args -> do
+                        let args' = unwords args
+                        let vr = Range (cfgDoctestEnabled cfgDoctest)
+                              /\ doctestJobVersionRange
+                              /\ RangePoints pkgJobs
+
+                        unless (null args) $ do
+                            change_dir_if vr $ pkgNameDirVariable pkgName
+                            sh_if vr $ "doctest " ++ doctestOptions ++ " " ++ args'
+
+        -- docspec
+        when docspecEnabled $ githubRun "docspec" $ do
+            -- docspec doesn't work with non-GHC (i.e. GHCJS)
+            let docspecRange' = docspecRange /\ RangeGHC
+            -- we need to rebuild, if tests screwed something.
+            sh_if docspecRange' "$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all"
+            sh_if docspecRange' cabalDocspec
+
+        -- hlint
+        when (cfgHLintEnabled cfgHLint) $ githubRun "hlint" $ do
+            let "" <+> ys = ys
+                xs <+> "" = xs
+                xs <+> ys = xs ++ " " ++ ys
+
+                prependSpace "" = ""
+                prependSpace xs = " " ++ xs
+
+            let hlintOptions = prependSpace $ maybe "" ("-h ${GITHUB_WORKSPACE}/source/" ++) (cfgHLintYaml cfgHLint) <+> unwords (cfgHLintOptions cfgHLint)
+
+            for_ pkgs $ \Pkg{pkgName,pkgGpd,pkgJobs} -> do
+                for_ (hlintArgs pkgGpd) $ \args -> do
+                    let args' = unwords args
+                    unless (null args) $
+                        sh_if (hlintJobVersionRange versions cfgHeadHackage (cfgHLintJob cfgHLint) /\ RangePoints pkgJobs) $
+                        "(cd " ++ pkgNameDirVariable pkgName ++ " && hlint" ++ hlintOptions ++ " " ++ args' ++ ")"
+
+        -- cabal check
+        when cfgCheck $ githubRun "cabal check" $ do
+            for_ pkgs $ \Pkg{pkgName,pkgJobs} -> do
+                let range = RangePoints pkgJobs
+                change_dir_if range $ pkgNameDirVariable pkgName
+                sh_if range "${CABAL} -vnormal check"
+
+        -- haddock
+        when (hasLibrary && not (equivVersionRanges C.noVersion cfgHaddock)) $ githubRun "haddock" $ do
+            let range = RangeGHC /\ Range cfgHaddock
+            sh_if range "$CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all"
+
+        -- unconstrained build
+        unless (equivVersionRanges C.noVersion cfgUnconstrainted) $ githubRun "unconstrained build" $ do
+            let range = Range cfgUnconstrainted
+            sh_if range "rm -f cabal.project.local"
+            sh_if range "$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all"
+
+        -- constraint sets
+        unless (null cfgConstraintSets) $ githubRun "prepare for constraint sets" $ do
+            sh "rm -f cabal.project.local"
+
+        for_ cfgConstraintSets $ \cs -> githubRun ("constraint set " ++ csName cs) $ do
+            let sh_cs           = sh_if (Range (csGhcVersions cs))
+            let sh_cs' r        = sh_if (Range (csGhcVersions cs) /\ r)
+            let testFlag        = if csTests cs then "--enable-tests" else "--disable-tests"
+            let benchFlag       = if csBenchmarks cs then "--enable-benchmarks" else "--disable-benchmarks"
+            let constraintFlags = map (\x ->  "--constraint='" ++ x ++ "'") (csConstraints cs)
+            let allFlags        = unwords (testFlag : benchFlag : constraintFlags)
+
+            sh_cs $ "$CABAL v2-build $ARG_COMPILER " ++ allFlags ++ " all"
+            when (docspecEnabled && csDocspec cs) $
+                sh_cs' docspecRange cabalDocspec
+            when (csRunTests cs) $
+                sh_cs' hasTests $ "$CABAL v2-test $ARG_COMPILER " ++ allFlags ++ " all"
+            when (hasLibrary && csHaddock cs) $
+                sh_cs $ "$CABAL v2-haddock $ARG_COMPILER " ++ withHaddock ++ " " ++ allFlags ++ " all"
+
+    -- assembling everything
+    return GitHub
+        { ghName = actionName
+        , ghOn = GitHubOn
+            { ghBranches = cfgOnlyBranches
+            }
+        , ghJobs = Map.fromList $ buildList $ do
+            item (mainJobName, GitHubJob
+                { ghjName            = actionName ++ " - Linux - ${{ matrix.compiler }}"
+                , ghjRunsOn          = "ubuntu-18.04" -- TODO: use cfgUbuntu
+                , ghjNeeds           = []
+                , ghjSteps           = steps
+                , ghjIf              = Nothing
+                , ghjContainer       = Just "buildpack-deps:bionic" -- use cfgUbuntu?
+                , ghjContinueOnError = Just "${{ matrix.allow-failure }}"
+                , ghjServices        = mconcat
+                    [ Map.singleton "postgres" postgresService | cfgPostgres ]
+                , ghjMatrix          =
+                    [ GitHubMatrixEntry
+                        { ghmeCompiler = compiler
+                        , ghmeAllowFailure =
+                               previewGHC cfgHeadHackage compiler
+                            || maybeGHC False (`C.withinRange` cfgAllowFailures) compiler
+                        }
+                    | compiler <- reverse $ toList versions
+                    , compiler /= GHCHead -- TODO: Make this work
+                                          -- https://github.com/haskell-CI/haskell-ci/issues/458
+                    ]
+                })
+            unless (null cfgIrcChannels) $
+                ircJob actionName mainJobName projectName config gitconfig
+        }
+  where
+    actionName  = fromMaybe "Haskell-CI" cfgGitHubActionName
+    mainJobName = "linux"
+
+    cabalVer = dispCabalVersion cfgCabalInstallVersion
+
+    Auxiliary {..} = auxiliary config prj jobs
+
+    anyGHCJS = any isGHCJS versions
+
+    -- GHC versions which need head.hackage
+    headGhcVers :: Set CompilerVersion
+    headGhcVers = S.filter (previewGHC cfgHeadHackage) versions
+
+    -- step primitives
+    githubRun' :: String -> Map.Map String String ->  ShM () -> ListBuilder (Either ShError GitHubStep) ()
+    githubRun' name env shm = item $ do
+        shs <- runSh shm
+        return $ GitHubStep name $ Left $ GitHubRun shs env
+
+    githubRun :: String -> ShM () -> ListBuilder (Either ShError GitHubStep) ()
+    githubRun name = githubRun' name mempty
+
+
+    githubUses :: String -> String -> [(String, String)] -> ListBuilder (Either ShError GitHubStep) ()
+    githubUses name action with = item $ return $
+        GitHubStep name $ Right $ GitHubUses action Nothing (Map.fromList with)
+
+    -- shell primitives
+    echo_to' :: FilePath -> String -> String
+    echo_to' fp s = "echo " ++ show s ++ " >> " ++ fp
+
+    echo_to :: FilePath -> String -> ShM ()
+    echo_to fp s = sh $ echo_to' fp s
+
+    echo_if_to :: CompilerRange -> FilePath -> String -> ShM ()
+    echo_if_to range fp s = sh_if range $ echo_to' fp s
+
+    change_dir_if :: CompilerRange -> String -> ShM ()
+    change_dir_if range dir = sh_if range ("cd " ++ dir ++ " || false")
+
+    tell_env' :: String -> String -> String
+    tell_env' k v = "echo " ++ show (k ++ "=" ++ v) ++ " >> $GITHUB_ENV"
+
+    tell_env :: String -> String -> ShM ()
+    tell_env k v = sh $ tell_env' k v
+
+    if_then_else :: CompilerRange -> String -> String -> ShM ()
+    if_then_else range con alt
+        | all (`compilerWithinRange` range) versions       = sh con
+        | not $ any (`compilerWithinRange` range) versions = sh alt
+        | otherwise = sh $ unwords
+        [ "if ["
+        , compilerVersionArithPredicate versions range
+        , "-ne 0 ]"
+        , "; then"
+        , con
+        , ";"
+        , "else"
+        , alt
+        , ";"
+        , "fi"
+        ]
+
+    sh_if :: CompilerRange -> String -> ShM ()
+    sh_if range con
+        | all (`compilerWithinRange` range) versions       = sh con
+        | not $ any (`compilerWithinRange` range) versions = pure ()
+        | otherwise = sh $ unwords
+        [ "if ["
+        , compilerVersionArithPredicate versions range
+        , "-ne 0 ]"
+        , "; then"
+        , con
+        , ";"
+        , "fi"
+        ]
+
+    -- Needed to work around haskell/cabal#6214
+    withHaddock :: String
+    withHaddock = "--with-haddock $HADDOCK"
+
+    cabalDocspec :: String
+    cabalDocspec =
+      let docspecOptions = cfgDocspecOptions cfgDocspec in
+      unwords $ "cabal-docspec $ARG_COMPILER" : docspecOptions
+
+    docspecRange :: CompilerRange
+    docspecRange = Range (cfgDocspecEnabled cfgDocspec)
+
+postgresService :: GitHubService
+postgresService = GitHubService
+    { ghServImage   = "postgres:10"
+    , ghServOptions = Just "--health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5"
+    , ghServEnv     = Map.fromList
+          [ ("POSTGRES_PASSWORD", "postgres")
+          ]
+    }
+
+ircJob :: String -> String -> String -> Config -> GitConfig -> ListBuilder (String, GitHubJob) ()
+ircJob actionName mainJobName projectName cfg gitconfig = item ("irc", GitHubJob
+    { ghjName            = actionName ++ " (IRC notification)"
+    , ghjRunsOn          = "ubuntu-18.04"
+    , ghjNeeds           = [mainJobName]
+    , ghjIf              = jobCondition
+    , ghjContainer       = Nothing
+    , ghjContinueOnError = Nothing
+    , ghjMatrix          = []
+    , ghjServices        = mempty
+    , ghjSteps           = [ ircStep serverChannelName success
+                           | serverChannelName <- serverChannelNames
+                           , success <- [True, False]
+                           ]
+    })
+  where
+    serverChannelNames = cfgIrcChannels cfg
+
+    jobCondition :: Maybe String
+    jobCondition
+        | cfgIrcIfInOriginRepo cfg
+        , Just url <- Map.lookup "origin" (gitCfgRemotes gitconfig)
+        , Just repo <- parseGitHubRepo url
+
+        = Just
+        $ "${{ always() && (github.repository == '" ++ T.unpack repo ++ "') }}"
+
+        | otherwise
+        = Just "${{ always() }}"
+        -- Use always() above to ensure that the IRC job will still run even if
+        -- the build job itself fails (see #437).
+
+    ircStep :: String -> Bool -> GitHubStep
+    ircStep serverChannelName success =
+        let (serverName, channelName) = break (== '#') serverChannelName
+
+            result | success   = "success"
+                   | otherwise = "failure"
+
+            resultPastTense | success   = "succeeded"
+                            | otherwise = "failed"
+
+            eqCheck | success   = "=="
+                    | otherwise = "!=" in
+
+        GitHubStep ("IRC " ++ result ++ " notification (" ++ serverChannelName ++ ")") $ Right $
+        GitHubUses "Gottox/irc-message-action@v1.1"
+                   (Just $ "needs." ++ mainJobName ++ ".result " ++ eqCheck ++ " 'success'") $
+        Map.fromList
+            [ ("server",   serverName)
+            , ("channel",  channelName)
+            , ("nickname", "github-actions")
+            , ("message",  "\x0313" ++ projectName ++ "\x03/\x0306${{ github.ref }}\x03 "
+                                    ++ "\x0314${{ github.sha }}\x03 "
+                                    ++ "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} "
+                                    ++ "The build " ++ resultPastTense ++ ".")
+            ]
+
+catCmd :: FilePath -> String -> String
+catCmd path contents = concat
+    [ "cat >> " ++ path ++ " <<EOF\n"
+    , contents
+    , "EOF"
+    ]
+
+cat :: FilePath -> String -> ShM ()
+cat path contents = sh $ catCmd path contents
+
+-- | GitHub is very lenient and undocumented. We accept something.
+-- Please, write a patch, if you need an extra scheme to be accepted.
+--
+-- >>> parseGitHubRepo "git@github.com:haskell-CI/haskell-ci.git"
+-- Just "haskell-CI/haskell-ci"
+--
+-- >>> parseGitHubRepo "git@github.com:haskell-CI/haskell-ci"
+-- Just "haskell-CI/haskell-ci"
+--
+-- >>> parseGitHubRepo "https://github.com/haskell-CI/haskell-ci.git"
+-- Just "haskell-CI/haskell-ci"
+--
+-- >>> parseGitHubRepo "https://github.com/haskell-CI/haskell-ci"
+-- Just "haskell-CI/haskell-ci"
+--
+-- >>> parseGitHubRepo "git://github.com/haskell-CI/haskell-ci"
+-- Just "haskell-CI/haskell-ci"
+--
+parseGitHubRepo :: Text -> Maybe Text
+parseGitHubRepo t =
+    either (const Nothing) Just $ Atto.parseOnly (parser <* Atto.endOfInput) t
+  where
+    parser :: Atto.Parser Text
+    parser = sshP <|> httpsP
+
+    sshP :: Atto.Parser Text
+    sshP = do
+        _ <- optional (Atto.string "git://")
+        _ <- Atto.string "git@github.com:"
+        repo <- Atto.takeWhile (/= '.')
+        _ <- optional (Atto.string ".git")
+        return repo
+
+    httpsP :: Atto.Parser Text
+    httpsP = do
+        _ <- Atto.string "https" <|> Atto.string "git"
+        _ <- Atto.string "://github.com/"
+        repo <- Atto.takeWhile (/= '.')
+        _ <- optional (Atto.string ".git")
+        return repo
diff --git a/src/HaskellCI/GitHub/Yaml.hs b/src/HaskellCI/GitHub/Yaml.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellCI/GitHub/Yaml.hs
@@ -0,0 +1,169 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards   #-}
+{-# LANGUAGE StrictData        #-}
+module HaskellCI.GitHub.Yaml where
+
+import HaskellCI.Prelude
+
+import qualified Data.Map.Strict as M
+
+import HaskellCI.Compiler
+import HaskellCI.List
+import HaskellCI.Sh
+import HaskellCI.YamlSyntax
+
+-------------------------------------------------------------------------------
+-- Data
+-------------------------------------------------------------------------------
+
+data GitHub = GitHub
+    { ghName :: String
+    , ghOn   :: GitHubOn
+    , ghJobs :: M.Map String GitHubJob
+    }
+  deriving (Show)
+
+newtype GitHubOn = GitHubOn
+    { ghBranches :: [String]
+    }
+  deriving (Show)
+
+data GitHubJob = GitHubJob
+    { ghjName            :: String
+    , ghjRunsOn          :: String
+    , ghjNeeds           :: [String]
+    , ghjIf              :: Maybe String
+    , ghjContainer       :: Maybe String
+    , ghjServices        :: M.Map String GitHubService
+    , ghjContinueOnError :: Maybe String
+    , ghjMatrix          :: [GitHubMatrixEntry]
+    , ghjSteps           :: [GitHubStep]
+    }
+  deriving (Show)
+
+data GitHubMatrixEntry = GitHubMatrixEntry
+    { ghmeCompiler     :: CompilerVersion
+    , ghmeAllowFailure :: Bool
+    }
+  deriving (Show)
+
+data GitHubStep = GitHubStep
+    { ghsName :: String
+    , ghsStep :: Either GitHubRun GitHubUses
+    }
+  deriving (Show)
+
+-- | Steps with @run@
+data GitHubRun = GitHubRun
+    { ghsRun :: [Sh]
+    , ghsEnv :: M.Map String String
+    }
+  deriving (Show)
+
+-- | Steps with @uses@
+data GitHubUses = GitHubUses
+    { ghsAction :: String
+    , ghsIf     :: Maybe String
+    , ghsWith   :: M.Map String String
+    }
+  deriving (Show)
+
+data GitHubService = GitHubService
+    { ghServImage   :: String
+    , ghServEnv     :: M.Map String String
+    , ghServOptions :: Maybe String
+    }
+  deriving (Show)
+
+-------------------------------------------------------------------------------
+-- ToYaml
+-------------------------------------------------------------------------------
+
+instance ToYaml GitHub where
+    toYaml GitHub {..} = ykeyValuesFilt []
+        [ "name" ~> fromString ghName
+        , "on"   ~> toYaml ghOn
+        , "jobs" ~> ykeyValuesFilt []
+            [ ([], j, toYaml job)
+            | (j, job) <- M.toList ghJobs
+            ]
+        ]
+
+instance ToYaml GitHubOn where
+    toYaml GitHubOn {..}
+        | null ghBranches
+        = ylistFilt [] ["push", "pull_request"]
+        | otherwise
+        = ykeyValuesFilt []
+              [ "push"         ~> branches
+              , "pull_request" ~> branches
+              ]
+      where
+        branches = ykeyValuesFilt []
+            [ "branches" ~> ylistFilt [] (map fromString ghBranches)
+            ]
+
+instance ToYaml GitHubJob where
+    toYaml GitHubJob {..} = ykeyValuesFilt [] $ buildList $ do
+        item $ "name" ~> fromString ghjName
+        item $ "runs-on" ~> fromString ghjRunsOn
+        item $ "needs" ~> ylistFilt [] (map fromString ghjNeeds)
+        for_ ghjIf $ \if_ ->
+            item $ "if" ~> fromString if_
+        item $ "container" ~> ykeyValuesFilt [] (buildList $
+            for_ ghjContainer $ \image -> item $ "image" ~> fromString image)
+        item $ "services" ~> toYaml ghjServices
+        for_ ghjContinueOnError $ \continueOnError ->
+            item $ "continue-on-error" ~> fromString continueOnError
+        item $ "strategy" ~> ykeyValuesFilt []
+            [ "matrix" ~> ykeyValuesFilt []
+                [ "include" ~> ylistFilt [] (map toYaml ghjMatrix)
+                ]
+            , "fail-fast" ~> YBool [] False
+            ]
+        item $ "steps" ~> ylistFilt [] (map toYaml $ filter notEmptyStep ghjSteps)
+
+instance ToYaml GitHubMatrixEntry where
+    toYaml GitHubMatrixEntry {..} = ykeyValuesFilt []
+        [ "compiler" ~> fromString (dispGhcVersion ghmeCompiler)
+        , "allow-failure" ~> toYaml ghmeAllowFailure
+        ]
+
+instance ToYaml GitHubStep where
+    toYaml GitHubStep {..} = ykeyValuesFilt [] $
+        [ "name" ~> fromString ghsName
+        ] ++ case ghsStep of
+            Left GitHubRun {..} ->
+                [ "run" ~> fromString (shlistToString ghsRun)
+                , "env" ~> mapToYaml ghsEnv
+                ]
+
+            Right GitHubUses {..} -> buildList $ do
+                item $ "uses" ~> fromString ghsAction
+                for_ ghsIf $ \if_ -> item $ "if" ~> fromString if_
+                item $ "with" ~> mapToYaml ghsWith
+
+notEmptyStep :: GitHubStep -> Bool
+notEmptyStep (GitHubStep _ (Left (GitHubRun [] _))) = False
+notEmptyStep _                                      = True
+
+instance ToYaml GitHubService where
+    toYaml GitHubService {..} = ykeyValuesFilt [] $ buildList $ do
+        item $ "image" ~> fromString ghServImage
+        item $ "env"   ~> toYaml (YString [] <$> ghServEnv)
+        for_ ghServOptions $ \opt -> item $ "options" ~> fromString opt
+
+-------------------------------------------------------------------------------
+-- Helpers
+-------------------------------------------------------------------------------
+
+mapToYaml :: M.Map String String -> Yaml [String]
+mapToYaml m = ykeyValuesFilt []
+    [ k ~> fromString v
+    | (k, v) <- M.toList m
+    ]
+
+shlistToString :: [Sh] -> String
+shlistToString shs = unlines (map go shs) where
+    go (Comment c) = "# " ++ c
+    go (Sh x)      = x
diff --git a/src/HaskellCI/HeadHackage.hs b/src/HaskellCI/HeadHackage.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellCI/HeadHackage.hs
@@ -0,0 +1,14 @@
+module HaskellCI.HeadHackage where
+
+import HaskellCI.Prelude
+
+headHackageRepoStanza :: [String]
+headHackageRepoStanza =
+    [ "repository head.hackage.ghc.haskell.org"
+    , "   url: https://ghc.gitlab.haskell.org/head.hackage/"
+    , "   secure: True"
+    , "   root-keys: 7541f32a4ccca4f97aea3b22f5e593ba2c0267546016b992dfadcd2fe944e55d"
+    , "              26021a13b401500c8eb2761ca95c61f2d625bfef951b939a8124ed12ecf07329"
+    , "              f76d08be13e9a61a377a85e2fb63f4c5435d40f8feb3e12eb05905edb8cdea89"
+    , "   key-threshold: 3"
+    ]
diff --git a/src/HaskellCI/Jobs.hs b/src/HaskellCI/Jobs.hs
--- a/src/HaskellCI/Jobs.hs
+++ b/src/HaskellCI/Jobs.hs
@@ -19,9 +19,14 @@
     , omittedOsxVersions :: Set Version
     }
 
-describeJobs :: MonadDiagnostics m => TestedWithJobs -> JobVersions -> [Package] -> m ()
-describeJobs twj JobVersions {..} pkgs = do
-    putStrLnInfo $ "Generating Travis-CI config for testing for GHC versions: " ++ ghcVersions
+describeJobs
+    :: MonadDiagnostics m
+    => String          -- ^ config
+    -> TestedWithJobs
+    -> JobVersions
+    -> [Package] -> m ()
+describeJobs typ twj JobVersions {..} pkgs = do
+    putStrLnInfo $ "Generating " ++ typ ++ " for testing for GHC versions: " ++ ghcVersions
     case twj of
         TestedWithUniform -> pure ()
         TestedWithAny     -> for_ pkgs $ \pkg -> do
diff --git a/src/HaskellCI/Newtypes.hs b/src/HaskellCI/Newtypes.hs
--- a/src/HaskellCI/Newtypes.hs
+++ b/src/HaskellCI/Newtypes.hs
@@ -4,15 +4,15 @@
 
 import HaskellCI.Prelude
 
-import qualified Data.Set                        as S
-import qualified Distribution.Compat.CharParsing as C
-import qualified Distribution.Compat.Newtype     as C
-import qualified Distribution.Parsec             as C
-import qualified Distribution.Parsec.Newtypes    as C
-import qualified Distribution.Pretty             as C
-import qualified Distribution.Types.Version      as C
-import qualified Distribution.Types.VersionRange as C
-import qualified Text.PrettyPrint                as PP
+import qualified Data.Set                           as S
+import qualified Distribution.Compat.CharParsing    as C
+import qualified Distribution.Compat.Newtype        as C
+import qualified Distribution.FieldGrammar.Newtypes as C
+import qualified Distribution.Parsec                as C
+import qualified Distribution.Pretty                as C
+import qualified Distribution.Types.Version         as C
+import qualified Distribution.Types.VersionRange    as C
+import qualified Text.PrettyPrint                   as PP
 
 -------------------------------------------------------------------------------
 -- PackageLocation
diff --git a/src/HaskellCI/OptionsGrammar.hs b/src/HaskellCI/OptionsGrammar.hs
--- a/src/HaskellCI/OptionsGrammar.hs
+++ b/src/HaskellCI/OptionsGrammar.hs
@@ -1,26 +1,73 @@
+{-# LANGUAGE ConstraintKinds         #-}
+{-# LANGUAGE FlexibleContexts        #-}
+{-# LANGUAGE FlexibleInstances       #-}
+{-# LANGUAGE FunctionalDependencies  #-}
+{-# LANGUAGE UndecidableInstances    #-}
+{-# LANGUAGE UndecidableSuperClasses #-}
 module HaskellCI.OptionsGrammar (
     OptionsGrammar (..),
     (C.^^^),
-    )  where
+    metaActionHelp,
+    ParsecPretty,
+    Help, MetaVar, BashCompletionAction
+)  where
 
 import HaskellCI.Prelude
 
 import qualified Distribution.Compat.Lens        as C
 import qualified Distribution.FieldGrammar       as C
 import qualified Distribution.Fields             as C
+import qualified Distribution.Parsec             as C
+import qualified Distribution.Pretty             as C
+import qualified Distribution.Types.PackageName  as C
 import qualified Distribution.Types.VersionRange as C
+import qualified Options.Applicative             as O
 
 import HaskellCI.Newtypes
 
-class C.FieldGrammar p => OptionsGrammar p where
-    metahelp :: String -> String -> p s a -> p s a
+-- | Help text for option.
+type Help    = String
+
+-- | Meta variable for option argument.
+type MetaVar = String
+
+-- | Bash completion action for option argument.
+--   Example: @"file"@ or @"directory"@.
+--
+-- See <https://github.com/pcapriotti/optparse-applicative#actions-and-completers>
+-- and <https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion-Builtins.html>.
+type BashCompletionAction = String
+
+class
+    ( C.FieldGrammar c p
+    , c Range, c (Identity C.VersionRange)
+    , c (C.List C.NoCommaFSep C.Token' String)
+    , c (C.List C.FSep C.Token' String)
+    , c (AlaSet C.NoCommaFSep C.Token' String)
+    , c (AlaSet C.NoCommaFSep (Identity Version) Version)
+    , c (C.List C.CommaVCat NoCommas String)
+    , c (C.List C.NoCommaFSep (Identity C.PackageName) C.PackageName)
+    , c (C.List C.FSep (Identity C.PackageName) C.PackageName)
+    )
+    => OptionsGrammar c p | p -> c
+  where
+    metaCompleterHelp :: MetaVar -> O.Completer -> Help -> p s a -> p s a
+    metaCompleterHelp _ _ _ = id
+
+    metahelp :: MetaVar -> Help -> p s a -> p s a
     metahelp _ _ = id
 
-    help :: String -> p s a -> p s a
+    help :: Help -> p s a -> p s a
     help _ = id
 
     -- we treat range fields specially in options
     rangeField :: C.FieldName -> C.ALens' s C.VersionRange -> C.VersionRange -> p s C.VersionRange
     rangeField fn = C.optionalFieldDefAla fn Range
 
-instance OptionsGrammar C.ParsecFieldGrammar
+metaActionHelp :: OptionsGrammar c p => MetaVar -> BashCompletionAction -> Help -> p s a -> p s a
+metaActionHelp m a = metaCompleterHelp m (O.bashCompleter a)
+
+instance OptionsGrammar C.Parsec C.ParsecFieldGrammar
+
+class    (C.Parsec a, C.Pretty a) => ParsecPretty a
+instance (C.Parsec a, C.Pretty a) => ParsecPretty a
diff --git a/src/HaskellCI/OptparseGrammar.hs b/src/HaskellCI/OptparseGrammar.hs
--- a/src/HaskellCI/OptparseGrammar.hs
+++ b/src/HaskellCI/OptparseGrammar.hs
@@ -1,9 +1,11 @@
-{-# LANGUAGE GADTs             #-}
-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE FlexibleInstances     #-}
+{-# LANGUAGE GADTs                 #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverloadedStrings     #-}
 module HaskellCI.OptparseGrammar (
     OptparseGrammar,
     runOptparseGrammar,
-    ) where
+) where
 
 import HaskellCI.Prelude
 
@@ -23,14 +25,14 @@
 import HaskellCI.OptionsGrammar
 
 data SomeParser s where
-    SP :: (Maybe String -> Maybe String -> O.Parser (s -> s)) -> SomeParser s
+    SP :: (Maybe MetaVar -> Maybe O.Completer -> Maybe Help -> O.Parser (s -> s)) -> SomeParser s
 
 newtype OptparseGrammar s a = OG [SomeParser s]
   deriving Functor
 
 runOptparseGrammar :: OptparseGrammar s a -> O.Parser (s -> s)
 runOptparseGrammar (OG ps) = fmap (foldr (flip (.)) id) $ many $ asum
-    [ p Nothing Nothing
+    [ p Nothing Nothing Nothing
     | SP p <- ps
     ]
 
@@ -38,9 +40,9 @@
     pure _ = OG []
     OG f <*> OG x = OG (f ++ x)
 
-instance C.FieldGrammar OptparseGrammar where
+instance C.FieldGrammar ParsecPretty OptparseGrammar where
     blurFieldGrammar l (OG ps) = OG
-        [ SP $ \v h -> fmap (l C.#%~) (p v h)
+        [ SP $ \v c h -> fmap (l C.#%~) (p v c h)
         | SP p <- ps
         ]
 
@@ -49,23 +51,23 @@
 
     -- the non default flag has help entry
     booleanFieldDef fn l def = OG
-        [ SP $ \_m h -> setOG l $ O.flag' True  $ flagMods fn (th h)
-        , SP $ \_m h -> setOG l $ O.flag' False $ flagMods ("no-" <> fn) (fh h)
+        [ SP $ \_m _c h -> setOG l $ O.flag' True  $ flagMods fn (th h)
+        , SP $ \_m _c h -> setOG l $ O.flag' False $ flagMods ("no-" <> fn) (fh h)
         ]
       where
         th h = if def then Nothing else h
         fh h = if def then h else Nothing
 
     optionalFieldAla fn c l = OG
-        [ SP $ \m h -> setOptionalOG l $ O.option (C.unpack' c <$> readMParsec) $ optionMods fn m h ]
+        [ SP $ \m cpl h -> setOptionalOG l $ O.option (C.unpack' c <$> readMParsec) $ optionMods fn m cpl h ]
 
     optionalFieldDefAla fn c l def = OG
-        [ SP $ \m h -> setOG l $ O.option (C.unpack' c <$> readMParsec) $ optionMods fn m (fmap hdef h) ]
+        [ SP $ \m cpl h -> setOG l $ O.option (C.unpack' c <$> readMParsec) $ optionMods fn m cpl (fmap hdef h) ]
       where
         hdef h = h ++ " (Default: " ++ C.prettyShow (C.pack' c def) ++ ")"
 
     monoidalFieldAla fn c l = OG
-        [ SP $ \m h -> monoidOG l $ O.option (C.unpack' c <$> readMParsec) $ optionMods fn m h ]
+        [ SP $ \m cpl h -> monoidOG l $ O.option (C.unpack' c <$> readMParsec) $ optionMods fn m cpl h ]
 
     prefixedFields _ _   = pure []
     knownField _         = pure ()
@@ -75,25 +77,30 @@
     hiddenField          = id
 
     freeTextField fn l = OG
-        [ SP $ \m h -> setOptionalOG l $ O.strOption $ optionMods fn m h ]
+        [ SP $ \m c h -> setOptionalOG l $ O.strOption $ optionMods fn m c h ]
 
     freeTextFieldDef fn l = OG
-        [ SP $ \m h -> setOG l $ O.strOption $ optionMods fn m h ]
+        [ SP $ \m c h -> setOG l $ O.strOption $ optionMods fn m c h ]
 
     freeTextFieldDefST fn l = OG
-        [ SP $ \m h -> setOG l $ O.strOption $ optionMods fn m h ]
+        [ SP $ \m c h -> setOG l $ O.strOption $ optionMods fn m c h ]
 
-instance OptionsGrammar OptparseGrammar where
+instance OptionsGrammar ParsecPretty OptparseGrammar where
     help h (OG ps) = OG
-        [ SP $ \m _h -> p m (Just h)
+        [ SP $ \m c _h -> p m c (Just h)
         | SP p <- ps
         ]
 
     metahelp m h (OG ps) = OG
-        [ SP $ \_m _h -> p (Just m) (Just h)
+        [ SP $ \_m c _h -> p (Just m) c (Just h)
         | SP p <- ps
         ]
 
+    metaCompleterHelp m c h (OG ps) = OG
+        [ SP $ \_m _c _h -> p (Just m) (Just c) (Just h)
+        | SP p <- ps
+        ]
+
     -- example: @rangeField tests #cfgTests anyVersion@, generates options:
     --
     -- --tests
@@ -103,19 +110,21 @@
     -- where the --no-tests has help, because it's not default.
     --
     rangeField fn l def = OG
-        [ SP $ \_m  h -> setOG l $ O.flag' C.anyVersion $ flagMods fn (th h)
-        , SP $ \_m  h -> setOG l $ O.flag' C.noVersion  $ flagMods ("no-" <> fn) (fh h)
-        , SP $ \_m _h -> setOG l $ O.option readMParsec $ O.long (fromUTF8BS $ fn <> "-jobs") <> O.metavar "RANGE"
+        [ SP $ \_m _c  h -> setOG l $ O.flag' C.anyVersion $ flagMods fn (th h)
+        , SP $ \_m _c  h -> setOG l $ O.flag' C.noVersion  $ flagMods ("no-" <> fn) (fh h)
+        , SP $ \_m _c _h -> setOG l $ O.option readMParsec $ O.long (fromUTF8BS $ fn <> "-jobs") <> O.metavar "RANGE"
         ]
       where
         th h = if equivVersionRanges def C.anyVersion then Nothing else h
         fh h = if equivVersionRanges def C.anyVersion then h else Nothing
 
-optionMods :: (O.HasName mods, O.HasMetavar mods) => C.FieldName -> Maybe String -> Maybe String -> O.Mod mods a
-optionMods fn mmetavar mhelp = flagMods fn mhelp
+optionMods :: (O.HasName mods, O.HasCompleter mods, O.HasMetavar mods)
+           => C.FieldName -> Maybe MetaVar -> Maybe O.Completer -> Maybe Help -> O.Mod mods a
+optionMods fn mmetavar mcompl mhelp = flagMods fn mhelp
     <> maybe mempty O.metavar mmetavar
+    <> maybe mempty O.completer mcompl
 
-flagMods :: O.HasName mods => C.FieldName -> Maybe String -> O.Mod mods a
+flagMods :: O.HasName mods => C.FieldName -> Maybe Help -> O.Mod mods a
 flagMods fn mhelp = O.long (fromUTF8BS fn)
     <> maybe mempty O.help mhelp
 
diff --git a/src/HaskellCI/Prelude.hs b/src/HaskellCI/Prelude.hs
--- a/src/HaskellCI/Prelude.hs
+++ b/src/HaskellCI/Prelude.hs
@@ -8,33 +8,36 @@
 
 import Prelude.Compat hiding (head, tail)
 
-import Algebra.Lattice        as X (BoundedJoinSemiLattice (..), BoundedLattice, BoundedMeetSemiLattice (..), Lattice (..))
-import Control.Applicative    as X (liftA2, (<|>))
-import Control.Exception      as X (Exception (..))
-import Control.Monad          as X (ap, unless, void, when)
-import Control.Monad.Catch    as X (MonadCatch, MonadMask, MonadThrow)
-import Control.Monad.IO.Class as X (MonadIO (..))
-import Data.Bifoldable        as X (Bifoldable (..))
-import Data.Bifunctor         as X (Bifunctor (..))
-import Data.Bitraversable     as X (Bitraversable (..), bifoldMapDefault, bimapDefault)
-import Data.ByteString        as X (ByteString)
-import Data.Char              as X (isSpace, isUpper, toLower)
-import Data.Coerce            as X (coerce)
-import Data.Either            as X (partitionEithers)
-import Data.Foldable          as X (for_, toList, traverse_)
-import Data.Function          as X (on)
-import Data.Functor.Compat    as X ((<&>))
-import Data.Functor.Identity  as X (Identity (..))
-import Data.List              as X (foldl', intercalate, isPrefixOf, nub, stripPrefix, tails)
-import Data.List.NonEmpty     as X (NonEmpty (..), groupBy)
-import Data.Maybe             as X (fromMaybe, isJust, isNothing, mapMaybe)
-import Data.Proxy             as X (Proxy (..))
-import Data.Set               as X (Set)
-import Data.String            as X (IsString (fromString))
-import Data.Void              as X (Void)
-import GHC.Generics           as X (Generic)
-import Network.URI            as X (URI, parseURI, uriToString)
-import Text.Read              as X (readMaybe)
+import Algebra.Lattice         as X (BoundedJoinSemiLattice (..), BoundedLattice, BoundedMeetSemiLattice (..), Lattice (..))
+import Control.Applicative     as X (liftA2, (<|>))
+import Control.Exception       as X (Exception (..), IOException, handle)
+import Control.Monad           as X (ap, unless, void, when)
+import Control.Monad.Catch     as X (MonadCatch, MonadMask, MonadThrow)
+import Control.Monad.IO.Class  as X (MonadIO (..))
+import Data.Bifoldable         as X (Bifoldable (..))
+import Data.Bifunctor          as X (Bifunctor (..))
+import Data.Binary             as X (Binary)
+import Data.Bitraversable      as X (Bitraversable (..), bifoldMapDefault, bimapDefault)
+import Data.ByteString         as X (ByteString)
+import Data.Char               as X (isSpace, isUpper, toLower)
+import Data.Coerce             as X (coerce)
+import Data.Either             as X (partitionEithers)
+import Data.Foldable           as X (for_, toList, traverse_)
+import Data.Foldable.WithIndex as X (ifoldr)
+import Data.Function           as X (on)
+import Data.Functor.Compat     as X ((<&>))
+import Data.Functor.Identity   as X (Identity (..))
+import Data.List               as X (foldl', intercalate, isPrefixOf, nub, stripPrefix, tails)
+import Data.List.NonEmpty      as X (NonEmpty (..), groupBy)
+import Data.Maybe              as X (fromMaybe, isJust, isNothing, mapMaybe)
+import Data.Proxy              as X (Proxy (..))
+import Data.Set                as X (Set)
+import Data.String             as X (IsString (fromString))
+import Data.Text               as X (Text)
+import Data.Void               as X (Void)
+import GHC.Generics            as X (Generic)
+import Network.URI             as X (URI, parseURI, uriToString)
+import Text.Read               as X (readMaybe)
 
 import Data.Generics.Lens.Lite  as X (field)
 import Distribution.Compat.Lens as X (over, toListOf, (&), (.~), (^.))
@@ -44,6 +47,8 @@
 import Distribution.Version as X (Version, VersionRange, anyVersion, mkVersion, noVersion)
 
 import qualified Distribution.Version as C
+
+import Data.Functor.WithIndex.Instances ()
 
 -------------------------------------------------------------------------------
 -- Extras
diff --git a/src/HaskellCI/ShVersionRange.hs b/src/HaskellCI/ShVersionRange.hs
--- a/src/HaskellCI/ShVersionRange.hs
+++ b/src/HaskellCI/ShVersionRange.hs
@@ -1,15 +1,14 @@
 module HaskellCI.ShVersionRange (
     compilerVersionPredicate,
+    compilerVersionArithPredicate,
     ) where
 
 import HaskellCI.Prelude
 
 import Algebra.Lattice (joins)
 import Algebra.Heyting.Free (Free (..))
-import Algebra.Lattice.Wide (Wide (..))
 
 import qualified Algebra.Heyting.Free as F
-import qualified Algebra.Lattice.Wide as W
 import qualified Data.Set             as S
 import qualified Distribution.Version as C
 
@@ -19,10 +18,19 @@
 -- >>> import Distribution.Pretty (prettyShow)
 
 compilerVersionPredicate :: Set CompilerVersion -> CompilerRange -> String
-compilerVersionPredicate cvs cr
-    | S.null ghcjsS = wideToString $ freeToWide ghcFree
-    | otherwise     = wideToString $ freeToWide $
-        (Var "$GHCJS" /\ ghcjsFree) \/ (Var "! $GHCJS" /\ ghcFree)
+compilerVersionPredicate = compilerVersionPredicateImpl (toTest . freeToArith) where
+    toTest expr = "[ " ++ expr ++ " -ne 0 ]"
+
+compilerVersionArithPredicate :: Set CompilerVersion -> CompilerRange -> String
+compilerVersionArithPredicate = compilerVersionPredicateImpl freeToArith
+
+compilerVersionPredicateImpl
+    :: (Free String -> String)
+    -> Set CompilerVersion -> CompilerRange -> String
+compilerVersionPredicateImpl conv cvs cr
+    | S.null ghcjsS = conv ghcFree
+    | otherwise     = conv $
+        (Var "GHCJSARITH" /\ ghcjsFree) \/ (Var "! GHCJSARITH" /\ ghcFree)
   where
     R hdS ghcS ghcjsS = partitionCompilerVersions cvs
     R hdR ghcR ghcjsR = simplifyCompilerRange cr
@@ -66,8 +74,8 @@
 
         earlier u | isMaxGHC u = C.anyVersion
                   | otherwise  = C.earlierVersion u
-      
 
+
     ghcRange :: VersionRange
     ghcRange = foldr (\/) C.noVersion $ map findGhc $ S.toList ghcS'
 
@@ -115,7 +123,7 @@
 
     disj :: C.VersionInterval -> Free String
     disj (C.LowerBound v C.InclusiveBound, C.UpperBound u C.InclusiveBound)
-        | v == u                = Var ("[ $HCNUMVER -eq " ++ f v ++ " ]")
+        | v == u                = Var ("HCNUMVER == " ++ f v)
     disj (lb, C.NoUpperBound)
         | isInclZero lb         = top
         | otherwise             = Var (lower lb)
@@ -126,11 +134,11 @@
     isInclZero (C.LowerBound v C.InclusiveBound) = v == C.mkVersion [0]
     isInclZero (C.LowerBound _ C.ExclusiveBound) = False
 
-    lower (C.LowerBound v C.InclusiveBound) = "[ $HCNUMVER -ge " ++ f v ++ " ]"
-    lower (C.LowerBound v C.ExclusiveBound) = "[ $HCNUMVER -gt " ++ f v ++ " ]"
+    lower (C.LowerBound v C.InclusiveBound) = "HCNUMVER >= " ++ f v
+    lower (C.LowerBound v C.ExclusiveBound) = "HCNUMVER > " ++ f v
 
-    upper v C.InclusiveBound = "[ $HCNUMVER -le " ++ f v ++ " ]"
-    upper v C.ExclusiveBound = "[ $HCNUMVER -lt " ++ f v ++ " ]"
+    upper v C.InclusiveBound = "HCNUMVER <= " ++ f v
+    upper v C.ExclusiveBound = "HCNUMVER < " ++ f v
 
     f = ghcVersionToString
 
@@ -182,22 +190,20 @@
     up' x []     = [x + 1]
     up' x (y:ys) = x : up' y ys
 
-wideToString :: Wide String -> String
-wideToString W.Bottom     = "false"
-wideToString W.Top        = "top"
-wideToString (W.Middle x) = x
-
+-------------------------------------------------------------------------------
+-- Arithmetic expression
+-------------------------------------------------------------------------------
 
-freeToWide :: Free String -> Wide String
-freeToWide z
-    | z == top    = top
-    | z == bottom = bottom
-    | otherwise   = Middle (go 0 z)
+freeToArith :: Free String -> String
+freeToArith z
+    | z == top    = "1"
+    | z == bottom = "0"
+    | otherwise   = "$((" ++ go 0 z ++ "))"
   where
     go :: Int -> Free String -> String
     go _ (Var x)  = x
-    go _ F.Bottom = "false"
-    go _ F.Top    = "true"
+    go _ F.Bottom = "1"
+    go _ F.Top    = "0"
 
     go d (x :/\: y) = parens (d > 3)
         $ go 4 x ++ " && " ++ go 3 y
@@ -205,7 +211,7 @@
         $ go 3 x ++ " || " ++ go 2 y
 
     go d (x :=>: y) = parens (d > 2)
-        $ "! { " ++ go 0 x ++ " ; } || " ++ go 2 y
+        $ "! (" ++ go 0 x ++ ") || " ++ go 2 y
 
     parens :: Bool -> String -> String
     parens True  s = "{ " ++ s ++ "; }"
diff --git a/src/HaskellCI/Travis.hs b/src/HaskellCI/Travis.hs
--- a/src/HaskellCI/Travis.hs
+++ b/src/HaskellCI/Travis.hs
@@ -2,50 +2,34 @@
 {-# LANGUAGE NamedFieldPuns    #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE RecordWildCards   #-}
-{-# OPTIONS_GHC -Wno-unused-imports -Wno-unused-matches #-}
+{-# OPTIONS_GHC -Wno-unused-matches #-}
 module HaskellCI.Travis (
     makeTravis,
     travisHeader,
     ) where
 
 import HaskellCI.Prelude
-import Prelude           (head)
 
-import qualified Data.Map.Strict                               as M
-import qualified Data.Set                                      as S
-import qualified Distribution.CabalSpecVersion                 as C
-import qualified Distribution.FieldGrammar                     as C
-import qualified Distribution.FieldGrammar.Pretty              as C
-import qualified Distribution.Fields.Pretty                    as C
-import qualified Distribution.Package                          as C
-import qualified Distribution.PackageDescription               as C
-import qualified Distribution.PackageDescription.Configuration as C
-import qualified Distribution.PackageDescription.FieldGrammar  as C
-import qualified Distribution.Pretty                           as C
-import qualified Distribution.Types.GenericPackageDescription  as C
-import qualified Distribution.Types.SourceRepo                 as C
-import qualified Distribution.Types.VersionRange               as C
-import qualified Distribution.Version                          as C
-import qualified Text.PrettyPrint                              as PP
-
-import qualified Distribution.Types.BuildInfo.Lens          as L
-import qualified Distribution.Types.PackageDescription.Lens as L
+import qualified Data.Map.Strict                 as M
+import qualified Data.Set                        as S
+import qualified Distribution.Fields.Pretty      as C
+import qualified Distribution.Package            as C
+import qualified Distribution.Pretty             as C
+import qualified Distribution.Types.VersionRange as C
+import qualified Distribution.Version            as C
 
-import Cabal.Optimization
 import Cabal.Project
-import Cabal.SourceRepo
-import HaskellCI.Cli
+import HaskellCI.Auxiliary
 import HaskellCI.Compiler
 import HaskellCI.Config
 import HaskellCI.Config.ConstraintSet
-import HaskellCI.Config.CopyFields
 import HaskellCI.Config.Doctest
 import HaskellCI.Config.Folds
 import HaskellCI.Config.HLint
 import HaskellCI.Config.Installed
 import HaskellCI.Config.Jobs
 import HaskellCI.Config.PackageScope
-import HaskellCI.Config.Ubuntu
+import HaskellCI.HeadHackage
 import HaskellCI.Jobs
 import HaskellCI.List
 import HaskellCI.MonadErr
@@ -82,13 +66,20 @@
 -- Generate travis configuration
 -------------------------------------------------------------------------------
 
+{-
+Travis CI–specific notes:
+
+* We use -j2 for parallelism, as Travis' virtual environments use 2 cores, per
+  https://docs.travis-ci.com/user/reference/overview/#virtualisation-environment-vs-operating-system.
+-}
+
 makeTravis
     :: [String]
     -> Config
     -> Project URI Void Package
     -> JobVersions
     -> Either ShError Travis -- TODO: writer
-makeTravis argv Config {..} prj JobVersions {..} = do
+makeTravis argv config@Config {..} prj jobs@JobVersions {..} = do
     -- before caching: clear some redundant stuff
     beforeCache <- runSh $ when cfgCache $ do
         sh "rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log"
@@ -105,9 +96,9 @@
         -- This have to be first
         when anyGHCJS $ sh $ unlines
             [ "if echo $CC | grep -q ghcjs; then"
-            , "    GHCJS=true;"
+            , "    GHCJS=true; GHCJSARITH=1;"
             , "else"
-            , "    GHCJS=false;"
+            , "    GHCJS=false; GHCJSARITH=0;"
             , "fi"
             ]
 
@@ -163,7 +154,7 @@
         cat "$CABALHOME/config"
             [ "verbose: normal +nowrap +markoutput" -- https://github.com/haskell/cabal/issues/5956
             , "remote-build-reporting: anonymous"
-            , "write-ghc-environment-files: always"
+            , "write-ghc-environment-files: never"
             , "remote-repo-cache: $CABALHOME/packages"
             , "logs-dir:          $CABALHOME/logs"
             , "world-file:        $CABALHOME/world"
@@ -182,17 +173,8 @@
         -- (locally you want to add it to cabal.project)
         unless (S.null headGhcVers) $ sh $ unlines $
             [ "if $HEADHACKAGE; then"
-            , "echo \"allow-newer: $($HCPKG list --simple-output | sed -E 's/([a-zA-Z-]+)-[0-9.]+/*:\\1/g')\" >> $CABALHOME/config"
             ] ++
-            lines (catCmd Double "$CABALHOME/config"
-            [ "repository head.hackage.ghc.haskell.org"
-            , "   url: https://ghc.gitlab.haskell.org/head.hackage/"
-            , "   secure: True"
-            , "   root-keys: 7541f32a4ccca4f97aea3b22f5e593ba2c0267546016b992dfadcd2fe944e55d"
-            , "              26021a13b401500c8eb2761ca95c61f2d625bfef951b939a8124ed12ecf07329"
-            , "              f76d08be13e9a61a377a85e2fb63f4c5435d40f8feb3e12eb05905edb8cdea89"
-            , "   key-threshold: 3"
-            ]) ++
+            lines (catCmd Double "$CABALHOME/config" headHackageRepoStanza) ++
             [ "fi"
             ]
 
@@ -258,11 +240,11 @@
 
         -- Install cabal-plan (for ghcjs tests)
         when (anyGHCJS && cfgGhcjsTests) $ do
-            shForJob RangeGHCJS $ cabal "v2-install -w ghc-8.4.4 --ignore-project cabal-plan --constraint='cabal-plan ^>=0.6.0.0' --constraint='cabal-plan +exe'"
+            shForJob RangeGHCJS $ cabal "v2-install -w ghc-8.4.4 --ignore-project -j2 cabal-plan --constraint='cabal-plan ^>=0.6.0.0' --constraint='cabal-plan +exe'"
 
         -- Install happy
         when anyGHCJS $ for_ cfgGhcjsTools $ \t ->
-            shForJob RangeGHCJS $ cabal $ "v2-install -w ghc-8.4.4 --ignore-project " ++ C.prettyShow t
+            shForJob RangeGHCJS $ cabal $ "v2-install -w ghc-8.4.4 --ignore-project -j2" ++ C.prettyShow t
 
         -- create cabal.project file
         generateCabalProject False
@@ -324,12 +306,12 @@
         -- build everything
         foldedSh FoldBuildEverything "Building with tests and benchmarks..." cfgFolds $ do
             comment "build & run tests, build benchmarks"
-            sh $ cabal "v2-build $WITHCOMPILER ${TEST} ${BENCH} all"
+            sh $ cabal "v2-build $WITHCOMPILER ${TEST} ${BENCH} all --write-ghc-environment-files=always"
 
         -- cabal v2-test fails if there are no test-suites.
         foldedSh FoldTest "Testing..." cfgFolds $ do
             shForJob (RangeGHC /\ Range (cfgTests /\ cfgRunTests) /\ hasTests) $
-                cabal "v2-test $WITHCOMPILER ${TEST} ${BENCH} all"
+                cabal $ "v2-test $WITHCOMPILER ${TEST} ${BENCH} all" ++ testShowDetails
 
             when cfgGhcjsTests $ shForJob (RangeGHCJS /\ hasTests) $ unwords
                 [ "cabal-plan list-bins '*:test:*' | while read -r line; do"
@@ -343,6 +325,7 @@
         -- doctest
         when doctestEnabled $ foldedSh FoldDoctest "Doctest..." cfgFolds $ do
             let doctestOptions = unwords $ cfgDoctestOptions cfgDoctest
+            sh $ "$CABAL v2-build $WITHCOMPILER ${TEST} ${BENCH} all --dry-run"
             unless (null $ cfgDoctestFilterEnvPkgs cfgDoctest) $ do
                 -- cabal-install mangles unit ids on the OSX,
                 -- removing the vowels to make filepaths shorter
@@ -403,7 +386,7 @@
         -- we can test with other constraint sets
         unless (null cfgConstraintSets) $ do
             comment "Constraint sets"
-            sh "rm -rf cabal.project.local"
+            sh "rm -f cabal.project.local"
 
             for_ cfgConstraintSets $ \cs -> do
                 let name            = csName cs
@@ -417,7 +400,7 @@
                 foldedSh' FoldConstraintSets name ("Constraint set " ++ name) cfgFolds $ do
                     shForCs $ cabal $ "v2-build $WITHCOMPILER " ++ allFlags ++ " all"
                     when (csRunTests cs) $
-                        shForCs' hasTests $ cabal $ "v2-test $WITHCOMPILER " ++ allFlags ++ " all"
+                        shForCs' hasTests $ cabal $ "v2-test $WITHCOMPILER " ++ allFlags ++ " all --test-show-details=direct"
                     when (hasLibrary && csHaddock cs) $
                         shForCs $ cabal $ "v2-haddock $WITHCOMPILER " ++ withHaddock ++ " " ++ allFlags ++ " all"
 
@@ -524,9 +507,7 @@
         , travisScript        = script
         }
   where
-    pkgs = prjPackages prj
-    uris = prjUriPackages prj
-    projectName = fromMaybe (pkgName $ Prelude.head pkgs) cfgProjectName
+    Auxiliary {..} = auxiliary config prj jobs
 
     justIf True x  = Just x
     justIf False _ = Nothing
@@ -559,18 +540,7 @@
         label' | null sfx  = showFold label
                | otherwise = showFold label ++ "-" ++ sfx
 
-    doctestEnabled = any (maybeGHC False (`C.withinRange` cfgDoctestEnabled cfgDoctest)) versions
 
-    -- version range which has tests
-    hasTests :: CompilerRange
-    hasTests = RangePoints $ S.unions
-        [ pkgJobs
-        | Pkg{pkgGpd,pkgJobs} <- pkgs
-        , not $ null $ C.condTestSuites pkgGpd
-        ]
-
-    hasLibrary = any (\Pkg{pkgGpd} -> isJust $ C.condLibrary pkgGpd) pkgs
-
     -- GHC versions which need head.hackage
     headGhcVers :: Set CompilerVersion
     headGhcVers = S.filter (previewGHC cfgHeadHackage) versions
@@ -598,52 +568,6 @@
 
     -- catForJob vr fp contents = shForJob vr (catCmd Double fp contents)
 
-    generateCabalProjectFields :: Bool -> [C.PrettyField ()]
-    generateCabalProjectFields dist = buildList $ do
-        -- generate package fields for URI packages.
-        for_ uris $ \uri ->
-            item $ C.PrettyField () "packages" $ PP.text $ uriToString id uri ""
-
-        -- copy fields from original cabal.project
-        case cfgCopyFields of
-            CopyFieldsNone -> pure ()
-            CopyFieldsSome -> copyFieldsSome
-            CopyFieldsAll  -> copyFieldsSome *> traverse_ item (prjOtherFields prj)
-
-        -- local ghc-options
-        unless (null cfgLocalGhcOptions) $ for_ pkgs $ \Pkg{pkgName} -> do
-            let s = unwords $ map (show . C.showToken) cfgLocalGhcOptions
-            item $ C.PrettySection () "package" [PP.text pkgName] $ buildList $
-                item $ C.PrettyField () "ghc-options" $ PP.text s
-
-        -- raw-project is after local-ghc-options so we can override per package.
-        traverse_ item cfgRawProject
-
-    copyFieldsSome :: ListBuilder (C.PrettyField ()) ()
-    copyFieldsSome = do
-        for_ (prjConstraints prj) $ \xs -> do
-            let s = concat (lines xs)
-            item $ C.PrettyField () "constraints" $ PP.text s
-
-        for_ (prjAllowNewer prj) $ \xs -> do
-            let s = concat (lines xs)
-            item $ C.PrettyField () "allow-newer" $ PP.text s
-
-        when (prjReorderGoals prj) $
-            item $ C.PrettyField () "reorder-goals" $ PP.text "True"
-
-        for_ (prjMaxBackjumps prj) $ \bj ->
-            item $ C.PrettyField () "max-backjumps" $ PP.text $ show bj
-
-        case prjOptimization prj of
-            OptimizationOn      -> return ()
-            OptimizationOff     -> item $ C.PrettyField () "optimization" $ PP.text "False"
-            OptimizationLevel l -> item $ C.PrettyField () "optimization" $ PP.text $ show l
-
-        for_ (prjSourceRepos prj) $ \repo ->
-            item $ C.PrettySection () "source-repository-package" [] $
-                C.prettyFieldGrammar C.cabalSpecLatest sourceRepositoryPackageGrammar (srpHoist toList repo)
-
     generateCabalProject :: Bool -> ShM ()
     generateCabalProject dist = do
         comment "Generate cabal.project"
@@ -670,8 +594,17 @@
                 sh "echo 'package *' >> cabal.project"
                 sh "echo '  ghc-options: -Werror=missing-methods' >> cabal.project"
 
-        cat "cabal.project" $ lines $ C.showFields' (const []) 2 $ generateCabalProjectFields dist
+        cat "cabal.project" $ lines $ C.showFields' (const []) (const id) 2 extraCabalProjectFields
 
+        -- If using head.hackage, allow building with newer versions of GHC boot libraries.
+        -- Note that we put this in a cabal.project file, not ~/.cabal/config, in order to avoid
+        -- https://github.com/haskell/cabal/issues/7291.
+        unless (S.null headGhcVers) $ sh $ unlines $
+            [ "if $HEADHACKAGE; then"
+            , "echo \"allow-newer: $($HCPKG list --simple-output | sed -E 's/([a-zA-Z-]+)-[0-9.]+/*:\\1,/g')\" >> $CABALHOME/config"
+            , "fi"
+            ]
+
         -- also write cabal.project.local file with
         -- @
         -- constraints: base installed
@@ -711,15 +644,7 @@
     withHaddock :: String
     withHaddock = "--with-haddock $HADDOCK"
 
-pkgNameDirVariable' :: String -> String
-pkgNameDirVariable' n = "PKGDIR_" ++ map f n where
-    f '-' = '_'
-    f c   = c
 
-pkgNameDirVariable :: String -> String
-pkgNameDirVariable n = "${PKGDIR_" ++ map f n ++ "}" where
-    f '-' = '_'
-    f c   = c
 
 data Quotes = Single | Double
 
diff --git a/src/HaskellCI/Travis/Yaml.hs b/src/HaskellCI/Travis/Yaml.hs
--- a/src/HaskellCI/Travis/Yaml.hs
+++ b/src/HaskellCI/Travis/Yaml.hs
@@ -4,15 +4,15 @@
 -- | @travis.yaml@ structure.
 module HaskellCI.Travis.Yaml where
 
-import           HaskellCI.Prelude
+import HaskellCI.Prelude
 
-import qualified Data.Aeson              as Aeson
-import qualified Data.List.NonEmpty      as NE
+import qualified Data.Aeson         as Aeson
+import qualified Data.List.NonEmpty as NE
 
-import           HaskellCI.Config.Ubuntu
-import           HaskellCI.List
-import           HaskellCI.Sh
-import           HaskellCI.YamlSyntax
+import HaskellCI.Config.Ubuntu
+import HaskellCI.List
+import HaskellCI.Sh
+import HaskellCI.YamlSyntax
 
 -------------------------------------------------------------------------------
 -- Data
@@ -104,9 +104,6 @@
 -- Serialisation helpers (move to Travis.Yaml?)
 -------------------------------------------------------------------------------
 
-(~>) :: String -> Yaml [String] -> ([String], String, Yaml [String])
-k ~> v = ([],k,v)
-
 (^^^) :: ([String], String, Yaml [String]) -> String -> ([String], String, Yaml [String])
 (a,b,c) ^^^ d = (d : a, b, c)
 
@@ -125,25 +122,6 @@
     gr (Comment c : rest) = case gr rest of
         (cs, xs) : xss -> (c : cs, xs) : xss
         []             -> [] -- end of comments are lost
-
-ykeyValuesFilt :: ann -> [(ann, String, Yaml ann)] -> Yaml ann
-ykeyValuesFilt ann xs = YKeyValues ann
-    [ x
-    | x@(_,_,y)  <- xs
-    , not (isEmpty y)
-    ]
-
-ylistFilt :: ann -> [Yaml ann] -> Yaml ann
-ylistFilt ann xs = YList ann
-    [ x
-    | x <- xs
-    , not (isEmpty x)
-    ]
-
-isEmpty :: Yaml ann -> Bool
-isEmpty (YList _ [])      = True
-isEmpty (YKeyValues _ []) = True
-isEmpty _                 = False
 
 -------------------------------------------------------------------------------
 -- ToYaml
diff --git a/src/HaskellCI/YamlSyntax.hs b/src/HaskellCI/YamlSyntax.hs
--- a/src/HaskellCI/YamlSyntax.hs
+++ b/src/HaskellCI/YamlSyntax.hs
@@ -8,17 +8,24 @@
     reann,
     ToYaml (..),
     prettyYaml,
+    -- * Helpers
+    (~>),
+    ykeyValuesFilt,
+    ylistFilt,
     ) where
 
 import HaskellCI.Prelude
 import Prelude ()
 
-import Data.Bits          (shiftR, (.&.))
-import Data.Char          (isControl, isPrint, ord)
-import Data.Monoid        (Endo (..))
+import Data.Bits   (shiftR, (.&.))
+import Data.Char   (isControl, isPrint, ord)
+import Data.Monoid (Endo (..))
 
 import qualified Data.Aeson              as Aeson
+import qualified Data.Aeson.Encoding     as AE
+import qualified Data.HashMap.Strict     as HM
 import qualified Data.List.NonEmpty      as NE
+import qualified Data.Map.Strict         as M
 import qualified Data.Text               as T
 import qualified Data.Text.Encoding      as TE
 import qualified Data.Text.Lazy          as TL
@@ -74,6 +81,12 @@
 instance ToYaml Aeson.Value where
     toYaml = YValue []
 
+instance (k ~ String, ToYaml v) => ToYaml (M.Map k v) where
+    toYaml m = ykeyValuesFilt []
+        [ k ~> toYaml v
+        | (k, v) <- M.toList m
+        ]
+
 -------------------------------------------------------------------------------
 -- Converting to string
 -------------------------------------------------------------------------------
@@ -194,7 +207,7 @@
         pure (0, Line (comment ann) (showString $ if b then "true" else "false"))
 
     go (YValue ann v) =
-        pure (0, Line (comment ann) (showString $ TL.unpack $ TLE.decodeUtf8 $ Aeson.encode v))
+        pure (0, Line (comment ann) (showString $ encodeValue v))
 
     go (YList ann [])     = pure (0, Line (comment ann) (showString "[]"))
     go (YList ann (x:xs)) = y :| (ys ++ yss)
@@ -305,14 +318,27 @@
 
     flatten :: NonEmpty (Int, Line) -> String
     flatten xs = appEndo (foldMap f xs) "" where
-        f (lvl, Line cs s) =
-            foldMap showComment cs <> g s
+        f (lvl, Line cs s)
+            | null (s "") = foldMap showComment cs <> Endo (showChar '\n')
+            | otherwise   = foldMap showComment cs <> g s
           where
             showComment "" = g (showString "#")
             showComment c  = g (showString "# " . showString c)
             g x = Endo (showString lvl' . x . showChar '\n')
             lvl' = replicate (lvl * 2) ' '
 
+encodeValue :: Aeson.Value -> String
+encodeValue = TL.unpack . TLE.decodeUtf8 . AE.encodingToLazyByteString . enc where
+    enc :: Aeson.Value -> Aeson.Encoding
+    enc Aeson.Null       = AE.null_
+    enc (Aeson.Bool b)   = AE.bool b
+    enc (Aeson.Number n) = AE.scientific n
+    enc (Aeson.String s) = AE.text s
+    enc (Aeson.Array v)  = AE.list enc (toList v)
+    enc (Aeson.Object m) = AE.dict AE.text enc M.foldrWithKey (toMap m)
+
+    toMap = M.fromList . HM.toList
+
 -- a 'Line' is comments before in and actual text after!
 data Line = Line [String] ShowS
 
@@ -364,3 +390,29 @@
 
     showHexDigit :: Int -> ShowS
     showHexDigit = showHex
+
+-------------------------------------------------------------------------------
+-- Helpers
+-------------------------------------------------------------------------------
+
+(~>) :: String -> Yaml [String] -> ([String], String, Yaml [String])
+k ~> v = ([],k,v)
+
+ykeyValuesFilt :: ann -> [(ann, String, Yaml ann)] -> Yaml ann
+ykeyValuesFilt ann xs = YKeyValues ann
+    [ x
+    | x@(_,_,y)  <- xs
+    , not (isEmpty y)
+    ]
+
+ylistFilt :: ann -> [Yaml ann] -> Yaml ann
+ylistFilt ann xs = YList ann
+    [ x
+    | x <- xs
+    , not (isEmpty x)
+    ]
+
+isEmpty :: Yaml ann -> Bool
+isEmpty (YList _ [])      = True
+isEmpty (YKeyValues _ []) = True
+isEmpty _                 = False
diff --git a/test/Tests.hs b/test/Tests.hs
--- a/test/Tests.hs
+++ b/test/Tests.hs
@@ -4,18 +4,15 @@
 import Prelude ()
 import Prelude.Compat
 
-import HaskellCI             hiding (main)
-import HaskellCI.Diagnostics (runDiagnosticsT)
+import HaskellCI hiding (main)
 
-import Control.Exception          (ErrorCall (..), throwIO)
+import Control.Arrow              (first)
 import Data.Algorithm.Diff        (PolyDiff (..), getGroupedDiff)
-import Data.List                  (stripPrefix)
-import Data.Maybe                 (mapMaybe)
-import System.Directory           (doesFileExist, setCurrentDirectory)
+import Distribution.Simple.Utils  (fromUTF8BS)
+import System.Directory           (setCurrentDirectory)
 import System.FilePath            (addExtension)
 import Test.Tasty                 (TestName, TestTree, defaultMain, testGroup)
 import Test.Tasty.Golden.Advanced (goldenTest)
-import Text.Read                  (readMaybe)
 
 import qualified Data.ByteString       as BS
 import qualified Data.ByteString.Char8 as BS8
@@ -25,104 +22,93 @@
 main = do
     setCurrentDirectory "fixtures/"
     defaultMain $ testGroup "fixtures"
-        [ fixtureGoldenTest "cabal.project.empty-line"
-        , fixtureGoldenTest "cabal.project.fail-versions"
-        , fixtureGoldenTest "cabal.project.messy"
-        , fixtureGoldenTest "cabal.project.travis-patch"
+        [ fixtureGoldenTest "all-versions"
+        , fixtureGoldenTest "empty-line"
+        , fixtureGoldenTest "fail-versions"
+        , fixtureGoldenTest "irc-channels"
+        , fixtureGoldenTest "messy"
+        , fixtureGoldenTest "psql"
+        , fixtureGoldenTest "travis-patch"
         , testGroup "copy-fields"
-            [ fixtureGoldenTest "cabal.project.copy-fields.all"
-            , fixtureGoldenTest "cabal.project.copy-fields.some"
-            , fixtureGoldenTest "cabal.project.copy-fields.none"
+            [ fixtureGoldenTest "copy-fields-all"
+            , fixtureGoldenTest "copy-fields-some"
+            , fixtureGoldenTest "copy-fields-none"
             ]
         ]
 
-linesToArgv :: String -> Maybe [String]
-linesToArgv txt = case mapMaybe lineToArgv (lines txt) of
-    [argv] -> Just argv
-    _ -> Nothing
-  where
-    lineToArgv line
-        | Just rest <- "# REGENDATA " `stripPrefix` line = readMaybe rest
-        | otherwise = Nothing
-
 -- |
 -- @
 -- travisFromConfigFile ::
 --    ... => ([String],Options) -> FilePath -> [String] -> Writer [String] m ()
 -- @
 fixtureGoldenTest :: FilePath -> TestTree
-fixtureGoldenTest fp = cabalGoldenTest fp outputRef errorRef $ do
-    (argv, opts) <- makeTravisFlags
-    let genConfig = travisFromConfigFile argv opts fp
-    runDiagnosticsT genConfig
+fixtureGoldenTest fp = testGroup fp
+    [ fixtureGoldenTest' "travis" travisFromConfigFile
+    , fixtureGoldenTest' "github" githubFromConfigFile
+    , fixtureGoldenTest' "bash"   bashFromConfigFile
+    ]
   where
-    outputRef = addExtension fp "travis.yml"
-    errorRef = addExtension fp "stderr"
-
-    referenceArgv :: Bool -> IO (Maybe [String])
-    referenceArgv refExists
-        | refExists = (linesToArgv . BS8.unpack) `fmap` BS.readFile outputRef
-        | otherwise = return $ Just [fp]
-
-    makeTravisFlags :: IO ([String], Options)
-    makeTravisFlags = do
-        result <- doesFileExist outputRef >>= referenceArgv
-        case result of
-            Nothing -> throwIO (ErrorCall "No REGENDATA in result file.")
-            Just argv -> do
-                (opts, _fp) <- parseOpts argv
-                return (argv, opts)
+    -- name acts as extension also
+    fixtureGoldenTest' name generate = cabalGoldenTest name outputRef $ do
+        (argv, opts') <- makeFlags
+        let opts = opts'
+              { optInputType      = Just InputTypeProject
+              , optConfigMorphism = (\cfg -> cfg { cfgInsertVersion = False}) . optConfigMorphism opts'
+              }
+        let genConfig = generate argv opts projectfp
+        first (fmap (lines . fromUTF8BS)) <$> runDiagnosticsT genConfig
+      where
+        outputRef = addExtension fp name
+        projectfp = fp ++ ".project"
 
-parseOpts :: [String] -> IO (Options, FilePath)
-parseOpts argv = do
-    (path, opts) <- parseTravis argv
-    return (opts, path)
+        readArgv :: IO [String]
+        readArgv = do
+            contents <- readFile $ addExtension fp "args"
+            return $ filter (not . null)$ lines contents
 
-data Result
-    = Success [String] [String]
-    | Failure [String]
-  deriving Eq
+        makeFlags :: IO ([String], Options)
+        makeFlags = do
+            argv <- readArgv
+            let argv' = argv ++ [name, projectfp]
+            (_fp, opts) <- parseOptions argv'
+            return (argv', opts)
 
 cabalGoldenTest
     :: TestName
     -> FilePath
-    -> FilePath
     -> IO (Maybe [String], [String])
     -> TestTree
-cabalGoldenTest name outRef errRef act = goldenTest name readGolden act' cmp upd
+cabalGoldenTest name outRef act = goldenTest name readGolden (transform <$> act) cmp upd
   where
     readData :: FilePath -> IO [String]
     readData fp = lines . BS8.unpack <$> BS.readFile fp
 
-    act' = flip fmap act $ \r -> case r of
-        (Nothing, diags) -> Failure diags
-        (Just x, diags)  -> Success diags x
+    transform :: (Maybe [String], [String]) -> [String]
+    transform (Nothing, diags) =
+        [ "# FAILURE"
+        ] ++
+        [ "# " ++ w
+        | w <- diags
+        ]
+    transform (Just contents, diags) =
+        [ "# SUCCESS"
+        ] ++
+        [ "# " ++ w
+        | w <- diags
+        ] ++
+        contents
 
-    readGolden = do
-        refExists <- doesFileExist outRef
-        if refExists
-           then Success <$> readData errRef <*> readData outRef
-           else Failure <$> readData errRef
+    readGolden = readData outRef
 
     packData :: [String] -> BS.ByteString
     packData = BS8.pack . unlines
 
-    upd (Failure (packData -> errs)) = BS.writeFile errRef errs
-    upd (Success (packData -> warnings) (packData -> contents)) = do
-        BS.writeFile outRef contents
-        BS.writeFile errRef warnings
+    upd (packData -> contents) = BS.writeFile outRef contents
 
     cmp x y | x == y = return Nothing
-    cmp (Failure err1) (Failure err2) = return . Just $ diff err1 err2
-    cmp (Success warn1 out1) (Success warn2 out2) = return . Just . mconcat $
-        [ diff warn1 warn2
-        , "\n\n"
-        , diff out1 out2
+    cmp out1 out2 = return . Just . mconcat $
+        [ diff out1 out2
         ]
-    cmp (Failure err) (Success warnings _) = return . Just . unlines $
-        [ "Expected failure:" ] ++ err ++ ["\n\nFound success:"] ++ warnings
-    cmp (Success warnings _) (Failure err) = return . Just . unlines $
-        [ "Expected success:" ] ++ warnings ++ ["\n\nFound failure:"] ++ err
 
     diff x y =
         ansiReset -- reset tasty's red color
