Skip to content
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

Closed
wants to merge 3 commits into from

Conversation

nathanhammond
Copy link
Contributor

@nathanhammond nathanhammond commented Apr 11, 2023

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:

  • Specify all environment variables that you want available in your build environment.
  • Specify whether you want those considered for the hash (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 in strict mode.

@vercel
Copy link

vercel bot commented Apr 11, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
examples-basic-web 🔄 Building (Inspect) Apr 28, 2023 10:09am
examples-vite-web 🔄 Building (Inspect) Apr 28, 2023 10:09am
turbo-site ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 28, 2023 10:09am
8 Ignored Deployments
Name Status Preview Comments Updated (UTC)
examples-cra-web ⬜️ Ignored (Inspect) Apr 28, 2023 10:09am
examples-designsystem-docs ⬜️ Ignored (Inspect) Apr 28, 2023 10:09am
examples-gatsby-web ⬜️ Ignored (Inspect) Apr 28, 2023 10:09am
examples-kitchensink-blog ⬜️ Ignored (Inspect) Apr 28, 2023 10:09am
examples-native-web ⬜️ Ignored (Inspect) Apr 28, 2023 10:09am
examples-nonmonorepo ⬜️ Ignored (Inspect) Apr 28, 2023 10:09am
examples-svelte-web ⬜️ Ignored (Inspect) Apr 28, 2023 10:09am
examples-tailwind-web ⬜️ Ignored (Inspect) Apr 28, 2023 10:09am

@vercel
Copy link

vercel bot commented Apr 11, 2023

@nathanhammond is attempting to deploy a commit to the Vercel Team on Vercel.

A member of the Team first needs to authorize it.

mehulkar

This comment was marked as resolved.

@turbo-orchestrator turbo-orchestrator bot added the area: docs Improvements or additions to documentation label Apr 11, 2023
@gsoltis
Copy link
Contributor

gsoltis commented Apr 11, 2023

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?

Copy link
Contributor Author

@nathanhammond nathanhammond left a 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.

  1. Adds a strict mode check.
  2. Makes strict mode stricter, but creates a level underneath it that includes framework vars.
  3. 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() {
Copy link
Contributor Author

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.

Comment on lines +384 to +401
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)
}
Copy link
Contributor Author

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.

Comment on lines 406 to +407
keyMatchers,
"TURBO_CI_VENDOR_ENV_KEY",
envVarContainingExcludePrefix,
Copy link
Contributor Author

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
Copy link
Contributor Author

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.

Comment on lines +28 to +30
// IsStrict collapses the two Strict variants.
func (em EnvMode) IsStrict() bool {
return em == Strict || em == StrictIncludeFrameworkVars
Copy link
Contributor Author

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.

Comment on lines +61 to +62
"passthrough": null,
"globalPassthrough": null
Copy link
Contributor Author

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,
Copy link
Contributor Author

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. 😅

Copy link
Contributor

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.

Copy link
Contributor Author

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 on turbo.json. (collapses to loose or strict-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"

Copy link
Contributor Author

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, in env and passThroughEnv, and using a yet-unimplemented globbing feature.

@nathanhammond
Copy link
Contributor Author

Closing in favor of #4788.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: docs Improvements or additions to documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants