haskell.nixのnix flake checkでHaskellの警告をエラーとして扱う
背景
- haskell.nixでのプロジェクト環境でnix flake checkでPostgreSQLへのアクセスを含むテストを実行する方法 - ncaq
- haskell.nixでテストが無いパッケージもnix flake checkでチェックする - ncaq
でnix flake check
で全体のテストを行うようにしました。
問題
nix flake check
でのビルドはデフォルトでは警告をエラーとして扱わないため、そのままではHaskellの警告が出てもCIで失敗しない。
私の思想
私は全体的には警告はエラーとして扱わないべきだと考えています。
実行環境とかライブラリのパッチアップデートで出る警告は、実行不可能なエラーとは分けて考えるべきだからです。
例えばライブラリのアップデートでimportが不要になった場合などをエラーにするべきだとは思えません。
本来警告が出るだけで動くプログラムを、警告が出るだけで動かなくするのはナンセンスです。
しかしCIでは警告はエラーとして扱うべきです。開発者のupstreamでは警告はその場所で取り除くべきです。
なのでcabalファイル自体でGHCのオプションに-Werror
を追加するのは行いたくないです。
使えなかった方法
環境変数での切り替えはNix Flakesが純粋的に評価を行うので注入が困難です。
nix flake check
には--arg
オプションは無いようでした。
実装
nix flake check
では警告時にエラーになれば良いので、
haskell.nixのmodules
に以下のように設定を追加しました。
# `nix flake check`レベルではcabalの警告をエラーとして扱います。
# ライブラリの問題ない範囲の不一致とか考えるとcabalの警告はエラーにしないべきですが、
# CIでは通したくないので警告も含めてエラーにします。
# CI専用に環境を分離するのも手ですが、
# 元々`nix flake check`では最適化を無効にするのが面倒なので時間がかかるため、
# あまり反復的に実行しません。
# 反復的に実行してテストの結果とかを確認するのには普通は`cabal test`のような言語固有のコマンドを使います。
# `cabal test`の方が実行するテストをフィルタリングとかも簡単に出来ますし。
# そのことを考えると本番を考えてエラーにしても構わないでしょう。
# flake参照された時にnixpkgsをfollowすると問題ない警告をエラーにしてしまうかもしれないのが懸念点ですが、
# 少なくとも現在は考慮する必要はないでしょう。
# 注意点として、`src`や`test`はビルドされますが、executableである`app`はビルドされません。
# 「appはエントリーポイントとしてのみ使う」習慣を守っていれば問題にはならないです。
(
{ lib, config, ... }:
{
# パッケージたちをハードコーディングすると変更忘れが発生するので`config.package-keys`で取得。
options.packages = lib.genAttrs config.package-keys (
_name:
lib.mkOption {
type = lib.types.submodule (
{ config, lib, ... }:
# `cabal.project`に`source-repository-package`などで書かれていたりする、
# 外部パッケージは変更したくないので、
# `isProject`でフィルタリングしています。
lib.mkIf config.package.isProject {
# この書き方で上書きではなく追加として扱われる。
ghcOptions = [ "-Werror" ];
}
);
}
);
}
)
nixでcheckする分には依存関係とかも完全に管理されるので、ライブラリ由来の警告とかがエラーとして扱われても問題ないと思います。