diff --git a/.github/workflows/haskell-ci-hackage.patch b/.github/workflows/haskell-ci-hackage.patch new file mode 100644 index 0000000..e7b8702 --- /dev/null +++ b/.github/workflows/haskell-ci-hackage.patch @@ -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 }} diff --git a/.github/workflows/haskell-ci.yml b/.github/workflows/haskell-ci.yml index 4b470f0..518f76b 100644 --- a/.github/workflows/haskell-ci.yml +++ b/.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 @@ 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 @@ -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 }} diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 9bd075a..a43ca36 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -59,58 +59,59 @@ ## 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](https://xmonad.github.io/xmonad-docs/) - 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. Post 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) + - [Haskell Discourse](https://discourse.haskell.org/) - * 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 diff --git a/cabal.haskell-ci b/cabal.haskell-ci index c78ed7f..3604812 100644 --- a/cabal.haskell-ci +++ b/cabal.haskell-ci @@ -5,6 +5,9 @@ apt: libxrandr-dev libxss-dev +github-patches: + .github/workflows/haskell-ci-hackage.patch + raw-project package xmonad flags: +pedantic diff --git a/src/XMonad/Config.hs b/src/XMonad/Config.hs index f35fc50..8d50092 100644 --- a/src/XMonad/Config.hs +++ b/src/XMonad/Config.hs @@ -39,7 +39,7 @@ import XMonad.Operations import XMonad.ManageHook import qualified XMonad.StackSet as W import Data.Bits ((.|.)) -import Data.Default +import Data.Default.Class import Data.Monoid import qualified Data.Map as M import System.Exit diff --git a/src/XMonad/Core.hs b/src/XMonad/Core.hs index 07fa95c..9c7a280 100644 --- a/src/XMonad/Core.hs +++ b/src/XMonad/Core.hs @@ -43,7 +43,7 @@ import Control.Monad.State import Control.Monad.Reader import Data.Semigroup import Data.Traversable (for) -import Data.Default +import Data.Default.Class import System.FilePath import System.IO import System.Info diff --git a/xmonad.cabal b/xmonad.cabal index 85382ff..76fce23 100644 --- a/xmonad.cabal +++ b/xmonad.cabal @@ -35,10 +35,11 @@ build-type: Simple extra-source-files: README.md CHANGES.md CONFIG + CONTRIBUTING.md + INSTALL.md + MAINTAINERS.md STYLE - tests/*.hs - tests/Properties/*.hs - tests/Properties/Layout/*.hs + TUTORIAL.md man/xmonad.1.markdown man/xmonad.1 man/xmonad.1.html @@ -71,7 +72,7 @@ library build-depends: base >= 4.9 && < 5 , X11 >= 1.10 && < 1.11 , containers - , data-default + , data-default-class , directory , filepath , mtl @@ -79,7 +80,6 @@ library , setlocale , transformers >= 0.3 , unix - , utf8-string >= 0.3 && < 1.1 ghc-options: -funbox-strict-fields -Wall -Wno-unused-do-bind -- Keep this in sync with the oldest version in 'tested-with' @@ -91,7 +91,7 @@ library executable xmonad main-is: Main.hs - build-depends: base, X11, mtl, unix, xmonad + build-depends: base, xmonad ghc-options: -Wall -Wno-unused-do-bind -- Keep this in sync with the oldest version in 'tested-with'