[Git][ghc/ghc][wip/backports-8.8] Backport CI infrastructure rework

Ben Gamari gitlab at gitlab.haskell.org
Sat Jul 11 16:54:31 UTC 2020



Ben Gamari pushed to branch wip/backports-8.8 at Glasgow Haskell Compiler / GHC


Commits:
9f52e0ca by Ben Gamari at 2020-07-11T12:54:18-04:00
Backport CI infrastructure rework

- - - - -


7 changed files:

- .gitlab-ci.yml
- + .gitlab/ci.sh
- − .gitlab/darwin-init.sh
- .gitlab/linters/check-makefiles.py
- + .gitlab/linters/check-version-number.sh
- .gitlab/linters/linter.py
- − .gitlab/win32-init.sh


Changes:

=====================================
.gitlab-ci.yml
=====================================
@@ -2,59 +2,45 @@ variables:
   GIT_SSL_NO_VERIFY: "1"
 
   # Commit of ghc/ci-images repository from which to pull Docker images
-  DOCKER_REV: 1ac7f435c9312f10422a82d304194778378e2a1a
+  DOCKER_REV: 6223fe0b5942f4fa35bdec92c74566cf195bfb42
 
   # Sequential version number capturing the versions of all tools fetched by
-  # .gitlab/win32-init.sh.
+  # .gitlab/ci.sh.
   WINDOWS_TOOLCHAIN_VERSION: 1
 
-before_script:
-  - python3 .gitlab/fix-submodules.py
-  - git submodule sync --recursive
-  - git submodule update --init --recursive
-  - git checkout .gitmodules
-  - "git fetch https://gitlab.haskell.org/ghc/ghc-performance-notes.git refs/notes/perf:refs/notes/perf || true"
+  # Disable shallow clones; they break our linting rules
+  GIT_DEPTH: 0
+
+  # Overridden by individual jobs
+  CONFIGURE_ARGS: ""
+
+  GIT_SUBMODULE_STRATEGY: "recursive"
 
 stages:
-  - lint       # Source linting
-  - build      # A quick smoke-test to weed out broken commits
-  - full-build # Build all the things
-  - cleanup    # See Note [Cleanup on Windows]
-  - packaging  # Source distribution, etc.
-  - hackage    # head.hackage testing
-  - deploy     # push documentation
-
-.only-default: &only-default
-  rules:
-    - if: $CI_MERGE_REQUEST_ID
-    - if: $CI_COMMIT_TAG
-    - if: '$CI_COMMIT_BRANCH == "master"'
-    - if: '$CI_COMMIT_BRANCH =~ /ghc-[0.9]+\.[0-9]+/'
-    - if: '$CI_PIPELINE_SOURCE == "web"'
+  - lint        # Source linting
+  - quick-build # A very quick smoke-test to weed out broken commits
+  - build       # A quick smoke-test to weed out broken commits
+  - full-build  # Build all the things
+  - cleanup     # See Note [Cleanup after the shell executor]
+  - packaging   # Source distribution, etc.
+  - testing     # head.hackage correctness and compiler performance testing
+  - deploy      # push documentation
 
 workflow:
-  # N.B. Don't run on wip/ branches, instead on run on merge requests.
+  # N.B.Don't run on wip/ branches, instead on run on merge requests.
   rules:
     - if: $CI_MERGE_REQUEST_ID
     - if: $CI_COMMIT_TAG
-    - if: '$CI_COMMIT_BRANCH == "wip/marge_bot_batch_merge_job"'
+    - if: '$CI_COMMIT_BRANCH == "master"'
     - if: '$CI_COMMIT_BRANCH =~ /ghc-[0.9]+\.[0-9]+/'
     - if: '$CI_PIPELINE_SOURCE == "web"'
 
-############################################################
-# Runner Tags
-############################################################
-#
-# * x86_64-linux: Any Docker-capable x86_64 Linux machine
-# * aarch64-linux: Any Docker-capable AArch64 Linux machine
-# * x86_64-windows: A x86_64 Windows machine
-# * lint: Any Docker-capable x86_64 Linux machine; distinct from
-#         x86_64-linux to ensure low-latency availability.
-#
-
 .nightly: &nightly
   rules:
     - if: $NIGHTLY
+  artifacts:
+    when: always
+    expire_in: 8 weeks
 
 .release: &release
   variables:
@@ -66,53 +52,105 @@ workflow:
   rules:
     - if: '$RELEASE == "yes"'
 
+############################################################
+# Runner Tags
+############################################################
+#
+# * x86_64-linux: Any Docker-capable x86_64 Linux machine
+# * aarch64-linux: Any Docker-capable AArch64 Linux machine
+# * x86_64-windows: A x86_64 Windows machine
+# * lint: Any Docker-capable x86_64 Linux machine; distinct from
+#         x86_64-linux to ensure low-latency availability.
+#
+
 
 ############################################################
 # Linting
 ############################################################
 
 ghc-linters:
-  allow_failure: true
   stage: lint
   image: "registry.gitlab.haskell.org/ghc/ci-images/linters:$DOCKER_REV"
   script:
-    - git fetch origin $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
+    - git fetch "$CI_MERGE_REQUEST_PROJECT_URL" $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
     - base="$(git merge-base FETCH_HEAD $CI_COMMIT_SHA)"
-    - "echo Merge base $base"
+    - "echo Linting changes between $base..$CI_COMMIT_SHA"
     #    - validate-commit-msg .git $(git rev-list $base..$CI_COMMIT_SHA)
     - validate-whitespace .git $(git rev-list $base..$CI_COMMIT_SHA)
-    - .gitlab/linters/check-makefiles.py $base $CI_COMMIT_SHA
-    - .gitlab/linters/check-cpp.py $base $CI_COMMIT_SHA
+    - .gitlab/linters/check-makefiles.py commits $base $CI_COMMIT_SHA
+    - .gitlab/linters/check-cpp.py commits $base $CI_COMMIT_SHA
+    - .gitlab/linters/check-version-number.sh
+    - python3 utils/checkUniques/check-uniques.py .
   dependencies: []
   tags:
     - lint
   rules:
     - if: $CI_MERGE_REQUEST_ID
 
+# Run mypy Python typechecker on linter scripts.
+lint-linters:
+  stage: lint
+  image: "registry.gitlab.haskell.org/ghc/ci-images/linters:$DOCKER_REV"
+  script:
+    - mypy .gitlab/linters/*.py
+  dependencies: []
+  tags:
+    - lint
+
+# Check that .T files all parse by listing broken tests.
+lint-testsuite:
+  stage: lint
+  image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb9:$DOCKER_REV"
+  script:
+    - make -Ctestsuite list_broken TEST_HC=ghc
+  dependencies: []
+  tags:
+    - lint
+
+# Run mypy Python typechecker on testsuite driver
+.typecheck-testsuite:
+  stage: lint
+  image: "registry.gitlab.haskell.org/ghc/ci-images/linters:$DOCKER_REV"
+  script:
+    - mypy testsuite/driver/runtests.py
+  dependencies: []
+  tags:
+    - lint
+
 # We allow the submodule checker to fail when run on merge requests (to
-# accomodate, e.g., haddock changes not yet upstream) but not on `master` or
+# accommodate, e.g., haddock changes not yet upstream) but not on `master` or
 # Marge jobs.
 .lint-submods:
   stage: lint
   image: "registry.gitlab.haskell.org/ghc/ci-images/linters:$DOCKER_REV"
   script:
-    - submodchecker .git $(git rev-list $base..$CI_COMMIT_SHA)
+    - git fetch "$CI_MERGE_REQUEST_PROJECT_URL" $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
+    - base="$(git merge-base FETCH_HEAD $CI_COMMIT_SHA)"
+    - "echo Linting submodule changes between $base..$CI_COMMIT_SHA"
+    - git submodule foreach git remote update
+    - submodchecker . $(git rev-list $base..$CI_COMMIT_SHA)
   dependencies: []
   tags:
     - lint
 
 lint-submods:
   extends: .lint-submods
+  # Allow failure on merge requests since any necessary submodule patches may
+  # not be upstreamed yet.
   rules:
     - if: '$CI_MERGE_REQUEST_LABELS =~ /.*marge_bot_batch_merge_job.*/'
       allow_failure: false
     - allow_failure: true
 
-lint-submods-mr:
+lint-submods-branch:
   extends: .lint-submods
-  allow_failure: true
+  script:
+    - "echo Linting submodule changes between $CI_COMMIT_BEFORE_SHA..$CI_COMMIT_SHA"
+    - git submodule foreach git remote update
+    - submodchecker . $(git rev-list $CI_COMMIT_BEFORE_SHA..$CI_COMMIT_SHA)
   rules:
-    - if: $CI_MERGE_REQUEST_ID
+    - if: '$CI_COMMIT_BRANCH == "master"'
+    - if: '$CI_COMMIT_BRANCH =~ /ghc-[0.9]+\.[0-9]+/'
 
 .lint-changelogs:
   stage: lint
@@ -125,6 +163,7 @@ lint-submods-mr:
 
 lint-changelogs:
   extends: .lint-changelogs
+  # Allow failure since this isn't a final release.
   allow_failure: true
   rules:
     - if: '$CI_COMMIT_BRANCH =~ /ghc-[0.9]+\.[0-9]+/'
@@ -140,71 +179,183 @@ lint-release-changelogs:
 ############################################################
 
 .validate-hadrian:
-  <<: *only-default
-  allow_failure: true
+  variables:
+    FLAVOUR: "validate"
   script:
-    - cabal update
-    - git clean -xdf && git submodule foreach git clean -xdf
-    - bash .circleci/prepare-system.sh
-    - if [[ -d ./cabal-cache ]]; then cp -R ./.cabal-cache ~/.cabal-cache; fi
-    - ./boot
-    - ./configure $CONFIGURE_ARGS
-    - hadrian/build.cabal.sh -j`mk/detect-cpu-count.sh` --docs=no-sphinx binary-dist
-    - mv _build/bindist/ghc*.tar.xz ghc.tar.xz
+    - .gitlab/ci.sh setup
+    - .gitlab/ci.sh configure
+    - .gitlab/ci.sh build_hadrian
+    - .gitlab/ci.sh test_hadrian
   cache:
     key: hadrian
     paths:
       - cabal-cache
   artifacts:
-    when: always
+    reports:
+      junit: junit.xml
+    expire_in: 2 week
     paths:
       - ghc.tar.xz
+      - junit.xml
 
-validate-x86_64-linux-deb8-hadrian:
+.validate-linux-hadrian:
   extends: .validate-hadrian
-  stage: build
-  image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb8:$DOCKER_REV"
+  image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb9:$DOCKER_REV"
+  variables:
+    TEST_ENV: "x86_64-linux-deb9-hadrian"
   before_script:
     # workaround for docker permissions
     - sudo chown ghc:ghc -R .
-    - python3 .gitlab/fix-submodules.py
     - git submodule sync --recursive
     - git submodule update --init --recursive
     - git checkout .gitmodules
     - "git fetch https://gitlab.haskell.org/ghc/ghc-performance-notes.git refs/notes/perf:refs/notes/perf || true"
+  after_script:
+    - .gitlab/ci.sh clean
   tags:
     - x86_64-linux
 
+validate-x86_64-linux-deb9-hadrian:
+  extends: .validate-linux-hadrian
+  stage: build
+
+validate-x86_64-linux-deb9-unreg-hadrian:
+  extends: .validate-linux-hadrian
+  stage: full-build
+  variables:
+    CONFIGURE_ARGS: --enable-unregisterised
+    TEST_ENV: "x86_64-linux-deb9-unreg-hadrian"
+
+hadrian-ghc-in-ghci:
+  stage: quick-build
+  image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb9:$DOCKER_REV"
+  before_script:
+    # workaround for docker permissions
+    - sudo chown ghc:ghc -R .
+    - git submodule sync --recursive
+    - git submodule update --init --recursive
+    - git checkout .gitmodules
+  variables:
+    GHC_FLAGS: -Werror
+  tags:
+    - x86_64-linux
+  script:
+    - cabal update
+    - cd hadrian; cabal new-build --project-file=ci.project; cd ..
+    - git clean -xdf && git submodule foreach git clean -xdf
+    - .gitlab/ci.sh setup
+    - if [[ -d ./cabal-cache ]]; then cp -R ./.cabal-cache ~/.cabal-cache; fi
+    - ./boot
+    - ./configure $CONFIGURE_ARGS
+    # Load ghc-in-ghci then immediately exit and check the modules loaded
+    - echo ":q" | hadrian/ghci -j`mk/detect-cpu-count.sh`| tail -n2 | grep "Ok,"
+  cache:
+    key: hadrian-ghci
+    paths:
+      - cabal-cache
 
 ############################################################
 # Validation via Pipelines (make)
 ############################################################
 
 .validate:
-  <<: *only-default
   variables:
     TEST_TYPE: test
-  before_script:
-    - git clean -xdf && git submodule foreach git clean -xdf
+    MAKE_ARGS: "-Werror"
   script:
-    - ./boot
-    - ./configure $CONFIGURE_ARGS
-    - |
-      THREADS=`mk/detect-cpu-count.sh`
-      make V=0 -j$THREADS WERROR=-Werror
-    - |
-      make binary-dist TAR_COMP_OPTS="-1"
-    - |
-      THREADS=`mk/detect-cpu-count.sh`
-      make $TEST_TYPE THREADS=$THREADS JUNIT_FILE=../../junit.xml METRICS_FILE=$METRICS_FILE
+    - .gitlab/ci.sh setup
+    - .gitlab/ci.sh configure
+    - .gitlab/ci.sh build_make
+    - .gitlab/ci.sh test_make
   dependencies: []
   artifacts:
     reports:
       junit: junit.xml
     expire_in: 2 week
     paths:
-      - ghc-*.tar.xz
+      - $BIN_DIST_PREP_TAR_COMP
       - junit.xml
+      - performance-metrics.tsv
+
+#################################
+# x86_64-freebsd
+#################################
+
+.build-x86_64-freebsd:
+  extends: .validate
+  tags:
+    - x86_64-freebsd
+  allow_failure: true
+  variables:
+    # N.B. we use iconv from ports as I see linker errors when we attempt
+    # to use the "native" iconv embedded in libc as suggested by the
+    # porting guide [1].
+    # [1] https://www.freebsd.org/doc/en/books/porters-handbook/using-iconv.html)
+    CONFIGURE_ARGS: "--with-gmp-includes=/usr/local/include --with-gmp-libraries=/usr/local/lib --with-iconv-includes=/usr/local/include --with-iconv-libraries=/usr/local/lib"
+    GHC_VERSION: 8.10.1
+    CABAL_INSTALL_VERSION: 3.2.0.0
+    BIN_DIST_PREP_TAR_COMP: "ghc-x86_64-portbld-freebsd.tar.xz"
+    TEST_ENV: "x86_64-freebsd"
+    BUILD_FLAVOUR: "validate"
+  after_script:
+    - cp -Rf $HOME/.cabal cabal-cache
+    - .gitlab/ci.sh clean
+  artifacts:
+    when: always
+    expire_in: 2 week
+  cache:
+    key: "freebsd-$GHC_VERSION"
+    paths:
+      - cabal-cache
+      - toolchain
+
+# Conditional due to lack of builder capacity
+validate-x86_64-freebsd:
+  extends: .build-x86_64-freebsd
+  stage: full-build
+  rules:
+    - if: '$CI_MERGE_REQUEST_LABELS =~ /.*FreeBSD.*/'
+
+nightly-x86_64-freebsd:
+  <<: *nightly
+  extends: .build-x86_64-freebsd
+  stage: full-build
+
+release-x86_64-freebsd:
+  <<: *release
+  extends: .build-x86_64-freebsd
+  stage: full-build
+
+.build-x86_64-freebsd-hadrian:
+  extends: .validate-hadrian
+  stage: full-build
+  tags:
+    - x86_64-freebsd
+  allow_failure: true
+  variables:
+    CONFIGURE_ARGS: "--with-gmp-includes=/usr/local/include --with-gmp-libraries=/usr/local/lib --with-iconv-includes=/usr/local/include --with-iconv-libraries=/usr/local/lib"
+    HADRIAN_ARGS: "--docs=no-sphinx"
+    GHC_VERSION: 8.6.3
+    CABAL_INSTALL_VERSION: 3.0.0.0
+    BIN_DIST_PREP_TAR_COMP: "ghc-x86_64-portbld-freebsd.tar.xz"
+    TEST_ENV: "x86_64-freebsd-hadrian"
+    FLAVOUR: "validate"
+  after_script:
+    - cp -Rf $HOME/.cabal cabal-cache
+    - .gitlab/ci.sh clean
+  artifacts:
+    when: always
+    expire_in: 2 week
+  cache:
+    key: "freebsd-$GHC_VERSION"
+    paths:
+      - cabal-cache
+      - toolchain
+
+# Disabled due to lack of builder capacity
+.validate-x86_64-freebsd-hadrian:
+  extends: .build-x86_64-freebsd-hadrian
+  stage: full-build
 
 #################################
 # x86_64-darwin
@@ -216,54 +367,71 @@ validate-x86_64-darwin:
   tags:
     - x86_64-darwin
   variables:
-    GHC_VERSION: "8.8.3"
-    CABAL_INSTALL_VERSION: 2.4.1.0
-    BIN_DIST_PREP_TAR_COMP: "bindistprep/ghc-x86_64-apple-darwin.tar.xz"
+    GHC_VERSION: 8.8.3
+    CABAL_INSTALL_VERSION: 3.0.0.0
+    BIN_DIST_PREP_TAR_COMP: "ghc-x86_64-apple-darwin.tar.xz"
     MACOSX_DEPLOYMENT_TARGET: "10.7"
     # Only Sierra and onwards supports clock_gettime. See #12858
     ac_cv_func_clock_gettime: "no"
     LANG: "en_US.UTF-8"
-    CONFIGURE_ARGS: --with-intree-gmp
+    CONFIGURE_ARGS: "--with-intree-gmp"
     TEST_ENV: "x86_64-darwin"
-  before_script:
-    - git clean -xdf && git submodule foreach git clean -xdf
-    - python3 .gitlab/fix-submodules.py
-    - git submodule sync --recursive
-    - git submodule update --init --recursive
-    - git checkout .gitmodules
-    - "git fetch https://gitlab.haskell.org/ghc/ghc-performance-notes.git refs/notes/perf:refs/notes/perf || true"
-
-    - bash .gitlab/darwin-init.sh
-    - PATH="`pwd`/toolchain/bin:$PATH"
+    BUILD_FLAVOUR: "perf"
   after_script:
     - cp -Rf $HOME/.cabal cabal-cache
+    - .gitlab/ci.sh clean
   artifacts:
     when: always
     expire_in: 2 week
   cache:
-    key: darwin
+    key: "darwin-$GHC_VERSION"
     paths:
       - cabal-cache
       - toolchain
 
