Skip to content

Turn on henforcer and fourmolu - #7

Draft
onslaughtq wants to merge 7 commits into
add-ci-flagfrom
add-henforcer-fourmolu
Draft

Turn on henforcer and fourmolu#7
onslaughtq wants to merge 7 commits into
add-ci-flagfrom
add-henforcer-fourmolu

Conversation

@onslaughtq

Copy link
Copy Markdown
Member

Both of these were held back while the CI and -Werror work landed. Three commits: the plugin, then the formatter config and its CI job, then the reformat on its own so it can be checked by re-running the formatter instead of read.

Two things a reviewer won't guess.

allowedOpenUnaliasedImports is 1, not 0. henforcer counts the implicit import Prelude as an open import, so 0 is unreachable without NoImplicitPrelude — which is why every repo in the org uses 1. That one slot is Prelude, and every explicit import now carries an alias or an import list.

henforcer is pinned from Hackage rather than the git commit the other repos pin. Its README still says it hasn't been released, but 1.0.0.1 is published and its tested-with reaches further than the commit the fleet points at. This is also the first repo here to run it under GHC 9.12.

The documentation rules (maximumExportsPlusHeaderUndocumented and the @since caps) are deliberately left off. Network.FTP.Client exports about forty-five names, most undocumented, so turning those on is a documentation project rather than a tooling change; beeline comments the same two rules out.

.git-blame-ignore-revs names the reformat commit. To skip it in blame:

git config blame.ignoreRevsFile .git-blame-ignore-revs

Stacked: add-ci-multi-ghcfix-response-line-partialitypr-2-multiline-and-handle-exportsadd-ci-flagadd-henforcer-fourmolufix-audit-findings. Merge bottom-up.

Adopts the plugin per the org convention, gated at impl (ghc >= 9.6) like
beeline, shrubbery and bounded-text. GHC 9.2 cannot run it at all -- it needs
base >= 4.17 -- and 9.4 is left off the gate to match the fleet, though
henforcer itself supports 9.4.

Pinned from Hackage rather than the git commit every other repo uses. The
plugin's README still says it is unreleased, but henforcer-1.0.0.1 is
published, and its tested-with reaches GHC 9.14.1 -- newer than the commit
the fleet pins. This is also the first repo in the org to run henforcer under
9.12, which works.

The config sets allowedOpenUnaliasedImports = 1, not 0. henforcer counts the
implicit `import Prelude` as an open import, so 0 is unreachable without
NoImplicitPrelude -- which is why every repo in the fleet uses 1. That one
slot is Prelude, so every explicit import now carries an alias or an import
list.

The documentation caps are deliberately left out. Network.FTP.Client exports
roughly forty-five names, most undocumented, and enforcing that is a
documentation project rather than a tooling change. beeline comments the same
two rules out.

Imports follow the house style of a qualified alias plus an explicit list for
operators: attoparsec as AC, Control.Exception as Exception, Data.Bits as
Bits, Network.Connection as Connection, Control.Monad.IO.Class as MIO, with
(<=<) and (***) imported by name. Prepositive `import qualified` is kept
rather than the postpositive form the codex shows, since these modules are
Haskell2010 and would otherwise need ImportQualifiedPost.

Module headers gain the Copyright field the config requires. The conduit
module's header also named Network.FTP.Client, a copy-paste error.
fourmolu.yaml is copied byte for byte from the rest of the org -- all twelve
repos that have it are identical, and it matches the config documented in
codex programming_style.md.

scripts/format-repo follows the git ls-files variant used by eight of the
eleven repos, rather than the find-piped-through-grep one in bounded-text and
shrubbery, whose pattern is unanchored and unescaped and so matches any path
containing "hs". The safe.directory line matters: the container runs as root
against a checkout owned by the runner, and git otherwise refuses to read it.
The three repos that omit it are exactly the three with no CI job, so it has
never been exercised there.

The check job needs no stack-root cache because nothing compiles; fourmolu is
a plain binary on the image's PATH.

This commit only adds the tooling. The repository is not yet formatted, so
the new job would fail here -- the reformat is the next commit.
Mechanical only, no functional changes. Verify by re-running
./scripts/format-repo rather than by reading the diff.
The blame ignore file follows purescript-erumu, which does the same for its
purs-tidy sweep. Configure git to use it with

    git config blame.ignoreRevsFile .git-blame-ignore-revs

