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

Print resolvedTaskDefinition in DryRun #3377

Merged
merged 13 commits into from
Jan 20, 2023

Conversation

mehulkar
Copy link
Contributor

@mehulkar mehulkar commented Jan 19, 2023

This PR adds a resolvedTaskDefinition key to the Dry Run output. Today, this allows users to see the applied defaults for each key in their tasks. In the future, this will allow users to introspect the task config when it's composed from multiple sources.

  • write tests

@vercel
Copy link

vercel bot commented Jan 19, 2023

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

10 Ignored Deployments
Name Status Preview Comments Updated
examples-basic-web ⬜️ Ignored (Inspect) Jan 20, 2023 at 2:34AM (UTC)
examples-cra-web ⬜️ Ignored (Inspect) Jan 20, 2023 at 2:34AM (UTC)
examples-designsystem-docs ⬜️ Ignored (Inspect) Jan 20, 2023 at 2:34AM (UTC)
examples-kitchensink-blog ⬜️ Ignored (Inspect) Jan 20, 2023 at 2:34AM (UTC)
examples-native-web ⬜️ Ignored (Inspect) Jan 20, 2023 at 2:34AM (UTC)
examples-nonmonorepo ⬜️ Ignored (Inspect) Jan 20, 2023 at 2:34AM (UTC)
examples-svelte-web ⬜️ Ignored (Inspect) Jan 20, 2023 at 2:34AM (UTC)
examples-tailwind-web ⬜️ Ignored (Inspect) Jan 20, 2023 at 2:34AM (UTC)
turbo-site ⬜️ Ignored (Inspect) Visit Preview Jan 20, 2023 at 2:34AM (UTC)
turbo-vite-web ⬜️ Ignored (Inspect) Jan 20, 2023 at 2:34AM (UTC)

@mehulkar mehulkar force-pushed the mehulkar/turbo-560-log-resolved-task-config-in-dry-run branch from bd7d0d7 to a83ca25 Compare January 19, 2023 08:46
@github-actions
Copy link
Contributor

github-actions bot commented Jan 19, 2023

🟢 CI successful 🟢

Thanks

Log File = apps/my-app/.turbo/turbo-build.log
Dependencies =
Dependendents =
ResolvedTaskDefinition = {"outputs":[],"cache":true,"dependsOn":[],"inputs":[],"outputMode":0,"env":[],"persistent":false}
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 thought about not printing json here and trying have nested lines, but I think we want json, since it's trying to reflect user's input.

cli/integration_tests/basic_monorepo/dry_run.t Outdated Show resolved Hide resolved
OutputMode util.TaskOutputMode `json:"outputMode,omitempty"`
Env []string `json:"env,omitempty"`
Persistent bool `json:"persistent,omitempty"`
Outputs []string `json:"outputs"`
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed this from a pointer, because I had trouble using it as a pointer in the new code, and I'm not sure if it needs to be one. I can change it back if it breaks something

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A comment from #2712 that got deleted seems to indicating this was a pointer so it would get unmarshaled as nil instead of []string{}:

// We can't use omitempty for Outputs, because it will
// always unmarshal into an empty array, which means something different from nil.

I think we don't need to differentiate between the two now that we don't supply default outputs.

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 had understood that comment to be about omitempty, rather than the pointer (which is why i deleted the comment). Also that comment used to be in the Unmarshal method, rather than where the pointer was defined, so that seems to support the theory
https://github.com/vercel/turbo/blob/v1.6.0/cli/internal/fs/turbo_json.go#L215-L219

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is all correct, and a good change. Using weird Go implementation details to hack serialization is a smell, and I'm happy to have it gone.

Dir string `json:"directory"`
Dependencies []string `json:"dependencies"`
Dependents []string `json:"dependents"`
ResolvedTaskDefinition *fs.TaskDefinition `json:"resolvedTaskDefinition"`
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to bikeshed the ResolvedTaskDefinition key name a bit.