+# Disabled because of OS X CI capacity
+.validate-x86_64-darwin-hadrian:
+  stage: full-build
+  tags:
+    - x86_64-darwin
+  variables:
+    GHC_VERSION: 8.8.3
+    MACOSX_DEPLOYMENT_TARGET: "10.7"
+    ac_cv_func_clock_gettime: "no"
+    LANG: "en_US.UTF-8"
+    CONFIGURE_ARGS: --with-intree-gmp
+    TEST_ENV: "x86_64-darwin-hadrian"
+    FLAVOUR: "validate"
+  script:
+    - .gitlab/ci.sh setup
+    - .gitlab/ci.sh configure
+    - .gitlab/ci.sh build_hadrian
+    - .gitlab/ci.sh test_hadrian
+  after_script:
+    - cp -Rf $HOME/.cabal cabal-cache
+    - .gitlab/ci.sh clean
+  artifacts:
+    when: always
+    expire_in: 2 week
+    reports:
+      junit: junit.xml
+    paths:
+      - ghc.tar.xz
+      - junit.xml
+
 .validate-linux:
   extends: .validate
   tags:
     - x86_64-linux
+  variables:
+    BUILD_FLAVOUR: "perf"
   before_script:
-    - git clean -xdf && git submodule foreach git clean -xdf
-    - python3 .gitlab/fix-submodules.py
-    - git submodule sync --recursive
-    - git submodule update --init --recursive
-    - git checkout .gitmodules
-    - "git fetch https://gitlab.haskell.org/ghc/ghc-performance-notes.git refs/notes/perf:refs/notes/perf || true"
       # Build hyperlinked sources for documentation when building releases
     - |
       if [[ -n "$CI_COMMIT_TAG" ]]; then
-        echo "EXTRA_HADDOCK_OPTS += --hyperlinked-source --quickjump" >> mk/build.mk
+        HADDOCK_HYPERLINKED_SOURCES=1
       fi
 
-    - bash .circleci/prepare-system.sh
     # workaround for docker permissions
     - sudo chown ghc:ghc -R .
   after_script:
@@ -285,9 +453,7 @@ validate-x86_64-darwin:
   allow_failure: true
   variables:
     TEST_ENV: "aarch64-linux-deb9"
-    BIN_DIST_PREP_TAR_COMP: "bindistprep/ghc-aarch64-linux-deb9.tar.xz"
-    # Inexplicably makeindex fails
-    BUILD_SPHINX_PDF: "NO"
+    BIN_DIST_PREP_TAR_COMP: "ghc-aarch64-linux-deb9.tar.xz"
   cache:
     key: linux-aarch64-deb9
   tags:
@@ -302,8 +468,41 @@ validate-aarch64-linux-deb9:
 nightly-aarch64-linux-deb9:
   <<: *nightly
   extends: .build-aarch64-linux-deb9
+  variables:
+    TEST_TYPE: slowtest
+
+#################################
+# armv7-linux-deb9
+#################################
+
+.build-armv7-linux-deb9:
+  extends: .validate-linux
+  stage: full-build
+  image: "registry.gitlab.haskell.org/ghc/ci-images/armv7-linux-deb9:$DOCKER_REV"
+  # Due to linker issues
+  allow_failure: true
+  variables:
+    TEST_ENV: "armv7-linux-deb9"
+    BIN_DIST_PREP_TAR_COMP: "ghc-armv7-linux-deb9.tar.xz"
+    CONFIGURE_ARGS: "--host=armv7-linux-gnueabihf --build=armv7-linux-gnueabihf --target=armv7-linux-gnueabihf"
+    # N.B. We disable ld.lld explicitly here because it appears to fail
+    # non-deterministically on ARMv7. See #18280.
+    LD: "ld.gold"
+    GccUseLdOpt: "-fuse-ld=gold"
+  cache:
+    key: linux-armv7-deb9
+  tags:
+    - armv7-linux
+
+validate-armv7-linux-deb9:
+  extends: .build-armv7-linux-deb9
   artifacts:
-    expire_in: 2 year
+    when: always
+    expire_in: 2 week
+
+nightly-armv7-linux-deb9:
+  <<: *nightly
+  extends: .build-armv7-linux-deb9
   variables:
     TEST_TYPE: slowtest
 
@@ -317,7 +516,7 @@ nightly-aarch64-linux-deb9:
   image: "registry.gitlab.haskell.org/ghc/ci-images/i386-linux-deb9:$DOCKER_REV"
   variables:
     TEST_ENV: "i386-linux-deb9"
-    BIN_DIST_PREP_TAR_COMP: "bindistprep/ghc-i386-deb9-linux.tar.xz"
+    BIN_DIST_PREP_TAR_COMP: "ghc-i386-deb9-linux.tar.xz"
   cache:
     key: linux-i386-deb9
 
@@ -332,23 +531,6 @@ nightly-i386-linux-deb9:
   extends: .build-i386-linux-deb9
   variables:
     TEST_TYPE: slowtest
-  artifacts:
-    when: always
-    expire_in: 2 week
-
-#################################
-# x86_64-linux-deb10
-#################################
-
-.build-x86_64-linux-deb10:
-  extends: .validate-linux
-  stage: full-build
-  image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb10:$DOCKER_REV"
-  variables:
-    TEST_ENV: "x86_64-linux-deb10"
-    BIN_DIST_PREP_TAR_COMP: "./ghc-x86_64-deb10-linux.tar.xz"
-  cache:
-    key: linux-x86_64-deb10
 
 #################################
 # x86_64-linux-deb9
@@ -356,40 +538,62 @@ nightly-i386-linux-deb9:
 
 .build-x86_64-linux-deb9:
   extends: .validate-linux
-  stage: full-build
   image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb9:$DOCKER_REV"
   variables:
     TEST_ENV: "x86_64-linux-deb9"
-    BIN_DIST_PREP_TAR_COMP: "bindistprep/ghc-x86_64-deb9-linux.tar.xz"
+    BIN_DIST_PREP_TAR_COMP: "./ghc-x86_64-deb9-linux.tar.xz"
   cache:
     key: linux-x86_64-deb9
 
-validate-x86_64-linux-deb9:
+# Disabled to reduce CI load
+.validate-x86_64-linux-deb9:
   extends: .build-x86_64-linux-deb9
+  stage: full-build
   artifacts:
     when: always
     expire_in: 2 week
 
+release-x86_64-linux-deb9:
+  <<: *release
+  extends: .build-x86_64-linux-deb9
+  stage: full-build
+
 nightly-x86_64-linux-deb9:
   <<: *nightly
   extends: .build-x86_64-linux-deb9
-  artifacts:
-    expire_in: 2 year
+  stage: full-build
   variables:
     TEST_TYPE: slowtest
 
 # N.B. Has DEBUG assertions enabled in stage2
 validate-x86_64-linux-deb9-debug:
   extends: .build-x86_64-linux-deb9
-  stage: build
+  stage: full-build
   variables:
     BUILD_FLAVOUR: validate
+    # Ensure that stage2 also has DEBUG enabled
+    ValidateSpeed: SLOW
+    # Override validate flavour default; see #16890.
+    BUILD_SPHINX_PDF: "YES"
+    TEST_TYPE: slowtest
     TEST_ENV: "x86_64-linux-deb9-debug"
+    BIN_DIST_PREP_TAR_COMP: "ghc-x86_64-deb9-linux-debug.tar.xz"
+  artifacts:
+    when: always
+    expire_in: 2 week
 
-validate-x86_64-linux-deb9-llvm:
+# Disabled to alleviate CI load
+.validate-x86_64-linux-deb9-llvm:
+  extends: .build-x86_64-linux-deb9
+  stage: full-build
+  variables:
+    BUILD_FLAVOUR: perf-llvm
+    TEST_ENV: "x86_64-linux-deb9-llvm"
+
+nightly-x86_64-linux-deb9-llvm:
+  <<: *nightly
   extends: .build-x86_64-linux-deb9
   stage: full-build
-  allow_failure: true
   variables:
     BUILD_FLAVOUR: perf-llvm
     TEST_ENV: "x86_64-linux-deb9-llvm"
@@ -397,11 +601,11 @@ validate-x86_64-linux-deb9-llvm:
 validate-x86_64-linux-deb9-integer-simple:
   extends: .build-x86_64-linux-deb9
   stage: full-build
-  allow_failure: true
   variables:
+    BUILD_FLAVOUR: validate
     INTEGER_LIBRARY: integer-simple
-    TEST_ENV: "x86_64-linux-deb9-integer-simple"
-    BIN_DIST_PREP_TAR_COMP: "bindistprep/ghc-x86_64-deb9-linux-integer-simple.tar.xz"
+    TEST_ENV: "x86_64-linux-deb9-integer-simple-validate"
+    BIN_DIST_PREP_TAR_COMP: "ghc-x86_64-deb9-linux-integer-simple.tar.xz"
 
 nightly-x86_64-linux-deb9-integer-simple:
   <<: *nightly
@@ -411,185 +615,205 @@ nightly-x86_64-linux-deb9-integer-simple:
     INTEGER_LIBRARY: integer-simple
     TEST_ENV: "x86_64-linux-deb9-integer-simple"
     TEST_TYPE: slowtest
-  artifacts:
-    expire_in: 2 year
 
-validate-x86_64-linux-deb9-unreg:
+validate-x86_64-linux-deb9-dwarf:
   extends: .build-x86_64-linux-deb9
   stage: full-build
-  allow_failure: true
   variables:
-    CONFIGURE_ARGS: --enable-unregisterised
-    TEST_ENV: "x86_64-linux-deb9-unreg"
+    CONFIGURE_ARGS: "--enable-dwarf-unwind"
+    BUILD_FLAVOUR: dwarf
+    TEST_ENV: "x86_64-linux-deb9-dwarf"
+    BIN_DIST_PREP_TAR_COMP: "ghc-x86_64-deb9-linux-dwarf.tar.xz"
+
+#################################
+# x86_64-linux-deb10
+#################################
 
-release-x86_64-linux-deb9-dwarf:
+.build-x86_64-linux-deb10:
   extends: .validate-linux
-  stage: build
-  image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb9:$DOCKER_REV"
-  allow_failure: true
+  stage: full-build
+  image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb10:$DOCKER_REV"
   variables:
