@@ -4,6 +4,7 @@ use circus_common::{CiError, InputType, error::Result, models::JobsetInput};
44use circus_config:: EvaluatorConfig ;
55use tokio:: process:: Command ;
66use tokio_util:: sync:: CancellationToken ;
7+ use url:: Url ;
78
89mod eval_command;
910mod flake_lock;
@@ -176,6 +177,7 @@ pub struct EvalResult {
176177#[ tracing:: instrument( skip( config, inputs) , fields( flake_mode, nix_expression) ) ]
177178pub async fn evaluate (
178179 repo_path : & Path ,
180+ commit_hash : & str ,
179181 nix_expression : & str ,
180182 flake_mode : bool ,
181183 timeout : Duration ,
@@ -201,8 +203,16 @@ pub async fn evaluate(
201203 } ;
202204
203205 if flake_mode {
204- evaluate_flake ( repo_path, nix_expression, timeout, config, inputs, cancel)
205- . await
206+ evaluate_flake (
207+ repo_path,
208+ commit_hash,
209+ nix_expression,
210+ timeout,
211+ config,
212+ inputs,
213+ cancel,
214+ )
215+ . await
206216 } else {
207217 evaluate_legacy ( repo_path, nix_expression, timeout, config, inputs, cancel)
208218 . await
@@ -270,6 +280,7 @@ fn lock_derived_allowed_uris(
270280#[ tracing:: instrument( skip( config, inputs) ) ]
271281async fn evaluate_flake (
272282 repo_path : & Path ,
283+ commit_hash : & str ,
273284 nix_expression : & str ,
274285 timeout : Duration ,
275286 config : & EvaluatorConfig ,
@@ -294,7 +305,7 @@ async fn evaluate_flake(
294305 ) ;
295306 }
296307
297- let flake_ref = format ! ( "{}#{effective_expr}" , repo_path . display ( ) ) ;
308+ let flake_ref = git_flake_ref ( repo_path , commit_hash , & effective_expr ) ? ;
298309
299310 tracing:: debug!( flake_ref = %flake_ref, "Running evix evaluation" ) ;
300311
@@ -333,6 +344,21 @@ async fn evaluate_flake(
333344 eval_command:: run_eval ( evix_config, timeout, "flake" , cancel) . await
334345}
335346
347+ fn git_flake_ref (
348+ repo_path : & Path ,
349+ commit_hash : & str ,
350+ expression : & str ,
351+ ) -> Result < String > {
352+ let mut url = Url :: from_file_path ( repo_path) . map_err ( |( ) | {
353+ CiError :: NixEval ( format ! (
354+ "Failed to convert repository path to a file URL: {}" ,
355+ repo_path. display( )
356+ ) )
357+ } ) ?;
358+ url. query_pairs_mut ( ) . append_pair ( "rev" , commit_hash) ;
359+ Ok ( format ! ( "git+{url}#{expression}" ) )
360+ }
361+
336362/// Resolve all toplevels in one nix eval.
337363async fn evaluate_all_nixos_configs (
338364 repo_path : & Path ,
@@ -891,6 +917,19 @@ mod meta_tests {
891917 assert ! ( rewrite_nixos_config_expr( "packages" ) . is_none( ) ) ;
892918 }
893919
920+ #[ test]
921+ fn git_flake_ref_pins_the_checked_out_commit ( ) {
922+ assert_eq ! (
923+ git_flake_ref(
924+ Path :: new( "/tmp/circus fixture" ) ,
925+ "0123456789abcdef" ,
926+ "packages" ,
927+ )
928+ . unwrap( ) ,
929+ "git+file:///tmp/circus%20fixture?rev=0123456789abcdef#packages" ,
930+ ) ;
931+ }
932+
894933 #[ test]
895934 fn parse_derivation_show_legacy_uses_top_level_drv_key ( ) {
896935 let v = serde_json:: json!( {
0 commit comments