-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
No env var inference in strict mode. #4527
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -325,6 +325,8 @@ func calculateTaskHashFromHashable(full *taskHashable, useOldTaskHashable bool) | |
// Remove the passthroughs from hash consideration if we're explicitly loose. | ||
full.passthroughEnv = nil | ||
return fs.HashObject(full) | ||
case util.StrictIncludeFrameworkVars: | ||
fallthrough | ||
case util.Strict: | ||
// Collapse `nil` and `[]` in strict mode. | ||
if full.passthroughEnv == nil { | ||
|
@@ -379,17 +381,30 @@ func (th *Tracker) CalculateTaskHash(packageTask *nodes.PackageTask, dependencyS | |
} | ||
|
||
var keyMatchers []string | ||
framework := inference.InferFramework(packageTask.Pkg) | ||
if framework != nil && framework.EnvMatcher != "" { | ||
// log auto detected framework and env prefix | ||
logger.Debug(fmt.Sprintf("auto detected framework for %s", packageTask.PackageName), "framework", framework.Slug, "env_prefix", framework.EnvMatcher) | ||
keyMatchers = append(keyMatchers, framework.EnvMatcher) | ||
var framework *inference.Framework | ||
envVarContainingExcludePrefix := "" | ||
|
||
// In Strict environment variable mode we don't do framework env var inference. | ||
// You must instead: | ||
// - Specify all environment variables that you want available in your build environment. | ||
// - Specify whether you want those considered for the hash or merely passed through. | ||
// | ||
// This allows advanced users to improve both cache hit ratio _and_ correctness with | ||
// the tradeoff of increased configuration verbosity. | ||
if packageTask.EnvMode != util.Strict { | ||
envVarContainingExcludePrefix = "TURBO_CI_VENDOR_ENV_KEY" | ||
framework := inference.InferFramework(packageTask.Pkg) | ||
if framework != nil && framework.EnvMatcher != "" { | ||
// log auto detected framework and env prefix | ||
logger.Debug(fmt.Sprintf("auto detected framework for %s", packageTask.PackageName), "framework", framework.Slug, "env_prefix", framework.EnvMatcher) | ||
keyMatchers = append(keyMatchers, framework.EnvMatcher) | ||
} | ||
Comment on lines
+384
to
+401
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In whitespace-ignoring review mode, you'll see that this is just an if statement, a delayed variable configuration, and a comment. It's the only material behavior change in this PR. |
||
} | ||
|
||
envVars, err := env.GetHashableEnvVars( | ||
packageTask.TaskDefinition.EnvVarDependencies, | ||
keyMatchers, | ||
"TURBO_CI_VENDOR_ENV_KEY", | ||
envVarContainingExcludePrefix, | ||
Comment on lines
406
to
+407
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These remain unset in |
||
) | ||
if err != nil { | ||
return "", err | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,13 +10,24 @@ const ( | |
Infer EnvMode = "Infer" | ||
// Loose - environment variables are unconstrained | ||
Loose EnvMode = "Loose" | ||
// StrictIncludeFrameworkVars - environment variables are limited. | ||
// They include vars from detected frameworks. | ||
StrictIncludeFrameworkVars EnvMode = "StrictIncludeFrameworkVars" | ||
// Strict - environment variables are limited | ||
Strict EnvMode = "Strict" | ||
) | ||
|
||
// MarshalText implements TextMarshaler for the struct. | ||
func (s EnvMode) MarshalText() (text []byte, err error) { | ||
return []byte(strings.ToLower(string(s))), nil | ||
func (em EnvMode) MarshalText() (text []byte, err error) { | ||
if em == StrictIncludeFrameworkVars { | ||
return []byte("strict-include-framework-vars"), nil | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I could include some fancy kebab-case handling thing, write my own, or just hardcode the singular edge case. I chose the one that wasn't a waste of time and bytes. There are tests that include this value, so it won't regress. |
||
} | ||
return []byte(strings.ToLower(string(em))), nil | ||
} | ||
|
||
// IsStrict collapses the two Strict variants. | ||
func (em EnvMode) IsStrict() bool { | ||
return em == Strict || em == StrictIncludeFrameworkVars | ||
Comment on lines
+28
to
+30
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We sometimes need to check these together. This makes it less error-prone. |
||
} | ||
|
||
// RunOpts holds the options that control the execution of a turbo run | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,6 +56,7 @@ pub enum DryRunMode { | |
pub enum EnvMode { | ||
Infer, | ||
Loose, | ||
StrictIncludeFrameworkVars, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The name here is a bikeshed. Note that the name introducing friction for using this is intentional. Happy to entertain other options but this is already less aggressive than my original. 😅 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should go with something a bit shorter, at least for the user-facing portions. We're intending to communicate that the env vars available will match the set of env vars that
I'm least wild about the "hashed" variants since we don't want to force users to think about hashing. For better or worse they already need to think about inference at least a little, so I think that's less bad. "auto" and "detected" are pretty general. After writing this out, my vote goes to "auto". It suggests that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After implementation I don't think we can drop
This primary way to get this is: "you defined The primary use case for manually specifying this flag is "I want strict mode for all my tasks, and for tasks that are Next.js I want to include The problem here is that "auto", "detect", and "infer" are all synonyms and are extremely difficult to differentiate so we need two names for things which will basically never be specified on the command line, one of which is the "wrong" solution to the problem:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A lot of words to say:
|
||
Strict, | ||
} | ||
|
||
|
@@ -728,6 +729,26 @@ mod test { | |
"env_mode: specified strict" | ||
); | ||
|
||
assert_eq!( | ||
Args::try_parse_from([ | ||
"turbo", | ||
"run", | ||
"build", | ||
"--experimental-env-mode", | ||
"strict-include-framework-vars" | ||
]) | ||
.unwrap(), | ||
Args { | ||
command: Some(Command::Run(Box::new(RunArgs { | ||
tasks: vec!["build".to_string()], | ||
env_mode: EnvMode::StrictIncludeFrameworkVars, | ||
..get_default_run_args() | ||
}))), | ||
..Args::default() | ||
}, | ||
"env_mode: specified strict-include-framework-vars" | ||
); | ||
|
||
assert_eq!( | ||
Args::try_parse_from(["turbo", "run", "build", "lint", "test"]).unwrap(), | ||
Args { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"name": "next-app", | ||
"scripts": { | ||
"build": "echo \"hello from $NEXT_PUBLIC_HELLO\"" | ||
}, | ||
"dependencies": { | ||
"next": "latest" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"name": "vite-app", | ||
"scripts": { | ||
"build": "echo \"hello from $VITE_HELLO\"" | ||
}, | ||
"dependencies": { | ||
"vite": "latest" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"name": "vue-app", | ||
"scripts": { | ||
"build": "echo \"hello from $VUE_APP_HELLO\"" | ||
}, | ||
"dependencies": { | ||
"@vue/cli-service": "latest" | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are now two strict modes with slightly different meanings.