Skip to content

fix(pre-commit): use fresh nix eval to pick up staged changes#27

Open
lovesegfault wants to merge 3 commits into
nialov:masterfrom
lovesegfault:fixes
Open

fix(pre-commit): use fresh nix eval to pick up staged changes#27
lovesegfault wants to merge 3 commits into
nialov:masterfrom
lovesegfault:fixes

Conversation

@lovesegfault

Copy link
Copy Markdown
Contributor

Summary

The pre-commit hook was rendering workflows based on the flake state at devshell entry time, not the current staged changes. This meant users had to run direnv reload or manually invoke nix run .#render-workflows after modifying their workflow configuration.

Root cause: The hook used packages.render-workflows which has the workflow JSON pre-evaluated and baked into the derivation when the devshell is created.

Fixes:

  • fix(render): handle missing --evaluated-ci-path argument - Path(None) raises TypeError, making the fresh nix eval code path unreachable despite the argument being marked as not required.

  • fix(pre-commit): use fresh nix eval instead of pre-evaluated JSON - The hook now runs render.py without --evaluated-ci-path, triggering nix eval at commit time to pick up current working directory state.

  • fix(render): use correct attribute path after ci -> actions-nix rename - The nix eval path .#ci.workflows was never updated when flake.ci was renamed to flake.actions-nix in c4f5168. This went unnoticed because the pre-commit hook always used pre-evaluated JSON.

Test plan

  • Tested locally by overriding flake input to local checkout
  • Verified pre-commit hook now picks up staged changes without direnv reload

Path(None) raises TypeError, making the fresh nix eval code path
unreachable despite the argument being marked as not required.
The pre-commit hook was using packages.render-workflows which has its
workflow JSON baked in at devshell entry time. This caused the hook to
render workflows based on the old flake state rather than staged changes.

Now the hook runs render.py without --evaluated-ci-path, triggering a
fresh `nix eval` at commit time to pick up the current working directory.
The nix eval path was never updated when flake.ci was renamed to
flake.actions-nix in c4f5168. This went unnoticed because the pre-commit
hook always used pre-evaluated JSON, making this code path unreachable.
@nialov

nialov commented Dec 8, 2025

Copy link
Copy Markdown
Owner

Thanks for the PR! This would indeed be the optimal way to get the evaluated config for rendering. I attempted to get this working originally, which you can see from the unreachable code path (eval_process).

However, running nix eval in the sandbox, which git-hooks.nix uses, runs into errors related to no network access.

       > render-workflows.........................................................Failed
       > - hook id: render-actions
       > - exit code: 1
       >
       > ERROR:root:{'eval_process_stdout': '', 'eval_process_stderr': "warning: '/nix/var/nix' does not exist, so Nix will use '/build/tmp.PqvYtXgFUa/.local/share/nix/root' as a chroot store\nunpacking 'github:hercules-ci/flake-parts/32ea77a06711b758da0ad9bd6a844c5740a87abd?narHash=sha256-7H9XgNiGLKN1G1CgRh0vUL4AheZSYzPm%2BzmZ7vxbJdo%3D' into the Git cache...\nerror:\n       … in the left operand of the update (//) operator\n         at «nix-internal»/call-flake.nix:69:13:\n           68|             # This is shadowed in the next //\n           69|             // sourceInfo\n             |             ^\n           70|             // {\n\n       … in the condition of the assert statement\n         at «nix-internal»/call-flake.nix:79:13:\n           78|           if node.flake or true then\n           79|             assert builtins.isFunction flake.outputs;\n             |             ^\n           80|             result\n\n       (stack trace truncated; use '--show-trace' to show the full, detailed trace)\n\n       error: Failed to open archive (Source threw exception: error: unable to download 'https://github.com/hercules-ci/flake-parts/archive/32ea77a06711b758da0ad9bd6a844c5740a87abd.tar.gz': Could not resolve hostname (6))\n"}
       > Traceback (most recent call last):
       >   File "/nix/store/qb3qqmp2yrjlxhv54y9m2r5wwldlh6z4-render.py", line 72, in <module>
       >     main(
       >   File "/nix/store/qb3qqmp2yrjlxhv54y9m2r5wwldlh6z4-render.py", line 57, in main
       >     workflows = evaluate(evaluator=eval_process)
       >                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
       >   File "/nix/store/qb3qqmp2yrjlxhv54y9m2r5wwldlh6z4-render.py", line 17, in evaluate
       >     eval_process.check_returncode()
       >   File "/nix/store/26yi95240650jxp5dj78xzch70i1kzlz-python3-3.12.9/lib/python3.12/subprocess.py", line 504, in check_returncode
       >     raise CalledProcessError(self.returncode, self.args, self.stdout,
       > subprocess.CalledProcessError: Command '['nix', 'eval', '--option', 'experimental-features', 'nix-command flakes', '.#actions-nix.workflows', '--offline', '--json']' returned non-zero exit status 1.

If you know how to get the eval working in the build sandbox, this can be implemented. I remember experimenting a bit with trying to have the "dependencies", i.e. flake inputs (e.g. flake-parts, ...), available when the eval starts but did not manage to get it working.

I personally circumvent the stale eval by running nix develop -c git commit for commits so that it is refreshed and the pre-commit hook successfully runs. It is of course a bit cumbersome. I should also document this in the README.

@nialov

nialov commented Dec 8, 2025

Copy link
Copy Markdown
Owner

nix also needs to be included in the environment.

diff --git a/nix/flake-modules/actions-nix/default.nix b/nix/flake-modules/actions-nix/default.nix
index a7440fc..f42d15a 100644
--- a/nix/flake-modules/actions-nix/default.nix
+++ b/nix/flake-modules/actions-nix/default.nix
@@ -47,8 +47,15 @@ _localFlake:
             entry =
               let
                 pythonEnv = pkgs.python3.withPackages (p: [ p.pyyaml ]);
+                app = pkgs.writeShellApplication {
+                  name = "render-workflows";
+                  runtimeInputs = [ pkgs.nix ];
+                  text = ''
+                    ${pythonEnv}/bin/python3 ${./render.py}
+                  '';
+                };
               in
-              "${pythonEnv}/bin/python3 ${./render.py}";
+              "${app}/bin/render-workflows";
           };
         };
 
diff --git a/nix/flake-modules/actions-nix/render.py b/nix/flake-modules/actions-nix/render.py
index e8f765d..0e599d1 100644
--- a/nix/flake-modules/actions-nix/render.py
+++ b/nix/flake-modules/actions-nix/render.py
@@ -48,6 +48,7 @@ def main(evaluated_ci_path: Optional[Path]):
                 "experimental-features",
                 "nix-command flakes",
                 ".#actions-nix.workflows",
+                "--offline",
                 "--json",
             ],
             text=True,

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