Both packages get a patch bump: the import qualification and the formatting
change no code that a consumer can observe, and henforcer sits behind the
manual ci flag, which defaults off.
henforcer exempts any import carrying a hiding clause, so
`import Conduit hiding (MonadResource)` was never reported and got left
unqualified while everything around it was qualified. That satisfied the
plugin but not the convention.

Qualifying it removes the workaround rather than adding to it: with Conduit
qualified, MonadResource cannot arrive unqualified from it, so the explicit
resourcet import is the only source and the hiding clause is unnecessary.
MonadIO and liftIO now come from Control.Monad.IO.Class as MIO, matching
Network.FTP.Client, instead of riding in on Conduit's re-export.
The formatting-check job was added after the fork-only pull_request guard, so
it lacked the condition and would have run twice for every same-repo pull
request -- once from push and once from pull_request.

The blame ignore file also still named the pre-rebase format commit. That SHA
changes every time this branch is restacked, so it is worth re-checking on each
rebase until this lands on main.

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 Henforcer and Fourmolu enforcement while preserving support across the GHC matrix.

Changes:

  • Enables Henforcer for CI builds on GHC 9.6+.
  • Adds Fourmolu configuration, formatting script, and CI check.
  • Reformats Haskell sources and updates package metadata.

Reviewed changes

Copilot reviewed 23 out of 28 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
.github/workflows/main.yaml Adds formatting CI job.
.git-blame-ignore-revs Excludes mass-format commit from blame.
fourmolu.yaml Defines formatting rules.
scripts/format-repo Runs Fourmolu in check or write mode.
stack.yaml.lock Locks Henforcer dependencies.
stack-ghc-9.6.yaml Adds GHC 9.6 Henforcer dependencies.
stack-ghc-9.6.yaml.lock Locks GHC 9.6 dependencies.
stack-ghc-9.8.yaml Adds GHC 9.8 Henforcer dependencies.
stack-ghc-9.8.yaml.lock Locks GHC 9.8 dependencies.
stack-ghc-9.10.yaml Adds GHC 9.10 Henforcer dependencies.
stack-ghc-9.10.yaml.lock Locks GHC 9.10 dependencies.
stack-ghc-9.12.yaml Adds GHC 9.12 Henforcer dependencies.
stack-ghc-9.12.yaml.lock Locks GHC 9.12 dependencies.
ftp-client/henforcer.toml Configures Henforcer rules.
ftp-client/package.yaml Enables plugin and bumps version.
ftp-client/ftp-client.cabal Regenerates Cabal metadata.
ftp-client/CHANGELOG.md Documents tooling release.
ftp-client/Setup.hs Applies formatting.
ftp-client/src/Network/FTP/Client.hs Qualifies imports and reformats source.
ftp-client/test/test.hs Reformats tests.
ftp-client-conduit/henforcer.toml Configures Henforcer rules.
ftp-client-conduit/package.yaml Enables plugin and bumps version.
ftp-client-conduit/ftp-client-conduit.cabal Regenerates Cabal metadata.
ftp-client-conduit/CHANGELOG.md Documents tooling release.
ftp-client-conduit/Setup.hs Applies formatting.
ftp-client-conduit/src/Network/FTP/Client/Conduit.hs Qualifies imports and reformats source.
example/Setup.hs Applies formatting.
example/app/Main.hs Reformats example application.
Suppressed comments (2)

ftp-client/src/Network/FTP/Client.hs:134

  • This Haddock text was accidentally rewritten with the import qualifier. It should describe the “three-digit response code,” not an AC.digit response code.
  -- ^ The three AC.digit response code

ftp-client/src/Network/FTP/Client.hs:143

  • The public type documentation now says AC.digit, which exposes an unrelated internal import alias and makes the sentence incorrect. Restore “First digit of an FTP response.”
-- | First AC.digit of an FTP response

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

} deriving Eq
data FTPResponse = FTPResponse
{ frStatus :: ResponseStatus
-- ^ Interpretation of the first AC.digit of an FTP response code
Comment thread ftp-client/package.yaml
Comment on lines +88 to +90
- henforcer
ghc-options:
- -fplugin Henforcer
Comment on lines +87 to +89
- henforcer
ghc-options:
- -fplugin Henforcer
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.

2 participants