-    CONFIGURE_ARGS: "--enable-dwarf-unwind"
-    BUILD_FLAVOUR: dwarf
-    TEST_ENV: "x86_64-linux-deb9"
-  artifacts:
-    when: always
-    expire_in: 2 week
+    TEST_ENV: "x86_64-linux-deb10"
+    BIN_DIST_PREP_TAR_COMP: "./ghc-x86_64-deb10-linux.tar.xz"
   cache:
-    key: linux-x86_64-deb9
+    key: linux-x86_64-deb10
 
+# Disabled to alleviate CI load
+.validate-x86_64-linux-deb10:
+  extends: .build-x86_64-linux-deb10
+  stage: full-build
 
-release-x86_64-linux-deb10-dwarf:
-  <<: *release
+nightly-x86_64-linux-deb10:
+  <<: *nightly
   extends: .build-x86_64-linux-deb10
   variables:
-    CONFIGURE_ARGS: "--enable-dwarf-unwind"
-    BUILD_FLAVOUR: dwarf
-    TEST_ENV: "x86_64-linux-deb10-dwarf"
-    BIN_DIST_PREP_TAR_COMP: "ghc-x86_64-deb10-linux-dwarf.tar.xz"
+    TEST_TYPE: slowtest
+
+release-x86_64-linux-deb10:
+  <<: *release
+  extends: .build-x86_64-linux-deb10
 
 #################################
 # x86_64-linux-deb8
 #################################
 
-release-x86_64-linux-deb8:
-  <<: *release
+.build-x86_64-linux-deb8:
   extends: .validate-linux
   stage: full-build
   image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb8:$DOCKER_REV"
+  # Due to #18298.
+  allow_failure: true
   variables:
     TEST_ENV: "x86_64-linux-deb8"
-    BIN_DIST_PREP_TAR_COMP: "bindistprep/ghc-x86_64-deb8-linux.tar.xz"
-    # Disable sphinx PDF output as our Debian image doesn't have the requisite packages
+    BIN_DIST_PREP_TAR_COMP: "ghc-x86_64-deb8-linux.tar.xz"
+    # Debian 8's Sphinx is too old to support the table directive's :widths:
+    # option: https://sourceforge.net/p/docutils/patches/120/
+    BUILD_SPHINX_HTML: "NO"
+    BUILD_SPHINX_INFO: "NO"
     BUILD_SPHINX_PDF: "NO"
+    BUILD_SPHINX_MAN: "NO"
   cache:
     key: linux-x86_64-deb8
+
+release-x86_64-linux-deb8:
+  <<: *release
+  extends: .build-x86_64-linux-deb8
+
+#################################
+# x86_64-linux-alpine
+#################################
+
+.build-x86_64-linux-alpine-hadrian:
+  extends: .validate-linux-hadrian
+  stage: full-build
+  image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-alpine:$DOCKER_REV"
+  # There are currently a few failing tests
+  allow_failure: true
+  variables:
+    TEST_ENV: "x86_64-linux-alpine"
+    BIN_DIST_PREP_TAR_COMP: "ghc-x86_64-alpine-linux.tar.xz"
+    # Can't use ld.gold due to #13958.
+    CONFIGURE_ARGS: "--disable-ld-override"
+    HADRIAN_ARGS: "--docs=no-sphinx"
+    # encoding004 due to lack of locale support
+    # T10458 due to fact that dynamic linker tries to reload libAS
+    BROKEN_TESTS: "encoding004 T10458"
+  cache:
+    key: linux-x86_64-alpine
   artifacts:
     when: always
     expire_in: 2 week
 
+release-x86_64-linux-alpine:
+  <<: *release
+  extends: .build-x86_64-linux-alpine-hadrian
+
+nightly-x86_64-linux-alpine:
+  <<: *nightly
+  extends: .build-x86_64-linux-alpine-hadrian
+
 #################################
 # x86_64-linux-centos7
 #################################
 
-release-x86_64-linux-centos7:
-  <<: *release
+.build-x86_64-linux-centos7:
   extends: .validate-linux
   stage: full-build
   image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-centos7:$DOCKER_REV"
   variables:
-    # For the testsuite
-    LANG: "en_US.UTF-8"
     # The sphinx release shipped with Centos 7 fails to build out documentation
     BUILD_SPHINX_HTML: "NO"
     BUILD_SPHINX_PDF: "NO"
     TEST_ENV: "x86_64-linux-centos7"
-    BIN_DIST_PREP_TAR_COMP: "bindistprep/ghc-x86_64-centos7-linux.tar.xz"
-  allow_failure: true
+    BIN_DIST_PREP_TAR_COMP: "ghc-x86_64-centos7-linux.tar.xz"
+    # CentOS seems to default to ascii
+    LANG: "en_US.UTF-8"
   cache:
     key: linux-x86_64-centos7
-  artifacts:
-    when: always
-    expire_in: 2 week
+
+release-x86_64-linux-centos7:
+  <<: *release
+  extends: .build-x86_64-linux-centos7
 
 #################################
 # x86_64-linux-fedora27
 #################################
 
-.build-x86_64-linux-fedora27:
+validate-x86_64-linux-fedora27:
   extends: .validate-linux
   stage: full-build
   image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-fedora27:$DOCKER_REV"
   variables:
     TEST_ENV: "x86_64-linux-fedora27"
-    BIN_DIST_PREP_TAR_COMP: "bindistprep/ghc-x86_64-fedora27-linux.tar.xz"
+    BIN_DIST_PREP_TAR_COMP: "ghc-x86_64-fedora27-linux.tar.xz"
   cache:
     key: linux-x86_64-fedora27
-
-validate-x86_64-linux-fedora27:
-  extends: .build-x86_64-linux-fedora27
   artifacts:
     when: always
     # These are used for head.hackage jobs therefore we keep them around for
     # longer.
     expire_in: 8 week
 
-release-x86_64-linux-fedora27:
-  <<: *release
-  extends: .build-x86_64-linux-fedora27
-
-release-x86_64-linux-fedora27-dwarf:
-  <<: *release
-  extends: .build-x86_64-linux-fedora27
-  variables:
-    CONFIGURE_ARGS: "--enable-dwarf-unwind"
-    BUILD_FLAVOUR: dwarf
-    TEST_ENV: "x86_64-linux-fedora27-dwarf"
-    BIN_DIST_PREP_TAR_COMP: "ghc-x86_64-fedora27-linux-dwarf.tar.xz"
-
 ############################################################
 # Validation via Pipelines (Windows)
 ############################################################
 
 .build-windows:
-  <<: *only-default
+  # For the reasons given in #17777 this build isn't reliable.
+  allow_failure: true
   before_script:
     - git clean -xdf
-    - git submodule foreach git clean -xdf
 
-    # Use a local temporary directory to ensure that concurrent builds don't
-    # interfere with one another
-    - |
-      mkdir tmp
-      set TMP=%cd%\tmp
-      set TEMP=%cd%\tmp
-
-    - set PATH=C:\msys64\usr\bin;%PATH%
-    - python .gitlab/fix-submodules.py
-    - git submodule sync --recursive
-    - git submodule update --init --recursive
-    - git checkout .gitmodules
-    - "git fetch https://gitlab.haskell.org/ghc/ghc-performance-notes.git refs/notes/perf:refs/notes/perf || true"
-    - bash .gitlab/win32-init.sh
+    # Setup toolchain
+    - bash .gitlab/ci.sh setup
   after_script:
-    - rd /s /q tmp
-    - robocopy /np /nfl /ndl /e "%APPDATA%\cabal" cabal-cache
-    - bash -c 'make clean || true'
+    - |
+      Copy-Item -Recurse -Path $Env:APPDATA\cabal -Destination cabal-cache
+    - bash .gitlab/ci.sh clean
   dependencies: []
   variables:
-    FORCE_SYMLINKS: 1
+    #FORCE_SYMLINKS: 1
     LANG: "en_US.UTF-8"
     SPHINXBUILD: "/mingw64/bin/sphinx-build.exe"
+    CABAL_INSTALL_VERSION: 3.0.0.0
+    GHC_VERSION: "8.8.3"
   cache:
     paths:
       - cabal-cache
-      - ghc-8.6.2
+      - toolchain
       - ghc-tarballs
 
 .build-windows-hadrian:
   extends: .build-windows
   stage: full-build
-  allow_failure: true
   variables:
-    GHC_VERSION: "8.8.3"
+    FLAVOUR: "validate"
+    # skipping perf tests for now since we build a quick-flavoured GHC,
+    # which might result in some broken perf tests?
+    HADRIAN_ARGS: "--docs=no-sphinx --skip-perf"
+
   script:
-    - |
-      python boot
-      bash -c './configure --enable-tarballs-autodownload GHC=`pwd`/toolchain/bin/ghc HAPPY=`pwd`/toolchain/bin/happy ALEX=`pwd`/toolchain/bin/alex'
-    - bash -c "PATH=`pwd`/toolchain/bin:$PATH hadrian/build.cabal.sh -j`mk/detect-cpu-count.sh` --flavour=Quick --docs=no-sphinx binary-dist"
-    - mv _build/bindist/ghc*.tar.xz ghc.tar.xz
-    # FIXME: Testsuite disabled due to #16156.
-    # - bash -c 'make V=0 test THREADS=`mk/detect-cpu-count.sh` JUNIT_FILE=../../junit.xml'
+    - bash .gitlab/ci.sh configure
+    - bash .gitlab/ci.sh build_hadrian
+    - bash .gitlab/ci.sh test_hadrian
   tags:
-    - x86_64-windows
+    - new-x86_64-windows
+    - test
   artifacts:
+    reports:
+      junit: junit.xml
+    expire_in: 2 week
     when: always
     paths:
       - ghc.tar.xz
+      - junit.xml
 
 validate-x86_64-windows-hadrian:
   extends: .build-windows-hadrian
   variables:
     MSYSTEM: MINGW64
+    TEST_ENV: "x86_64-windows-hadrian"
   cache:
     key: "x86_64-windows-hadrian-$WINDOWS_TOOLCHAIN_VERSION"
 
@@ -598,86 +822,94 @@ nightly-i386-windows-hadrian:
   extends: .build-windows-hadrian
   variables:
     MSYSTEM: MINGW32
+    TEST_ENV: "i386-windows-hadrian"
   cache:
     key: "i386-windows-hadrian-$WINDOWS_TOOLCHAIN_VERSION"
 
 .build-windows-make:
   extends: .build-windows
   stage: full-build
-  # due to #16084
-  allow_failure: true
   variables:
-    BUILD_FLAVOUR: "UNSET"
-    GHC_VERSION: "8.8.3"
-    BUILD_PROF_LIBS: "YES"
-    BIN_DIST_PREP_TAR_COMP: "bindistprep/ghc-x86_64-mingw32.tar.xz"
+    BUILD_FLAVOUR: "quick"
+    BIN_DIST_PREP_TAR_COMP: "ghc-x86_64-mingw32.tar.xz"
   script:
-    - |
-      python boot
-      bash -c './configure --enable-tarballs-autodownload GHC=`pwd`/toolchain/bin/ghc HAPPY=`pwd`/toolchain/bin/happy ALEX=`pwd`/toolchain/bin/alex $CONFIGURE_ARGS'
-    - bash -c "echo \"include mk/flavours/${BUILD_FLAVOUR}.mk\" > mk/build.mk"
-    - bash -c "echo \"GhcLibHcOpts+=-haddock\" >> mk/build.mk"
-    - bash -c "echo \"BUILD_PROF_LIBS = $BUILD_PROF_LIBS\" >> mk/build.mk"
-    - bash -c "PATH=`pwd`/toolchain/bin:$PATH make -j`mk/detect-cpu-count.sh`"
-    - bash -c "PATH=`pwd`/toolchain/bin:$PATH make binary-dist TAR_COMP_OPTS=-1"
-    - bash -c 'make V=0 test THREADS=`mk/detect-cpu-count.sh` JUNIT_FILE=../../junit.xml'
+    - bash .gitlab/ci.sh configure
+    - bash .gitlab/ci.sh build_make
+    - bash .gitlab/ci.sh test_make
   tags:
-    - x86_64-windows
+    - new-x86_64-windows
+    - test
   artifacts:
     when: always
     expire_in: 2 week
     reports:
       junit: junit.xml
     paths:
-      - ghc-*.tar.xz
+      # N.B. variable interpolation apparently doesn't work on Windows so
+      # this can't be $BIN_DIST_PREP_TAR_COMP
+      - "ghc-x86_64-mingw32.tar.xz"
       - junit.xml
 
-validate-x86_64-windows:
+.build-x86_64-windows-make:
   extends: .build-windows-make
   variables:
     MSYSTEM: MINGW64
-    GHC_VERSION: 8.8.4-rc1
-    GHC_TARBALL_URL: "http://home.smart-cactus.org/~ben/ghc/release-prep/8.8.4-rc1/ghc-8.8.3.20200710-x86_64-unknown-mingw32.tar.xz"
-    BUILD_FLAVOUR: "quick"
-    CONFIGURE_ARGS: "--target=x86_64-unknown-mingw32"
+    TEST_ENV: "x86_64-windows"
   cache:
     key: "x86_64-windows-$WINDOWS_TOOLCHAIN_VERSION"
 
+validate-x86_64-windows:
+  extends: .build-x86_64-windows-make
+
+nightly-x86_64-windows:
+  <<: *nightly
+  extends: .build-x86_64-windows-make
+  stage: full-build
+  variables:
+    BUILD_FLAVOUR: "validate"
+
 # Normal Windows validate builds are profiled; that won't do for releases.
 release-x86_64-windows:
   <<: *release
   extends: validate-x86_64-windows
   variables:
-    MSYSTEM: MINGW64
-    GHC_VERSION: 8.8.4-rc1
-    GHC_TARBALL_URL: "http://home.smart-cactus.org/~ben/ghc/release-prep/8.8.4-rc1/ghc-8.8.3.20200710-x86_64-unknown-mingw32.tar.xz"
     BUILD_FLAVOUR: "perf"
-    CONFIGURE_ARGS: "--target=x86_64-unknown-mingw32"
-
-release-i386-windows:
+    #
+release-x86_64-windows-integer-simple:
   <<: *release
-  extends: .build-windows-make
+  extends: validate-x86_64-windows
   variables:
-    MSYSTEM: MINGW32
+    INTEGER_LIBRARY: integer-simple
     BUILD_FLAVOUR: "perf"
-    CONFIGURE_ARGS: "--target=i386-unknown-mingw32"
-    # Due to #15934
-    BUILD_PROF_LIBS: "NO"
-  cache:
-    key: "i386-windows-$WINDOWS_TOOLCHAIN_VERSION"
 
-nightly-i386-windows:
-  <<: *nightly
+
+.build-i386-windows-make:
   extends: .build-windows-make
   variables:
     MSYSTEM: MINGW32
-    CONFIGURE_ARGS: "--target=i386-unknown-mingw32"
-    BUILD_FLAVOUR: "quick"
     # Due to #15934
     BUILD_PROF_LIBS: "NO"
+    TEST_ENV: "i386-windows"
+  # Due to #17736
+  allow_failure: true
   cache:
     key: "i386-windows-$WINDOWS_TOOLCHAIN_VERSION"
 
+validate-i386-windows:
+  extends: .build-i386-windows-make
+  variables:
+    BUILD_FLAVOUR: "perf"
+
+release-i386-windows:
+  <<: *release
+  extends: .build-i386-windows-make
+  variables:
+    BUILD_FLAVOUR: "perf"
+
+nightly-i386-windows:
+  <<: *nightly
+  extends: .build-i386-windows-make
+
 ############################################################
 # Cleanup
 ############################################################
@@ -687,40 +919,24 @@ nightly-i386-windows:
 #
 # As noted in [1], gitlab-runner's shell executor doesn't clean up its working
 # directory after builds. Unfortunately, we are forced to use the shell executor
-# on Windows. To avoid running out of disk space we add a stage at the end of
-# the build to remove the \GitLabRunner\builds directory. Since we only run a
-# single build at a time on Windows this should be safe.
+# on Darwin. To avoid running out of disk space we add a stage at the end of
+# the build to remove the /.../GitLabRunner/builds directory. Since we only run a
+# single build at a time on Darwin this should be safe.
+#
+# We used to have a similar cleanup job on Windows as well however it ended up
+# being quite fragile as we have multiple Windows builders yet there is no
+# guarantee that the cleanup job is run on the same machine as the build itself
+# was run. Consequently we were forced to instead handle cleanup with a separate
+# cleanup cron job on Windows.
 #
 # [1] https://gitlab.com/gitlab-org/gitlab-runner/issues/3856
 
-# See Note [Cleanup after shell executor]
-cleanup-windows:
-  <<: *only-default
-  stage: cleanup
-  tags:
-    - x86_64-windows
-  dependencies: []
-  before_script:
-    - echo "Time to clean up"
-  script:
-    - echo "Let's go"
-  after_script:
-    - set "BUILD_DIR=%CI_PROJECT_DIR%"
-    - set "BUILD_DIR=%BUILD_DIR:/=\%"
-    - echo "Cleaning %BUILD_DIR%"
-    - cd \GitLabRunner
-    # This is way more complicated than it should be:
-    # See https://stackoverflow.com/questions/1965787
-    - del %BUILD_DIR%\* /F /Q
-    - for /d %%p in (%BUILD_DIR%\*) do rd /Q /S "%%p"
-    - exit /b 0
-
 # See Note [Cleanup after shell executor]
 cleanup-darwin:
-  <<: *only-default
   stage: cleanup
   tags:
     - x86_64-darwin
+  when: always
   dependencies: []
   before_script:
     - echo "Time to clean up"
@@ -737,19 +953,56 @@ cleanup-darwin:
 # Packaging
 ############################################################
 
+doc-tarball:
+  stage: packaging
+  tags:
+    - x86_64-linux
+  image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb9:$DOCKER_REV"
+  dependencies:
+    - validate-x86_64-linux-deb9-debug
+    - validate-x86_64-windows
+  variables:
+    LINUX_BINDIST: "ghc-x86_64-deb9-linux-debug.tar.xz"
+    WINDOWS_BINDIST: "ghc-x86_64-mingw32.tar.xz"
+  # Due to Windows allow_failure
+  allow_failure: true
+  artifacts:
+    paths:
+      - haddock.html.tar.xz
+      - libraries.html.tar.xz
+      - users_guide.html.tar.xz
+      - index.html
+      - "*.pdf"
+  script:
+    - |
+      if [ ! -f "$LINUX_BINDIST" ]; then
+        echo "Error: $LINUX_BINDIST does not exist. Did the Debian 9 job fail?"
+        exit 1
+      fi
+      if [ ! -f "$WINDOWS_BINDIST" ]; then
+        echo "Error: $WINDOWS_BINDIST does not exist. Did the 64-bit Windows job fail?"
+        exit 1
+      fi
+    - rm -Rf docs
+    - bash -ex distrib/mkDocs/mkDocs $LINUX_BINDIST $WINDOWS_BINDIST
+    - ls -lh
+    - mv docs/*.tar.xz docs/index.html .
+
 source-tarball:
-  <<: *release
   stage: packaging
   tags:
     - x86_64-linux
   image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb9:$DOCKER_REV"
   dependencies: []
+  rules:
+    - if: $CI_COMMIT_TAG
+      when: always
   artifacts:
     paths:
       - ghc-*.tar.xz
       - version
   script:
-    - mk/get-win32-tarballs.sh download all
+    - python3 mk/get-win32-tarballs.py download all
     - ./boot
     - ./configure
     - make sdist
@@ -770,9 +1023,8 @@ source-tarball:
 # pipeline.
 
 .hackage:
-  <<: *only-default
-  stage: hackage
-  image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb9:$DOCKER_REV"
+  stage: testing
+  image: ghcci/x86_64-linux-deb9:0.2
   tags:
     - x86_64-linux
   dependencies: []
@@ -781,6 +1033,10 @@ source-tarball:
   script:
     - bash .gitlab/start-head.hackage.sh
 
+hackage:
+  extends: .hackage
+  when: manual
+
 hackage-label:
   extends: .hackage
   rules:
@@ -790,3 +1046,69 @@ nightly-hackage:
   <<: *nightly
   extends: .hackage
 
+############################################################
+# Nofib testing
+############################################################
+
+perf-nofib:
+  stage: testing
+  dependencies:
+    - validate-x86_64-linux-deb9-dwarf
+  image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb9:$DOCKER_REV"
+  rules:
+    - if: $CI_MERGE_REQUEST_ID
+    - if: '$CI_COMMIT_BRANCH == "master"'
+    - if: '$CI_COMMIT_BRANCH =~ /ghc-[0.9]+\.[0-9]+/'
+  tags:
+    - x86_64-linux
+  script:
+    - root=$(pwd)/ghc
+    - |
+      mkdir tmp
+      tar -xf ghc-x86_64-deb9-linux-dwarf.tar.xz -C tmp
+      pushd tmp/ghc-*/
+      ./configure --prefix=$root
+      make install
+      popd
+      rm -Rf tmp
+    - export BOOT_HC=$(which ghc)
+    - cabal update; cabal install -w $BOOT_HC regex-compat
+    - export PATH=$root/bin:$PATH
+    - make -C nofib boot mode=fast -j$CPUS
+    - "make -C nofib EXTRA_RUNTEST_OPTS='-cachegrind +RTS -V0 -RTS' NoFibRuns=1 mode=fast -j$CPUS 2>&1 | tee nofib.log"
+  artifacts:
+    expire_in: 12 week
+    when: always
+    paths:
+      - nofib.log
+
+############################################################
+# Documentation deployment via GitLab Pages
+############################################################
+
+pages:
+  stage: deploy
+  dependencies:
+    - doc-tarball
+  image: ghcci/x86_64-linux-deb9:0.2
+  # Due to Windows allow_failure
+  allow_failure: true
+  tags:
+    - x86_64-linux
+  script:
+    - mkdir -p public/doc
+    - tar -xf haddock.html.tar.xz -C public/doc
+    - tar -xf libraries.html.tar.xz -C public/doc
+    - tar -xf users_guide.html.tar.xz -C public/doc
+    - |
+      cat >public/index.html <<EOF
+      <!DOCTYPE HTML>
+      <meta charset="UTF-8">
+      <meta http-equiv="refresh" content="1; url=doc/">
+      EOF
+    - cp -f index.html public/doc
+  rules:
+    - if: '$CI_COMMIT_BRANCH == "master"'
+  artifacts:
+    paths:
+      - public


=====================================
.gitlab/ci.sh
=====================================
@@ -0,0 +1,464 @@
+#!/usr/bin/env bash
+# shellcheck disable=SC2230
+
+# This is the primary driver of the GitLab CI infrastructure.
+
+set -e -o pipefail
+
+# Configuration:
+hackage_index_state="@1579718451"
+
+# Colors
+BLACK="0;30"
+GRAY="1;30"
+RED="0;31"
+LT_RED="1;31"
+BROWN="0;33"
+LT_BROWN="1;33"
+GREEN="0;32"
+LT_GREEN="1;32"
+BLUE="0;34"
+LT_BLUE="1;34"
+PURPLE="0;35"
+LT_PURPLE="1;35"
+CYAN="0;36"
+LT_CYAN="1;36"
+WHITE="1;37"
+LT_GRAY="0;37"
+
+export LANG=C.UTF-8
+export LC_ALL=C.UTF-8
+
+# GitLab Pipelines log section delimiters
+# https://gitlab.com/gitlab-org/gitlab-foss/issues/14664
+start_section() {
+  name="$1"
+  echo -e "section_start:$(date +%s):$name\015\033[0K"
+}
+
+end_section() {
+  name="$1"
+  echo -e "section_end:$(date +%s):$name\015\033[0K"
+}
+
+echo_color() {
+  local color="$1"
+  local msg="$2"
+  echo -e "\033[${color}m${msg}\033[0m"
+}
+
+error() { echo_color "${RED}" "$1"; }
+warn() { echo_color "${LT_BROWN}" "$1"; }
+info() { echo_color "${LT_BLUE}" "$1"; }
+
+fail() { error "error: $1"; exit 1; }
+
+function run() {
+  info "Running $*..."
+  "$@" || ( error "$* failed"; return 1; )
+}
+
+TOP="$(pwd)"
+
+function mingw_init() {
+  case "$MSYSTEM" in
+    MINGW32)
+      triple="i386-unknown-mingw32"
+      boot_triple="i386-unknown-mingw32" # triple of bootstrap GHC
+      ;;
+    MINGW64)
+      triple="x86_64-unknown-mingw32"
+      boot_triple="x86_64-unknown-mingw32" # triple of bootstrap GHC
+      ;;
+    *)
+      fail "win32-init: Unknown MSYSTEM $MSYSTEM"
+      ;;
+  esac
+
+  # Bring mingw toolchain into PATH.
+  # This is extracted from /etc/profile since this script inexplicably fails to
+  # run under gitlab-runner.
+  # shellcheck disable=SC1091
+  source /etc/msystem
+  MINGW_MOUNT_POINT="${MINGW_PREFIX}"
+  PATH="$MINGW_MOUNT_POINT/bin:$PATH"
+
+  # We always use mingw64 Python to avoid path length issues like #17483.
+  export PYTHON="/mingw64/bin/python3"
+}
+
+# This will contain GHC's local native toolchain
+toolchain="$TOP/toolchain"
+mkdir -p "$toolchain/bin"
+PATH="$toolchain/bin:$PATH"
+
+export METRICS_FILE="$CI_PROJECT_DIR/performance-metrics.tsv"
+
+cores="$(mk/detect-cpu-count.sh)"
+
+# Use a local temporary directory to ensure that concurrent builds don't
+# interfere with one another
+mkdir -p "$TOP/tmp"
+export TMP="$TOP/tmp"
+export TEMP="$TOP/tmp"
+
+function darwin_setup() {
+  # It looks like we already have python2 here and just installing python3
+  # does not work.
+  brew upgrade python
+  brew install ghc cabal-install ncurses gmp
+
+  pip3 install sphinx
+  # PDF documentation disabled as MacTeX apparently doesn't include xelatex.
+  #brew cask install mactex
+}
+
+function show_tool() {
+  local tool="$1"
+  info "$tool = ${!tool}"
+  ${!tool} --version
+}
+
+function set_toolchain_paths() {
+  needs_toolchain=1
+  case "$(uname)" in
+    Linux) needs_toolchain="" ;;
+    *) ;;
+  esac
+
+  if [[ -n "$needs_toolchain" ]]; then
+      # These are populated by setup_toolchain
+      GHC="$toolchain/bin/ghc$exe"
+      CABAL="$toolchain/bin/cabal$exe"
+      HAPPY="$toolchain/bin/happy$exe"
+      ALEX="$toolchain/bin/alex$exe"
+  else
+      GHC="$(which ghc)"
+      CABAL="/usr/local/bin/cabal"
+      HAPPY="$HOME/.cabal/bin/happy"
+      ALEX="$HOME/.cabal/bin/alex"
+  fi
+  export GHC
+  export CABAL
+  export HAPPY
+  export ALEX
+}
+
+# Extract GHC toolchain
+function setup() {
+  if [ -d "$TOP/cabal-cache" ]; then
+      info "Extracting cabal cache..."
+      mkdir -p "$cabal_dir"
+      cp -Rf cabal-cache/* "$cabal_dir"
+  fi
+
+  if [[ -n "$needs_toolchain" ]]; then
+    setup_toolchain
+  fi
+  case "$(uname)" in
+    Darwin) darwin_setup ;;
+    *) ;;
+  esac
+
+  # Make sure that git works
+  git config user.email "ghc-ci at gitlab-haskell.org"
+  git config user.name "GHC GitLab CI"
+
+  info "====================================================="
+  info "Toolchain versions"
+  info "====================================================="
+  show_tool GHC
+  show_tool CABAL
+  show_tool HAPPY
+  show_tool ALEX
+}
+
+function fetch_ghc() {
+  local v="$GHC_VERSION"
+  if [[ -z "$v" ]]; then
+      fail "GHC_VERSION is not set"
+  fi
+
+  if [ ! -e "$GHC" ]; then
+      start_section "fetch GHC"
+      url="https://downloads.haskell.org/~ghc/${GHC_VERSION}/ghc-${GHC_VERSION}-${boot_triple}.tar.xz"
+      info "Fetching GHC binary distribution from $url..."
+      curl "$url" > ghc.tar.xz || fail "failed to fetch GHC binary distribution"
+      tar -xJf ghc.tar.xz || fail "failed to extract GHC binary distribution"
+      case "$(uname)" in
+        MSYS_*|MINGW*)
+          cp -r "ghc-${GHC_VERSION}"/* "$toolchain"
+          ;;
+        *)
+          pushd "ghc-${GHC_VERSION}"
+          ./configure --prefix="$toolchain"
+          "$MAKE" install
+          popd
+          ;;
+      esac
+      rm -Rf "ghc-${GHC_VERSION}" ghc.tar.xz
+      end_section "fetch GHC"
+  fi
+
+}
+
+function fetch_cabal() {
+  local v="$CABAL_INSTALL_VERSION"
+  if [[ -z "$v" ]]; then
+      fail "CABAL_INSTALL_VERSION is not set"
+  fi
+
+  if [ ! -e "$CABAL" ]; then
+      start_section "fetch GHC"
+      case "$(uname)" in
+        # N.B. Windows uses zip whereas all others use .tar.xz
+        MSYS_*|MINGW*)
+          case "$MSYSTEM" in
+            MINGW32) cabal_arch="i386" ;;
+            MINGW64) cabal_arch="x86_64" ;;
+            *) fail "unknown MSYSTEM $MSYSTEM" ;;
+          esac
+          url="https://downloads.haskell.org/~cabal/cabal-install-$v/cabal-install-$v-$cabal_arch-unknown-mingw32.zip"
+          info "Fetching cabal binary distribution from $url..."
+          curl "$url" > "$TMP/cabal.zip"
+          unzip "$TMP/cabal.zip"
+          mv cabal.exe "$CABAL"
+          ;;
+        *)
+          local base_url="https://downloads.haskell.org/~cabal/cabal-install-$v/"
+          case "$(uname)" in
+            Darwin) cabal_url="$base_url/cabal-install-$v-x86_64-apple-darwin17.7.0.tar.xz" ;;
+            FreeBSD)
+              #cabal_url="$base_url/cabal-install-$v-x86_64-portbld-freebsd.tar.xz" ;;
+              cabal_url="http://home.smart-cactus.org/~ben/ghc/cabal-install-3.0.0.0-x86_64-portbld-freebsd.tar.xz" ;;
+            *) fail "don't know where to fetch cabal-install for $(uname)"
+          esac
+          echo "Fetching cabal-install from $cabal_url"
+          curl "$cabal_url" > cabal.tar.xz
+          tar -xJf cabal.tar.xz
+          mv cabal "$toolchain/bin"
+          ;;
+      esac
+      end_section "fetch GHC"
+  fi
+}
+
+# For non-Docker platforms we prepare the bootstrap toolchain
+# here. For Docker platforms this is done in the Docker image
+# build.
+function setup_toolchain() {
+  fetch_ghc
+  fetch_cabal
+  cabal_install="$CABAL v2-install --index-state=$hackage_index_state --installdir=$toolchain/bin"
+  # Avoid symlinks on Windows
+  case "$(uname)" in
+    MSYS_*|MINGW*) cabal_install="$cabal_install --install-method=copy" ;;
+    *) ;;
+  esac
+
+  if [ ! -e "$HAPPY" ]; then
+      info "Building happy..."
+      cabal update
+      $cabal_install happy
+  fi
+
+  if [ ! -e "$ALEX" ]; then
+      info "Building alex..."
+      cabal update
+      $cabal_install alex
+  fi
+}
+
+function cleanup_submodules() {
+  start_section "clean submodules"
+  info "Cleaning submodules..."
+  # On Windows submodules can inexplicably get into funky states where git
+  # believes that the submodule is initialized yet its associated repository
+  # is not valid. Avoid failing in this case with the following insanity.
+  git submodule sync --recursive || git submodule deinit --force --all
+  git submodule update --init --recursive
+  git submodule foreach git clean -xdf
+  end_section "clean submodules"
+}
+
+function prepare_build_mk() {
+  if [[ -z "$BUILD_FLAVOUR" ]]; then fail "BUILD_FLAVOUR is not set"; fi
+  if [[ -z ${BUILD_SPHINX_HTML:-} ]]; then BUILD_SPHINX_HTML=YES; fi
+  if [[ -z ${BUILD_SPHINX_PDF:-} ]]; then BUILD_SPHINX_PDF=YES; fi
+  if [[ -z ${INTEGER_LIBRARY:-} ]]; then INTEGER_LIBRARY=integer-gmp; fi
+
+  cat > mk/build.mk <<EOF
+V=1
+HADDOCK_DOCS=YES
+LATEX_DOCS=YES
+HSCOLOUR_SRCS=YES
+BUILD_SPHINX_HTML=$BUILD_SPHINX_HTML
+BUILD_SPHINX_PDF=$BUILD_SPHINX_PDF
+BeConservative=YES
+INTEGER_LIBRARY=$INTEGER_LIBRARY
+XZ_CMD=$XZ
+
+BuildFlavour=$BUILD_FLAVOUR
+ifneq "\$(BuildFlavour)" ""
+include mk/flavours/\$(BuildFlavour).mk
+endif
+GhcLibHcOpts+=-haddock
+EOF
+
+  if [ -n "$HADDOCK_HYPERLINKED_SOURCES" ]; then
+    echo "EXTRA_HADDOCK_OPTS += --hyperlinked-source --quickjump" >> mk/build.mk
+  fi
+
+  case "$(uname)" in
+    Darwin) echo "libraries/integer-gmp_CONFIGURE_OPTS += --configure-option=--with-intree-gmp" >> mk/build.mk ;;
+    *) ;;
+  esac
+
+  info "build.mk is:"
+  cat mk/build.mk
+}
+
+function configure() {
+  start_section "booting"
+  run python3 boot
+  end_section "booting"
+
+  local target_args=""
+  if [[ -n "$triple" ]]; then
+    target_args="--target=$triple"
+  fi
+
+  start_section "configuring"
+  run ./configure \
+    --enable-tarballs-autodownload \
+    $target_args \
+    $CONFIGURE_ARGS \
+    GHC="$GHC" \
+    HAPPY="$HAPPY" \
+    ALEX="$ALEX" \
+    || ( cat config.log; fail "configure failed" )
+  end_section "configuring"
+}
+
+function build_make() {
+  prepare_build_mk
+  if [[ -z "$BIN_DIST_PREP_TAR_COMP" ]]; then
+    fail "BIN_DIST_PREP_TAR_COMP is not set"
+  fi
+
+  echo "include mk/flavours/${BUILD_FLAVOUR}.mk" > mk/build.mk
+  echo 'GhcLibHcOpts+=-haddock' >> mk/build.mk
+  run "$MAKE" -j"$cores" $MAKE_ARGS
+  run "$MAKE" -j"$cores" binary-dist-prep TAR_COMP_OPTS=-1
+  ls -lh "$BIN_DIST_PREP_TAR_COMP"
+}
+
+function fetch_perf_notes() {
+  info "Fetching perf notes..."
+  "$TOP/.gitlab/test-metrics.sh" pull
+}
+
+function push_perf_notes() {
+  info "Pushing perf notes..."
+  "$TOP/.gitlab/test-metrics.sh" push
+}
+
+function test_make() {
+  run "$MAKE" test_bindist TEST_PREP=YES
+  run "$MAKE" V=0 test \
+    THREADS="$cores" \
+    JUNIT_FILE=../../junit.xml
+}
+
+function build_hadrian() {
+  if [ -z "$FLAVOUR" ]; then
+    fail "FLAVOUR not set"
+  fi
+
+  run_hadrian binary-dist
+
+  mv _build/bindist/ghc*.tar.xz ghc.tar.xz
+}
+
+function test_hadrian() {
+  cd _build/bindist/ghc-*/
+  run ./configure --prefix="$TOP"/_build/install
+  run "$MAKE" install
+  cd ../../../
+
+  run_hadrian \
+    test \
+    --summary-junit=./junit.xml \
+    --test-compiler="$TOP"/_build/install/bin/ghc
+}
+
+function clean() {
+  rm -R tmp
+  run "$MAKE" --quiet clean || true
+  run rm -Rf _build
+}
+
+function run_hadrian() {
+  run hadrian/build-cabal \
+    --flavour="$FLAVOUR" \
+    -j"$cores" \
+    --broken-test="$BROKEN_TESTS" \
+    $HADRIAN_ARGS \
+    $@
+}
+
+# A convenience function to allow debugging in the CI environment.
+function shell() {
+  local cmd=$@
+  if [ -z "$cmd" ]; then
+    cmd="bash -i"
+  fi
+  run $cmd
+}
+
+# Determine Cabal data directory
+case "$(uname)" in
+  MSYS_*|MINGW*) exe=".exe"; cabal_dir="$APPDATA/cabal" ;;
+  *) cabal_dir="$HOME/.cabal"; exe="" ;;
+esac
+
+# Platform-specific environment initialization
+MAKE="make"
+case "$(uname)" in
+  MSYS_*|MINGW*) mingw_init ;;
+  Darwin) boot_triple="x86_64-apple-darwin" ;;
+  FreeBSD)
+    boot_triple="x86_64-portbld-freebsd"
+    MAKE="gmake"
+    ;;
+  Linux) ;;
+  *) fail "uname $(uname) is not supported" ;;
+esac
+
+set_toolchain_paths
+
+case $1 in
+  setup) setup && cleanup_submodules ;;
+  configure) configure ;;
+  build_make) build_make ;;
+  test_make)
+    fetch_perf_notes
+    res=0
+    test_make || res=$?
+    push_perf_notes
+    exit $res ;;
+  build_hadrian) build_hadrian ;;
+  # N.B. Always push notes, even if the build fails. This is okay to do as the
+  # testsuite driver doesn't record notes for tests that fail due to
+  # correctness.
+  test_hadrian)
+    fetch_perf_notes
+    res=0
+    test_hadrian || res=$?
+    push_perf_notes
+    exit $res ;;
+  run_hadrian) run_hadrian $@ ;;
+  clean) clean ;;
+  shell) shell $@ ;;
+  *) fail "unknown mode $1" ;;
+esac


