Skip to content

Commit

Permalink
Automate and document releasing to Hackage
Browse files Browse the repository at this point in the history
Pioneered in https://github.com/xmonad/X11, this adds automation for
Hackage releases and updates MAINTAINERS.md with simplified instruction
for the release procedure.

Related: xmonad#75
Related: xmonad#264
Related: xmonad/xmonad-contrib#393
  • Loading branch information
liskin committed Jun 7, 2021
1 parent 061b1bd commit 3a499d5
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 39 deletions.
115 changes: 115 additions & 0 deletions .github/workflows/haskell-ci-hackage.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
Piggy-back on the haskell-ci workflow for automatic releases to Hackage.

This extends the workflow with two additional triggers:

* When a release is created on GitHub, 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).

* To make a final release, the workflow can be triggered manually by entering
the correct version number matching the version in the cabal file. This is
here because promoting the candidate on Hackage discards the uploaded docs
(https://github.com/haskell/hackage-server/issues/70).

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,17 @@
#
name: Haskell-CI
on:
- - push
- - pull_request
+ push:
+ pull_request:
+ release:
+ types:
+ - published
+ workflow_dispatch:
+ inputs:
+ version:
+ # releases to Hackage are final and cannot be reverted, thus require
+ # manual entry of version as a poor man's mistake avoidance
+ description: version (must match version in cabal file)
jobs:
linux:
name: Haskell-CI - Linux - ${{ matrix.compiler }}
@@ -28,6 +37,7 @@
include:
- compiler: ghc-9.0.1
allow-failure: false
+ upload: true
- compiler: ghc-8.10.4
allow-failure: false
- compiler: ghc-8.8.4
@@ -171,8 +181,66 @@
${CABAL} -vnormal check
- name: haddock
run: |
- $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
+ $CABAL v2-haddock $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 == 'release'
+ run: |
+ set -ex
+ PACKAGE_VERSION="${PACKAGE_VERSION#v}"
+ curl \
+ --silent --show-error --fail \
+ --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/
+ curl \
+ --silent --show-error --fail \
+ -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
+ env:
+ HACKAGE_API_KEY: ${{ secrets.HACKAGE_API_KEY }}
+ PACKAGE_NAME: ${{ github.event.repository.name }}
+ PACKAGE_VERSION: ${{ github.event.release.tag_name }}
+ - name: hackage upload (release)
+ if: matrix.upload && github.event_name == 'workflow_dispatch'
+ run: |
+ set -ex
+ PACKAGE_VERSION="${PACKAGE_VERSION#v}"
+ curl \
+ --silent --show-error --fail \
+ --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/
+ curl \
+ --silent --show-error --fail \
+ -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
+ env:
+ HACKAGE_API_KEY: ${{ secrets.HACKAGE_API_KEY }}
+ PACKAGE_NAME: ${{ github.event.repository.name }}
+ PACKAGE_VERSION: ${{ github.event.inputs.version }}
74 changes: 71 additions & 3 deletions .github/workflows/haskell-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,17 @@
#
name: Haskell-CI
on:
- push
- pull_request
push:
pull_request:
release:
types:
- published
workflow_dispatch:
inputs:
version:
# releases to Hackage are final and cannot be reverted, thus require
# manual entry of version as a poor man's mistake avoidance
description: version (must match version in cabal file)
jobs:
linux:
name: Haskell-CI - Linux - ${{ matrix.compiler }}
Expand All @@ -28,6 +37,7 @@ jobs:
include:
- compiler: ghc-9.0.1
allow-failure: false
upload: true
- compiler: ghc-8.10.4
allow-failure: false
- compiler: ghc-8.8.4
Expand Down Expand Up @@ -171,8 +181,66 @@ jobs:
${CABAL} -vnormal check
- name: haddock
run: |
$CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
$CABAL v2-haddock $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 == 'release'
run: |
set -ex
PACKAGE_VERSION="${PACKAGE_VERSION#v}"
curl \
--silent --show-error --fail \
--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/
curl \
--silent --show-error --fail \
-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
env:
HACKAGE_API_KEY: ${{ secrets.HACKAGE_API_KEY }}
PACKAGE_NAME: ${{ github.event.repository.name }}
PACKAGE_VERSION: ${{ github.event.release.tag_name }}
- name: hackage upload (release)
if: matrix.upload && github.event_name == 'workflow_dispatch'
run: |
set -ex
PACKAGE_VERSION="${PACKAGE_VERSION#v}"
curl \
--silent --show-error --fail \
--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/
curl \
--silent --show-error --fail \
-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
env:
HACKAGE_API_KEY: ${{ secrets.HACKAGE_API_KEY }}
PACKAGE_NAME: ${{ github.event.repository.name }}
PACKAGE_VERSION: ${{ github.event.inputs.version }}
72 changes: 36 additions & 36 deletions MAINTAINERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,58 +59,58 @@

## Release Procedures

When the time comes to release another version of XMonad and Contrib...
When the time comes to release another version of xmonad and xmonad-contrib:

1. Create a release branch (e.g., `release-0.XX`).
1. Update the version number in all the `*.cabal` files and let the CI
verify that it all builds together.

This will allow you to separate the release process from main
development. Changes you make on this branch will be merged back
into `master` as one of the last steps.
2. Review documentation files and make sure they are accurate:

2. Update the version number in the `*.cabal` files and verify
dependencies and documentation. This includes the `tested-with:`
field.
- [`README.md`](README.md)
- [`CHANGES.md`](CHANGES.md)
- [`INSTALL.md`](INSTALL.md)
- [`man/xmonad.1.markdown.in`](man/xmonad.1.markdown.in)
- haddocks <!-- TODO: link to web with doc snapshots once there's one -->

3. Use the [packdeps][] tool to ensure you have the dependency
versions correct. If you need to update the version of a
dependency then you should rebuild and retest.
If the manpage changes, wait for the CI to rebuild the rendered outputs.

4. Review documentation files and make sure they are accurate:
3. Check dependency bounds. In particular, [packdeps][] can be used to check
if any new versions are excluded by the upper bounds specified.
Also, make sure that `tested-with:` covers several recent releases of
GHC, and that `.github/workflows/stack.yml` tests with several recent
revisions of [Stackage][] LTS.

- `README.md`
- `CHANGES.md`
- and the `example-config.hs` in the `xmonad-testing` repo
4. Create a release on GitHub:

5. Generate the manpage:
- https://github.com/xmonad/xmonad/releases/new
- https://github.com/xmonad/xmonad-contrib/releases/new

* `cabal configure` with the `-fgeneratemanpage` flag
* Build the project
* Run the `generatemanpage` tool from the top level of this repo
* Review the man page: `man -l man/xmonad.1`
CI will upload a release candidate to Hackage. Check again that
everything looks good. To publish a final release, run the CI workflow
once again with the correct version number:

6. Tag the repository with the release version (e.g., `v0.13`)
- https://github.com/xmonad/xmonad/actions/workflows/haskell-ci.yml
- https://github.com/xmonad/xmonad-contrib/actions/workflows/haskell-ci.yml

7. Build the project tarballs (`cabal sdist`)
See [haskell-ci-hackage.patch][] for details about the release infrastructure.

8. Upload the packages to Hackage (`cabal upload`)
5. Update the website:

9. Merge the release branches into `master`
- Post a [new release announcement][web-announce]
- Check install instructions, guided tour, keybindings cheat sheet, …

10. Update the website:
7. Send e-mail announcement to:

* Generate and push haddocks with `xmonad-web/gen-docs.sh`
- [XMonad mailing list](https://mail.haskell.org/mailman/listinfo/xmonad)
- [Haskell Cafe](https://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe)

* Check that `tour.html` and `intro.html` are up to date, and
mention all core bindings
See [old announcements][old-announce] for inspiration.

11. Update the topic for the IRC channel (`#xmonad`)

12. Send the `announce-0.XX.txt` file to:

- XMonad mailing list
- Haskell Cafe

[packdeps]: http://hackage.haskell.org/package/packdeps
[packdeps]: https://hackage.haskell.org/package/packdeps
[Stackage]: https://www.stackage.org/
[haskell-ci-hackage.patch]: .github/workflows/haskell-ci-hackage.patch
[web-announce]: https://github.com/xmonad/xmonad-web/tree/gh-pages/news/_posts
[old-announce]: https://github.com/xmonad/xmonad-web/tree/55614349421ebafaef4a47424fcb16efa80ff768

## Website and Other Accounts

Expand Down
3 changes: 3 additions & 0 deletions cabal.haskell-ci
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ apt:
libxrandr-dev
libxss-dev

github-patches:
.github/workflows/haskell-ci-hackage.patch

raw-project
package xmonad
flags: +pedantic

0 comments on commit 3a499d5

Please sign in to comment.