I have a Haskell project that uses nix.
We have a local cabal package take takes bunch of yaml files and generates Haskell code. Both the yaml file and generated code are checked into git. Anytime somebody changes the yaml files they must remember to regenerate the code. If they forgot to regenerate the code and thereby the yaml and Haskell code is out of sync then CI should fail accordingly.
The CI runs nix. How do we have this check in nix. We currently have a bash script that regenerates the code and looks for the diff.
https://github.com/nammayatri/nammayatri
This is my shell script
#!/bin/bash
cabal run alchemist-generator-exe
treefmt
# This script checks if there are any changes in the src-read-only folder
CHANGES_FOUND=false
git diff --unified=0 -- | grep -E "^\\+\\+\\+|^@@" | while read -r line; do
file_path=$(grep -oP "^\\+\\+\\+ b/\K(.+)" <<< "$line")
if [[ $file_path == *"/src-read-only/"* ]]; then
git diff --unified=0 --relative="$file_path" | grep -E "^@@" | while read -r diff_line; do
line_number=$(grep -oP "@@\\s-\\d+(,\d+)?\\s+\\+\\K\d+" <<< "$diff_line")
echo $file_path:$line_number:"Changes found in src-read-only folder with diff line: $diff_line"
CHANGES_FOUND=true
done
fi
done
# git checkout -- .
if [ "$CHANGES_FOUND" = true ]; then
exit 1
else
exit 0
fi
You can use pre-commit to do this check. Flakes also has support for it.
In fact, the nammayatri repo already uses it for checking a similar thing (overlapping migrations), so you can use the same approach.
Instead of using cabal run
, however, you'd have to use the Nix package itself (lib.getExe self.packages.${pkgs.system}.alchemist-whatever
).
There's one limitation to be aware of with pre-commit-hooks.nix. There's no user-defined ordering yet; https://github.com/cachix/pre-commit-hooks.nix/issues/250
I am currently working on a pre-commit hook for this project to check diff, aiming to run both a package and a formatter in the same hook. However, I am encountering an issue where the formatter fails to run after the package execution.
Here's a snippet of the relevant configuration:
check-src-read-only-diff-check = {
enable = true;
name = "check-src-read-only-diff-check";
description = "Check that src-read-only folder is read-only";
types = [ "file" ];
pass_filenames = true;
files = ".*\\/((rider-platform\\/rider-app)|(provider-platform\\/dynamic-offer-driver-app))\\/Main\\/src-read-only\\/.*\\.hs$";
entry = "bash -c '${lib.getExe self'.packages.alchemist}' ; bash -c '${lib.getExe config.treefmt.programs.ormolu.package}'";
};
The issue arises after the package execution, preventing the formatter from running successfully. Am i doing something wrong here ?
Any help or suggestions regarding the correct configuration or execution order would be greatly appreciated.
How did you confirm that the package is running? If it is running and the formatter is not, one possible explanation could be that your package might be a service that doesn't complete, is it?
Well package is supposed to generate the new unformatted files, which it is generating . Now the next thing i wanted was the formatter should format the files and after formatting if there are still new files in staged area i want the commit to be failed
let me put forward a scenario, let's assume you make changes to your yaml files, the .hs
files for these changes are not generated yet.
Now you proceed to commit these yaml files and when you do alchemist
package and sequentially ormolu
runs and generates formatted .hs
files, these files will not match the already existing .hs
files and the commit will fail.
The above mentioned is the ideal scenario and you are saying that alchemist
is running, failing the commit, but the formatter
is not running after alchemist? is my understanding here correct?
So what we do is, we first put some change in yaml file. After that we run the alchemist-generator which is nix command which generates and formats the code. We stage those changes i.e. yaml and newly generated file.
Now, When I'm trying to commit i want the pre-commit to work in a such a way that It will first run the alchemist-generator which will generate the same code but it will be unformatted code.Hence, it will have diff between staged and newly code generated . Now my goal is to format those newly generated code by ormulo and after that as we haven't made any change
all those files will be same as staged one and hence no file will be there in Unstaged area.
I want my pre-commit to fail only if the staged code is different from the unstaged code generated during pre-commit.
But with my pre-commit it's failing everytime as code is generated during pre-commit run but fails to format it.
to check if the formatter is working, I removed bash -c '${lib.getExe self'.packages.alchemist}'
from the code and tried to format unformatted file using this hook. It didn't format those files.
If your formatter is not working, most probable culprit could be the regex you have to detect the files, assuming rest of the configuration is correct.
Last updated: Nov 15 2024 at 12:33 UTC