=====================================
.gitlab/darwin-init.sh deleted
=====================================
@@ -1,41 +0,0 @@
-#!/bin/bash
-
-set -e
-
-toolchain=`pwd`/toolchain
-PATH="$toolchain/bin:$PATH"
-
-if [ -d "`pwd`/cabal-cache" ]; then
-    cp -Rf cabal-cache $HOME/.cabal
-fi
-
-if [ ! -e $toolchain/bin/ghc ]; then
-    mkdir -p tmp
-    cd tmp
-    ghc_tarball="https://downloads.haskell.org/~ghc/$GHC_VERSION/ghc-$GHC_VERSION-x86_64-apple-darwin.tar.xz"
-    echo "Fetching GHC from $ghc_tarball"
-    curl $ghc_tarball | tar -xJ
-    cd ghc-$GHC_VERSION
-    ./configure --prefix=$toolchain
-    make install
-    cd ../..
-    rm -Rf tmp
-fi
-
-if [ ! -e $toolchain/bin/cabal ]; then
-    cabal_tarball="https://downloads.haskell.org/~cabal/cabal-install-$CABAL_INSTALL_VERSION/cabal-install-$CABAL_INSTALL_VERSION-x86_64-apple-darwin-sierra.tar.xz"
-    echo "Fetching cabal-install from $cabal_tarball"
-    curl $cabal_tarball | tar -xz
-    mv cabal $toolchain/bin
-fi
-
-if [ ! -e $toolchain/bin/happy ]; then
-    cabal update
-    cabal new-install happy --symlink-bindir=$toolchain/bin
-fi
-
-if [ ! -e $toolchain/bin/alex ]; then
-    cabal update
-    cabal new-install alex --symlink-bindir=$toolchain/bin
-fi
-


=====================================
.gitlab/linters/check-makefiles.py
=====================================
@@ -1,5 +1,11 @@
 #!/usr/bin/env python3
 
+"""
+Linters for testsuite makefiles
+"""
+
+from linter import run_linters, RegexpLinter
+
 """
 Warn for use of `--interactive` inside Makefiles (#11468).
 
@@ -7,13 +13,21 @@ Encourage the use of `$(TEST_HC_OPTS_INTERACTIVE)` instead of
 `$(TEST_HC_OPTS) --interactive -ignore-dot-ghci -v0`. It's too easy to
 forget one of those flags when adding a new test.
 """
+interactive_linter = \
+    RegexpLinter(r'--interactive',
+                 message = "Warning: Use `$(TEST_HC_OPTS_INTERACTIVE)` instead of `--interactive -ignore-dot-ghci -v0`."
+                ).add_path_filter(lambda path: path.name == 'Makefile')
 
-from linter import run_linters, RegexpLinter
+test_hc_quotes_linter = \
+    RegexpLinter('\t\\$\\(TEST_HC\\)',
+                 message = "Warning: $(TEST_HC) should be quoted in Makefiles.",
+                ).add_path_filter(lambda path: path.name == 'Makefile')
 
 linters = [
-    RegexpLinter(r'--interactive',
-                 message = "Warning: Use `$(TEST_HC_OPTS_INTERACTIVE)` instead of `--interactive -ignore-dot-ghci -v0`.")
+    interactive_linter,
+    test_hc_quotes_linter,
 ]
 
 if __name__ == '__main__':
-    run_linters(linters) #$, subdir='testsuite')
+    run_linters(linters,
+                subdir='testsuite')


=====================================
.gitlab/linters/check-version-number.sh
=====================================
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+
+set -e
+
+grep -E -q '\[[0-9]+\.[0-9]+\.[0-9]+\]' configure.ac ||
+  ( echo "error: configure.ac: GHC version number must have three components."; exit 1 )


=====================================
.gitlab/linters/linter.py
=====================================
@@ -7,10 +7,11 @@ import sys
 import re
 import textwrap
 import subprocess
-from typing import List, Optional
+from pathlib import Path
+from typing import List, Optional, Callable, Sequence
 from collections import namedtuple
 
-def lint_failure(file, line_no, line_content, message):
+def lint_failure(file, line_no: int, line_content: str, message: str):
     """ Print a lint failure message. """
     wrapper = textwrap.TextWrapper(initial_indent='  ',
                                    subsequent_indent='    ')
@@ -29,7 +30,7 @@ def lint_failure(file, line_no, line_content, message):
 
     print(textwrap.dedent(msg))
 
-def get_changed_files(base_commit, head_commit,
+def get_changed_files(base_commit: str, head_commit: str,
                       subdir: str = '.'):
     """ Get the files changed by the given range of commits. """
     cmd = ['git', 'diff', '--name-only',
@@ -46,12 +47,21 @@ class Linter(object):
     """
     def __init__(self):
         self.warnings = [] # type: List[Warning]
+        self.path_filters = [] # type: List[Callable[[Path], bool]]
 
     def add_warning(self, w: Warning):
         self.warnings.append(w)
 
-    def lint(self, path):
-        pass
+    def add_path_filter(self, f: Callable[[Path], bool]) -> "Linter":
+        self.path_filters.append(f)
+        return self
+
+    def do_lint(self, path: Path):
+        if all(f(path) for f in self.path_filters):
+            self.lint(path)
+
+    def lint(self, path: Path):
+        raise NotImplementedError
 
 class LineLinter(Linter):
     """
@@ -59,44 +69,55 @@ class LineLinter(Linter):
     the given line from a file and calls :func:`add_warning` for any lint
     issues found.
     """
-    def lint(self, path):
-        if os.path.isfile(path):
-            with open(path, 'r') as f:
+    def lint(self, path: Path):
+        if path.is_file():
+            with path.open('r') as f:
                 for line_no, line in enumerate(f):
                     self.lint_line(path, line_no+1, line)
 
-    def lint_line(self, path, line_no, line):
-        pass
+    def lint_line(self, path: Path, line_no: int, line: str):
+        raise NotImplementedError
 
 class RegexpLinter(LineLinter):
     """
     A :class:`RegexpLinter` produces the given warning message for
     all lines matching the given regular expression.
     """
-    def __init__(self, regex, message):
+    def __init__(self, regex: str, message: str):
         LineLinter.__init__(self)
         self.re = re.compile(regex)
         self.message = message
 
-    def lint_line(self, path, line_no, line):
+    def lint_line(self, path: Path, line_no: int, line: str):
         if self.re.search(line):
             w = Warning(path=path, line_no=line_no, line_content=line[:-1],
                         message=self.message)
             self.add_warning(w)
 
-def run_linters(linters: List[Linter],
+def run_linters(linters: Sequence[Linter],
                 subdir: str = '.') -> None:
     import argparse
     parser = argparse.ArgumentParser()
-    parser.add_argument('base', help='Base commit')
-    parser.add_argument('head', help='Head commit')
+    subparsers = parser.add_subparsers()
+
+    subparser = subparsers.add_parser('commits', help='Lint a range of commits')
+    subparser.add_argument('base', help='Base commit')
+    subparser.add_argument('head', help='Head commit')
+    subparser.set_defaults(get_linted_files=lambda args:
+                            get_changed_files(args.base, args.head, subdir))
+
+    subparser = subparsers.add_parser('files', help='Lint a range of commits')
+    subparser.add_argument('file', nargs='+', help='File to lint')
+    subparser.set_defaults(get_linted_files=lambda args: args.file)
+
     args = parser.parse_args()
 
-    for path in get_changed_files(args.base, args.head, subdir):
+    linted_files = args.get_linted_files(args)
+    for path in linted_files:
         if path.startswith('.gitlab/linters'):
             continue
         for linter in linters:
-            linter.lint(path)
+            linter.do_lint(Path(path))
 
     warnings = [warning
                 for linter in linters


=====================================
.gitlab/win32-init.sh deleted
=====================================
@@ -1,50 +0,0 @@
-#!/bin/bash
-
-set -e
-
-toolchain=`pwd`/toolchain
-PATH="$toolchain/bin:/mingw64/bin:$PATH"
-
-if [ -d "`pwd`/cabal-cache" ]; then
-    cp -Rf cabal-cache $APPDATA/cabal
-fi
-
-if [ ! -e $toolchain/bin/ghc ]; then
-    case $MSYSTEM in
-      MINGW32)
-        triple="i386-unknown-mingw32"
-        ;;
-      MINGW64)
-        triple="x86_64-unknown-mingw32"
-        ;;
-      *)
-        echo "win32-init: Unknown MSYSTEM $MSYSTEM"
-        exit 1
-        ;;
-    esac
-    if [ -z "$GHC_TARBALL_URL" ]; then
-      GHC_TARBALL_URL="https://downloads.haskell.org/~ghc/$GHC_VERSION/ghc-$GHC_VERSION-$triple.tar.xz"
-    fi
-    curl "$GHC_TARBALL_URL" | tar -xJ
-    mv ghc-$GHC_VERSION toolchain
-fi
-
-if [ ! -e $toolchain/bin/cabal ]; then
-    url="https://downloads.haskell.org/~cabal/cabal-install-2.4.1.0/cabal-install-2.4.1.0-x86_64-unknown-mingw32.zip"
-    curl $url > /tmp/cabal.zip
-    unzip /tmp/cabal.zip
-    mv cabal.exe $toolchain/bin
-fi
-
-if [ ! -e $toolchain/bin/happy ]; then
-    cabal update
-    cabal install happy
-    cp $APPDATA/cabal/bin/happy $toolchain/bin
-fi
-
-if [ ! -e $toolchain/bin/alex ]; then
-    cabal update
-    cabal install alex
-    cp $APPDATA/cabal/bin/alex $toolchain/bin
-fi
-



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9f52e0ca0cc0430da4d30de4228844f92c89226b

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9f52e0ca0cc0430da4d30de4228844f92c89226b
You're receiving this email because of your account on gitlab.haskell.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20200711/ed527bcc/attachment-0001.html>


More information about the ghc-commits mailing list