1
- use std:: sync:: OnceLock ;
1
+ use std:: { collections :: HashMap , sync:: OnceLock } ;
2
2
3
3
use serde:: Deserialize ;
4
4
use turborepo_repository:: package_graph:: PackageInfo ;
5
5
6
- #[ derive( Debug , PartialEq , Deserialize ) ]
6
+ #[ derive( Debug , PartialEq , Deserialize , Clone ) ]
7
7
#[ serde( rename_all = "camelCase" ) ]
8
8
enum Strategy {
9
9
All ,
10
10
Some ,
11
11
}
12
12
13
- #[ derive( Debug , PartialEq , Deserialize ) ]
13
+ #[ derive( Debug , PartialEq , Deserialize , Clone ) ]
14
14
#[ serde( rename_all = "camelCase" ) ]
15
15
struct Matcher {
16
16
strategy : Strategy ,
17
17
dependencies : Vec < String > ,
18
18
}
19
19
20
- #[ derive( Debug , PartialEq , Deserialize ) ]
20
+ #[ derive( Debug , PartialEq , Deserialize , Clone ) ]
21
+ #[ serde( rename_all = "camelCase" ) ]
22
+ struct EnvConditionKey {
23
+ key : String ,
24
+ value : Option < String > ,
25
+ }
26
+
27
+ #[ derive( Debug , PartialEq , Deserialize , Clone ) ]
28
+ #[ serde( rename_all = "camelCase" ) ]
29
+ struct EnvConditional {
30
+ when : EnvConditionKey ,
31
+ include : Vec < String > ,
32
+ }
33
+
34
+ #[ derive( Debug , PartialEq , Deserialize , Clone ) ]
21
35
#[ serde( rename_all = "camelCase" ) ]
22
36
pub struct Framework {
23
37
slug : String ,
24
38
env_wildcards : Vec < String > ,
39
+ env_conditionals : Option < Vec < EnvConditional > > ,
25
40
dependency_match : Matcher ,
26
41
}
27
42
@@ -30,8 +45,22 @@ impl Framework {
30
45
self . slug . clone ( )
31
46
}
32
47
33
- pub fn env_wildcards ( & self ) -> & [ String ] {
34
- & self . env_wildcards
48
+ pub fn env ( & self , env_at_execution_start : & HashMap < String , String > ) -> Vec < String > {
49
+ let mut env_vars = self . env_wildcards . clone ( ) ;
50
+
51
+ if let Some ( env_conditionals) = & self . env_conditionals {
52
+ for conditional in env_conditionals {
53
+ let ( key, expected_value) = ( & conditional. when . key , & conditional. when . value ) ;
54
+
55
+ if let Some ( actual_value) = env_at_execution_start. get ( key) {
56
+ if expected_value. is_none ( ) || expected_value. as_ref ( ) == Some ( actual_value) {
57
+ env_vars. extend ( conditional. include . iter ( ) . cloned ( ) ) ;
58
+ }
59
+ }
60
+ }
61
+ }
62
+
63
+ env_vars
35
64
}
36
65
}
37
66
@@ -80,6 +109,8 @@ pub fn infer_framework(workspace: &PackageInfo, is_monorepo: bool) -> Option<&Fr
80
109
81
110
#[ cfg( test) ]
82
111
mod tests {
112
+ use std:: collections:: HashMap ;
113
+
83
114
use test_case:: test_case;
84
115
use turborepo_repository:: { package_graph:: PackageInfo , package_json:: PackageJson } ;
85
116
@@ -199,4 +230,118 @@ mod tests {
199
230
let framework = infer_framework ( & workspace_info, is_monorepo) ;
200
231
assert_eq ! ( framework, expected) ;
201
232
}
233
+
234
+ #[ test]
235
+ fn test_env_with_no_conditions ( ) {
236
+ let framework = get_framework_by_slug ( "nextjs" ) ;
237
+
238
+ let env_at_execution_start = HashMap :: new ( ) ;
239
+ let env_vars = framework. env ( & env_at_execution_start) ;
240
+
241
+ assert_eq ! (
242
+ env_vars,
243
+ framework. env_wildcards. clone( ) ,
244
+ "Expected env_wildcards when no conditionals exist"
245
+ ) ;
246
+ }
247
+
248
+ #[ test]
249
+ fn test_env_with_matching_condition ( ) {
250
+ let framework = get_framework_by_slug ( "nextjs" ) ;
251
+
252
+ let mut env_at_execution_start = HashMap :: new ( ) ;
253
+ env_at_execution_start. insert (
254
+ "VERCEL_SKEW_PROTECTION_ENABLED" . to_string ( ) ,
255
+ "1" . to_string ( ) ,
256
+ ) ;
257
+
258
+ let env_vars = framework. env ( & env_at_execution_start) ;
259
+
260
+ let mut expected_vars = framework. env_wildcards . clone ( ) ;
261
+ expected_vars. push ( "VERCEL_DEPLOYMENT_ID" . to_string ( ) ) ;
262
+
263
+ assert_eq ! (
264
+ env_vars, expected_vars,
265
+ "Expected VERCEL_DEPLOYMENT_ID to be included when condition is met"
266
+ ) ;
267
+ }
268
+
269
+ #[ test]
270
+ fn test_env_with_non_matching_condition ( ) {
271
+ let framework = get_framework_by_slug ( "nextjs" ) ;
272
+
273
+ let mut env_at_execution_start = HashMap :: new ( ) ;
274
+ env_at_execution_start. insert (
275
+ "VERCEL_SKEW_PROTECTION_ENABLED" . to_string ( ) ,
276
+ "0" . to_string ( ) ,
277
+ ) ;
278
+
279
+ let env_vars = framework. env ( & env_at_execution_start) ;
280
+
281
+ assert_eq ! (
282
+ env_vars,
283
+ framework. env_wildcards. clone( ) ,
284
+ "Expected only env_wildcards when condition is not met"
285
+ ) ;
286
+ }
287
+
288
+ #[ test]
289
+ fn test_env_with_condition_without_value_requirement ( ) {
290
+ let mut framework = get_framework_by_slug ( "nextjs" ) . clone ( ) ;
291
+
292
+ if let Some ( env_conditionals) = framework. env_conditionals . as_mut ( ) {
293
+ env_conditionals[ 0 ] . when . value = None ;
294
+ }
295
+
296
+ let mut env_at_execution_start = HashMap :: new ( ) ;
297
+ env_at_execution_start. insert (
298
+ "VERCEL_SKEW_PROTECTION_ENABLED" . to_string ( ) ,
299
+ "random" . to_string ( ) ,
300
+ ) ;
301
+
302
+ let env_vars = framework. env ( & env_at_execution_start) ;
303
+
304
+ let mut expected_vars = framework. env_wildcards . clone ( ) ;
305
+ expected_vars. push ( "VERCEL_DEPLOYMENT_ID" . to_string ( ) ) ;
306
+
307
+ assert_eq ! (
308
+ env_vars, expected_vars,
309
+ "Expected VERCEL_DEPLOYMENT_ID to be included when condition key exists, regardless \
310
+ of value"
311
+ ) ;
312
+ }
313
+
314
+ #[ test]
315
+ fn test_env_with_multiple_conditions ( ) {
316
+ let mut framework = get_framework_by_slug ( "nextjs" ) . clone ( ) ;
317
+
318
+ if let Some ( env_conditionals) = framework. env_conditionals . as_mut ( ) {
319
+ env_conditionals. push ( crate :: framework:: EnvConditional {
320
+ when : crate :: framework:: EnvConditionKey {
321
+ key : "ANOTHER_CONDITION" . to_string ( ) ,
322
+ value : Some ( "true" . to_string ( ) ) ,
323
+ } ,
324
+ include : vec ! [ "ADDITIONAL_ENV_VAR" . to_string( ) ] ,
325
+ } ) ;
326
+ }
327
+
328
+ let mut env_at_execution_start = HashMap :: new ( ) ;
329
+ env_at_execution_start. insert (
330
+ "VERCEL_SKEW_PROTECTION_ENABLED" . to_string ( ) ,
331
+ "1" . to_string ( ) ,
332
+ ) ;
333
+ env_at_execution_start. insert ( "ANOTHER_CONDITION" . to_string ( ) , "true" . to_string ( ) ) ;
334
+
335
+ let env_vars = framework. env ( & env_at_execution_start) ;
336
+
337
+ let mut expected_vars = framework. env_wildcards . clone ( ) ;
338
+ expected_vars. push ( "VERCEL_DEPLOYMENT_ID" . to_string ( ) ) ;
339
+ expected_vars. push ( "ADDITIONAL_ENV_VAR" . to_string ( ) ) ;
340
+
341
+ assert_eq ! (
342
+ env_vars, expected_vars,
343
+ "Expected both VERCEL_DEPLOYMENT_ID and ADDITIONAL_ENV_VAR when both conditions are \
344
+ met"
345
+ ) ;
346
+ }
202
347
}
0 commit comments