My main concern is that "resolved" is misleading because we aren't going to include things like turbo's injected env vars or expand globs in inputs/outputs. I think that is ok, since this is a "task definition", and that "fully resolved state" is more for "cache hit status".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO I think the name pretty clear

CacheState cache.ItemStatus `json:"cacheState"`
Command string `json:"command"`
Outputs []string `json:"outputs"`
ExcludedOutputs []string `json:"excludedOutputs"`
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Outputs and ExcludedOutputs are redundant now, and I would like to remove them at some point in the future.

@mehulkar mehulkar marked this pull request as ready for review January 19, 2023 21:38
@mehulkar mehulkar requested a review from a team as a code owner January 19, 2023 21:38
cli/integration_tests/basic_monorepo/dry_run.t Outdated Show resolved Hide resolved
OutputMode util.TaskOutputMode `json:"outputMode,omitempty"`
Env []string `json:"env,omitempty"`
Persistent bool `json:"persistent,omitempty"`
Outputs []string `json:"outputs"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A comment from #2712 that got deleted seems to indicating this was a pointer so it would get unmarshaled as nil instead of []string{}:

// We can't use omitempty for Outputs, because it will
// always unmarshal into an empty array, which means something different from nil.

I think we don't need to differentiate between the two now that we don't supply default outputs.

cli/internal/run/dry_run.go Outdated Show resolved Hide resolved
@@ -301,6 +300,46 @@ func (c *TaskDefinition) UnmarshalJSON(data []byte) error {
return nil
}

// MarshalJSON deserializes JSON into a TaskDefinition
func (c *TaskDefinition) MarshalJSON() ([]byte, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick glancing through the code I think we aren't altering TaskDefinitions after construction, but since non-determinism has gotten us before: we might want to sort these slices before marshalling them. If you've done some closer reading of the code to verify that the slices remain sorted after creation, then feel free to ignore this comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. That seems like a good idea, even just for determinism in tests, but I don't think it should affect task hashes, right? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrote a test first and it seemed to pass deterministically, but added a sort in anyway

Copy link
Contributor

@nathanhammond nathanhammond Jan 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder how visible this change will be. I think it effectively changes the execution order of peer tasks?

None of that should be relied upon (and we should probably intentionally insert randomness into that at execution time to prevent people relying on it) but that doesn't mean people aren't implicitly relying on it right now.

(If we range over a map in our graph pass this is irrelevant, but I didn't check the stack trace.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on my experience with test runs, the order is indeterminate already (see prysk/prysk#154, for example), so I don't think the sort is guaranteeing anything.

Also, for future readers, to be clear, Marshal doesn't play a part in taskGraph exectution at all. I'm guessing Nathan is commenting on sorting lists in general (and in this case the Unmarshal part)

Dir string `json:"directory"`
Dependencies []string `json:"dependencies"`
Dependents []string `json:"dependents"`
ResolvedTaskDefinition *fs.TaskDefinition `json:"resolvedTaskDefinition"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO I think the name pretty clear

@mehulkar mehulkar enabled auto-merge (squash) January 20, 2023 02:33
@mehulkar mehulkar merged commit 6e33584 into main Jan 20, 2023
@mehulkar mehulkar deleted the mehulkar/turbo-560-log-resolved-task-config-in-dry-run branch January 20, 2023 02:54
@@ -301,6 +300,54 @@ func (c *TaskDefinition) UnmarshalJSON(data []byte) error {
return nil
}

// MarshalJSON deserializes JSON into a TaskDefinition
func (c *TaskDefinition) MarshalJSON() ([]byte, error) {
// Initialize with empty arrays, so we get empty arrays serialized into JSON
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For elegance I kinda want to omit empty arrays when printing, but that may make it harder for people to use --dry=json. So I'm not actually proposing this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, IMO it's actually important to print the empty arrays, so it's never a question about what the whole config is. In other words, missing key can mean "we don't have this config" or "this config has an empty value", and that makes debugging a bit harder.

@mehulkar mehulkar mentioned this pull request Feb 6, 2023
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants