Skip to content

Add dockerized CI and a GHC 9.2-9.12 matrix - #3

Merged
onslaughtq merged 4 commits into
mainfrom
add-ci-multi-ghc
Aug 24, 2026
Merged

Add dockerized CI and a GHC 9.2-9.12 matrix#3
onslaughtq merged 4 commits into
mainfrom
add-ci-multi-ghc

Conversation

@onslaughtq

@onslaughtq onslaughtq commented Aug 20, 2026

Copy link
Copy Markdown
Member

Adds CI to a repo that had none, and makes the repo buildable with stack again.

stack.yaml pinned lts-16.9 (GHC 8.8.3), which cannot satisfy the
crypton-connection >= 0.3 bound this package has claimed since 1cbd6b9 — so
stack build could not work here at all, and the hspec suite in
ftp-client/test/test.hs (which has existed since 2019) was reachable only by
running cabal by hand.

What's here

  • Dockerized haskell-tools CI following the org pattern: compose.yaml,
    scripts/ that re-exec into the container, one stack-ghc-*.yaml per GHC, and
    a workflow whose matrix is discovered by globbing those files — so adding a GHC
    later is one new file, no workflow edit.
  • All three packages converted to hpack, with the generated .cabal files
    committed alongside, as elsewhere in the org.
  • Tests against GHC 9.2.8, 9.4.8, 9.6.7, 9.8.4, 9.10.3 and 9.12.4.

No Haskell source changes.

Dependency bounds this turned up

Building against six GHCs found three bounds that were wrong:

  • resourcet >= 1.2 && < 1.3 in ftp-client-conduit excluded resourcet-1.3.0,
    which is what current Stackage snapshots carry
    — so the package could not
    build against them. The module uses resourcet only for the MonadResource
    class, unchanged across that boundary, so the bound moves to < 1.4.
  • ftp-client-conduit required crypton-connection >= 0.4 while ftp-client
    accepted >= 0.3. The conduit code uses exactly one symbol from it,
    connectionClose, which 0.3 has. Relaxed to match.
  • base >= 4.8 (ftp-client) and >= 4.7 (ftp-client-conduit) claimed support
    back to GHC 7.10 and 7.8. Nothing that old can build these packages, because
    crypton-connection does not exist there. Both become >= 4.16, the oldest GHC
    actually tested, and tested-with now records the set.

crypton-connection is absent from lts-21 and earlier, so the 9.2 and 9.4 rungs
pin the crypton stack explicitly. The comments in those files explain why the
newer crypton-x509 1.9 series is avoided.

Deliberately not included

No fourmolu and no formatting job — the code has never been formatted and doing
it here would bury the CI change in a whole-repo diff. No strict ghc-options
flag either. Both arrive in later PRs in this stack.

Stack position

First of six stacked branches, each containing the one before it. This one is
source-neutral on purpose, so every later PR arrives with a green matrix:

  1. add-ci-multi-ghc ← this PR
  2. fix-response-line-partiality
  3. pr-2-multiline-and-handle-exports (closes exposing handle creation functions and fixed issue in reading multi line response  #2)
  4. add-ci-flag
  5. add-henforcer-fourmolu
  6. fix-audit-findings

Every flipstone repo running the multi-GHC matrix workflow defines its
packages in package.yaml, so move all three here to match. The generated
.cabal files are committed alongside, as they are elsewhere. Metadata and
bounds carry over unchanged apart from the corrections below.

Three bounds were wrong, and building against six GHC versions is what
surfaced them:

resourcet >= 1.2 && < 1.3 excluded resourcet-1.3.0, which is what lts-24
carries, so ftp-client-conduit could not build there at all. The module
uses resourcet only for the MonadResource class, which is unchanged
across that boundary, so the bound moves to < 1.4.

ftp-client-conduit asked for crypton-connection >= 0.4 while ftp-client
accepted >= 0.3. The conduit code uses exactly one symbol from the
package, connectionClose, which 0.3 has. Relaxing it to match ftp-client
lets both build on lts-22, whose crypton-connection is 0.3.2.

base >= 4.8 (ftp-client) and base >= 4.7 (ftp-client-conduit) claimed
support back to GHC 7.10. Nothing that old can build these packages,
because crypton-connection did not exist then. Both become >= 4.16, the
oldest GHC now actually tested, and tested-with records the rest.
This repo had no CI, and stack could not build it at all: stack.yaml
pinned lts-16.9 (GHC 8.8.3), which cannot satisfy the crypton-connection
dependency the package has claimed since 1cbd6b9. The hspec suite was
reachable only by running cabal by hand, which is why it went unnoticed
during review of #2.

Adopts the same shape as the rest of the org: a dev container on the
haskell-tools image, scripts that re-exec themselves into it, one
stack-ghc-*.yaml per GHC, and a workflow whose matrix is discovered by
globbing those files. scripts/test-all uses the same glob, so local and
CI coverage cannot drift.

ftp-client is the only repo here depending on crypton-connection, so the
old resolvers need help. lts-21 has no crypton-connection and lts-20 has
no crypton at all, so both pin the versions that shipped together in
lts-22. The newer crypton-x509 1.9 series is deliberately avoided: it
wants crypton 1.1 and the crypton-asn1-* rewrite, which would mean
replacing most of the snapshot's crypto stack.

No fourmolu and no formatting job, following haskell-non-empty-text --
this code has never been formatted and reformatting it would rewrite
every line. No strict ghc-options flag yet either; -Wall currently
reports 27 warnings in ftp-client and 22 across the other two, which is
a separate cleanup.

Lock files are committed and scripts/test enforces them in CI with
--lock-file error-on-write, so stack.yaml.lock comes out of .gitignore.
Both packages have published metadata changes on this branch -- corrected
base bounds, a corrected resourcet bound and a relaxed crypton-connection
bound -- with no API change, so both get a patch bump. Neither package had
a changelog; seed one for each.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Dockerized CI across GHC 9.2–9.12 and restores Stack builds.

Changes:

  • Adds six Stack configurations with lock files.
  • Converts all packages to hpack and corrects dependency bounds.
  • Adds containerized build, test, Cabal, and shellcheck workflows.

Reviewed changes

Copilot reviewed 25 out of 34 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
stack.yaml.lock Locks the default snapshot.
stack.yaml Selects GHC 9.10 by default.
stack-base.yaml Shares package and PVP settings.
stack-ghc-9.2.yaml Configures GHC 9.2 dependencies.
stack-ghc-9.2.yaml.lock Locks the GHC 9.2 build.
stack-ghc-9.4.yaml Configures GHC 9.4 dependencies.
stack-ghc-9.4.yaml.lock Locks the GHC 9.4 build.
stack-ghc-9.6.yaml Configures GHC 9.6.
stack-ghc-9.6.yaml.lock Locks the GHC 9.6 build.
stack-ghc-9.8.yaml Configures GHC 9.8.
stack-ghc-9.8.yaml.lock Locks the GHC 9.8 build.
stack-ghc-9.10.yaml Configures GHC 9.10.
stack-ghc-9.10.yaml.lock Locks the GHC 9.10 build.
stack-ghc-9.12.yaml Configures GHC 9.12.
stack-ghc-9.12.yaml.lock Locks the GHC 9.12 build.
scripts/test-all Tests every matrix configuration.
scripts/test Runs local or CI tests.
scripts/shellcheck Adds shell-script linting.
scripts/shell Opens the development shell.
scripts/lib/run-in-container.sh Re-executes scripts in Docker.
scripts/cabal-latest Builds with latest GHC and dependencies.
scripts/build Provides the aggregate build command.
scripts/bootstrap Initializes local Docker resources.
ftp-client/package.yaml Adds hpack metadata and updated bounds.
ftp-client/ftp-client.cabal Regenerates the package definition.
ftp-client/CHANGELOG.md Documents the corrected base bound.
ftp-client-conduit/package.yaml Adds hpack metadata and corrected bounds.
ftp-client-conduit/ftp-client-conduit.cabal Regenerates the conduit package definition.
ftp-client-conduit/CHANGELOG.md Documents dependency-bound corrections.
example/package.yaml Adds hpack metadata for the example.
example/example.cabal Regenerates the example package definition.
compose.yaml Defines the development container.
.gitignore Ignores generated build artifacts.
.github/workflows/main.yaml Adds the CI matrix and validation jobs.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread scripts/lib/run-in-container.sh Outdated
Comment thread .github/workflows/main.yaml
Both from review feedback on #3.

scripts/lib/run-in-container.sh had an unquoted $0, which word splits and glob
expands on a path containing spaces or metacharacters. The shellcheck job did
not catch it: the file has no shebang, so file(1) reports it as ASCII text and
scripts/shellcheck, which filters on "shell script", never passed it to the
linter. Adding a shebang -- inert in a sourced file -- brings it into the
linted set, and shellcheck then does report SC2086 for the unquoted $0, so the
check now covers what it previously missed.

The workflow only ran on push. A fork pull request pushes to the fork, not
here, so external contributions received no checks at all.

Adding pull_request alongside push would have doubled every same-repo run: the
concurrency group keys on github.ref_name, which is the branch for a push but
<n>/merge for a pull request, so the two never share a group and neither
cancels the other. Scoping push to the default branch would have stopped branch
pushes getting CI. Instead pull_request runs only when the head repository is
not this one -- exactly the case where no push event fires here. Same-repo
branches get one run from push, fork pull requests get one from pull_request,
and nothing runs twice.

This does not give same-repo pull requests merge-commit testing; they still
test the pushed head. That is unreachable while keeping branch-push CI without
duplicate runs, so it is a deliberate trade rather than an oversight.
@onslaughtq
onslaughtq marked this pull request as ready for review August 22, 2026 21:34
@onslaughtq
onslaughtq merged commit dc80cbe into main Aug 24, 2026
15 checks passed
@ysangkok
ysangkok deleted the add-ci-multi-ghc branch August 24, 2026 15:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants