-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
8 Ignored Deployments
|
@nathanhammond is attempting to deploy a commit to the Vercel Team on Vercel. A member of the Team first needs to authorize it. |
6e1f7ec
to
90b302c
Compare
I don't think we should skip inferred vars in strict mode. The point is to allow users to discover if they are relying on an env var that doesn't make it into the hash. If the env var does make it into the hash, for whatever reason, it should be fine to rely on it. Is there perhaps another way that users could get the information about what was inferred? I think it's in the Run Summary, right? |
5c2e19a
to
4055a6d
Compare
ee55f32
to
f0a80da
Compare
f1b82e3
to
7e8e4f2
Compare
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.
Reviewer's guide! Review commit-by-commit.
- Adds a strict mode check.
- Makes strict mode stricter, but creates a level underneath it that includes framework vars.
- Is a docs patch for naming issues.
@@ -292,7 +292,7 @@ func (ec *execContext) exec(ctx gocontext.Context, packageTask *nodes.PackageTas | |||
currentState := env.GetEnvMap() | |||
passthroughEnv := env.EnvironmentVariableMap{} | |||
|
|||
if packageTask.EnvMode == util.Strict { | |||
if packageTask.EnvMode.IsStrict() { |
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.
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) | ||
} |
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.
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.
keyMatchers, | ||
"TURBO_CI_VENDOR_ENV_KEY", | ||
envVarContainingExcludePrefix, |
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.
These remain unset in Strict
mode, triggering the behavior change.
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 comment
The 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.
// IsStrict collapses the two Strict variants. | ||
func (em EnvMode) IsStrict() bool { | ||
return em == Strict || em == StrictIncludeFrameworkVars |
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.
We sometimes need to check these together. This makes it less error-prone.
"passthrough": null, | ||
"globalPassthrough": null |
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.
That these are properly set is tested in framework_inference.t
.
@@ -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 comment
The 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 comment
The 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 turbo
considers to be dependencies, and that means we're going infer some vars. Some ideas:
- inferred
- hashed
- hashed-only
- auto
- detected
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 turbo
is doing something beyond what the user has specified, and I think it also contrasts nicely with "strict": "do your best guess at what will work" vs "don't do anything, I'm going to specify everything". I'm open to other [short] suggestions though.
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.
After implementation I don't think we can drop infer
so we're going to be four states:
--infer
: we figure it out per-task based onturbo.json
. (collapses toloose
orstrict-include-framework-vars
)--loose
: you get everything.--strict
: we include only what you tell us.--strict-include-framework-vars
: we include what you tell us and the framework vars.
This primary way to get this is: "you defined passThroughEnv
but don't pass in a command line flag". This is what gets you strict-include-framework-vars
. In general the user should rarely want or need to specify this.
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 NEXT_PUBLIC_*
." Packages basically never change frameworks, so using this is really just a feature request for "globbing over env vars" in turbo.json
."
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:
- "we pull it from turbo.json"
- "strict + framework vars"
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.
A lot of words to say:
- I think the clarity of length is valuable. This length improves the run summary.
- I believe that users will rarely, if ever, actually specify it.
- The friction will push people toward doing it the way we want them to, which is more-easily shareable: in
turbo.json
, inenv
andpassThroughEnv
, and using a yet-unimplemented globbing feature.
7e8e4f2
to
81dbf96
Compare
81dbf96
to
394d691
Compare
Closing in favor of #4788. |
We presently use framework inference to determine if we should automatically include certain environment variables into the hash. In strict environment variable mode we should not automatically include any env vars into the hash or the execution environment.
You must instead:
env
) or merely passed through (passthroughEnv
).We will also apply this to "inferred strict" on a per-task basis. If you specify
passthroughEnv
we infer that your task is supposed to be instrict
mode.