Piggy-back on the haskell-ci workflow for automatic releases to Hackage.

This extends the workflow with two additional triggers:

 * When the Haskell-CI workflow is triggered manually with a non-empty version
   input (matching the version in the cabal file), a candidate release is
   uploaded to Hackage and docs are submitted for it as Hackage can't build
   them itself (https://github.com/haskell/hackage-server/issues/925).

   Note that promoting the candidate on Hackage discards the uploaded docs
   (https://github.com/haskell/hackage-server/issues/70). Don't do that.

 * When a release is created on GitHub, a final release is uploaded to Hackage
   and docs are submitted for it.

The automation uses a special Hackage user: https://hackage.haskell.org/user/xmonad
and each repo (X11, xmonad, xmonad-contrib) has its own HACKAGE_API_KEY token
set in GitHub repository secrets.

--- .github/workflows/haskell-ci.yml.orig
+++ .github/workflows/haskell-ci.yml
@@ -14,8 +14,15 @@
 #
 name: Haskell-CI
 on:
-  - push
-  - pull_request
+  push:
+  pull_request:
+  release:
+    types:
+      - published
+  workflow_dispatch:
+    inputs:
+      version:
+        description: candidate version (must match version in cabal file)
 jobs:
   linux:
     name: Haskell-CI - Linux - ${{ matrix.compiler }}
@@ -31,6 +38,7 @@
             compilerVersion: 9.0.2
             setup-method: ghcup
             allow-failure: false
+            upload: true
           - compiler: ghc-8.10.7
             compilerKind: ghc
             compilerVersion: 8.10.7
@@ -240,8 +240,80 @@
           ${CABAL} -vnormal check
       - name: haddock
         run: |
-          $CABAL v2-haddock --haddock-all $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
+          $CABAL v2-haddock --haddock-all $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH --haddock-for-hackage --builddir $GITHUB_WORKSPACE/haddock all
       - name: unconstrained build
         run: |
           rm -f cabal.project.local
           $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+      - name: upload artifacts (sdist)
+        if: matrix.upload
+        uses: actions/upload-artifact@v2
+        with:
+          path: ${{ github.workspace }}/sdist/*.tar.gz
+      - name: upload artifacts (haddock)
+        if: matrix.upload
+        uses: actions/upload-artifact@v2
+        with:
+          path: ${{ github.workspace }}/haddock/*-docs.tar.gz
+      - name: hackage upload (candidate)
+        if: matrix.upload && github.event_name == 'workflow_dispatch' && github.event.inputs.version != ''
+        shell: bash
+        run: |
+          set -ex
+          PACKAGE_VERSION="${PACKAGE_VERSION#v}"
+          res=$(
+            curl \
+              --silent --show-error --output /dev/stderr --write-out '%{http_code}' \
+              --header "Accept: text/plain" \
+              --header "Authorization: X-ApiKey $HACKAGE_API_KEY" \
+              --form package=@"${GITHUB_WORKSPACE}/sdist/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz" \
+              https://hackage.haskell.org/packages/candidates/
+          )
+          [[ $res == 2?? ]]  # TODO: --fail-with-body once curl 7.76.0 is available
+          res=$(
+            curl \
+              --silent --show-error --output /dev/stderr --write-out '%{http_code}' \
+              -X PUT \
+              --header "Accept: text/plain" \
+              --header "Authorization: X-ApiKey $HACKAGE_API_KEY" \
+              --header "Content-Type: application/x-tar" \
+              --header "Content-Encoding: gzip" \
+              --data-binary @"${GITHUB_WORKSPACE}/haddock/${PACKAGE_NAME}-${PACKAGE_VERSION}-docs.tar.gz" \
+              https://hackage.haskell.org/package/${PACKAGE_NAME}-${PACKAGE_VERSION}/candidate/docs
+          )
+          [[ $res == 2?? ]]
+        env:
+          HACKAGE_API_KEY: ${{ secrets.HACKAGE_API_KEY }}
+          PACKAGE_NAME: ${{ github.event.repository.name }}
+          PACKAGE_VERSION: ${{ github.event.inputs.version }}
+      - name: hackage upload (release)
+        if: matrix.upload && github.event_name == 'release'
+        shell: bash
+        run: |
+          set -ex
+          PACKAGE_VERSION="${PACKAGE_VERSION#v}"
+          res=$(
+            curl \
+              --silent --show-error --output /dev/stderr --write-out '%{http_code}' \
+              --header "Accept: text/plain" \
+              --header "Authorization: X-ApiKey $HACKAGE_API_KEY" \
+              --form package=@"${GITHUB_WORKSPACE}/sdist/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz" \
+              https://hackage.haskell.org/packages/
+          )
+          [[ $res == 2?? ]]  # TODO: --fail-with-body once curl 7.76.0 is available
+          res=$(
+            curl \
+              --silent --show-error --output /dev/stderr --write-out '%{http_code}' \
+              -X PUT \
+              --header "Accept: text/plain" \
+              --header "Authorization: X-ApiKey $HACKAGE_API_KEY" \
+              --header "Content-Type: application/x-tar" \
+              --header "Content-Encoding: gzip" \
+              --data-binary @"${GITHUB_WORKSPACE}/haddock/${PACKAGE_NAME}-${PACKAGE_VERSION}-docs.tar.gz" \
+              https://hackage.haskell.org/package/${PACKAGE_NAME}-${PACKAGE_VERSION}/docs
+          )
+          [[ $res == 2?? ]]
+        env:
+          HACKAGE_API_KEY: ${{ secrets.HACKAGE_API_KEY }}
+          PACKAGE_NAME: ${{ github.event.repository.name }}
+          PACKAGE_VERSION: ${{ github.event.release.tag_name }}