-
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
Print resolvedTaskDefinition in DryRun #3377
Print resolvedTaskDefinition in DryRun #3377
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎ 10 Ignored Deployments
|
bd7d0d7
to
a83ca25
Compare
🟢 CI successful 🟢Thanks |
afbf0d6
to
e81703b
Compare
Log File = apps/my-app/.turbo/turbo-build.log | ||
Dependencies = | ||
Dependendents = | ||
ResolvedTaskDefinition = {"outputs":[],"cache":true,"dependsOn":[],"inputs":[],"outputMode":0,"env":[],"persistent":false} |
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 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.
OutputMode util.TaskOutputMode `json:"outputMode,omitempty"` | ||
Env []string `json:"env,omitempty"` | ||
Persistent bool `json:"persistent,omitempty"` | ||
Outputs []string `json:"outputs"` |
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.
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
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 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.
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 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
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.
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"` |
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.
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".
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.
IMO I think the name pretty clear
CacheState cache.ItemStatus `json:"cacheState"` | ||
Command string `json:"command"` | ||
Outputs []string `json:"outputs"` | ||
ExcludedOutputs []string `json:"excludedOutputs"` |
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.
Outputs
and ExcludedOutputs
are redundant now, and I would like to remove them at some point in the future.
OutputMode util.TaskOutputMode `json:"outputMode,omitempty"` | ||
Env []string `json:"env,omitempty"` | ||
Persistent bool `json:"persistent,omitempty"` | ||
Outputs []string `json:"outputs"` |
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 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.
@@ -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) { |
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.
Quick glancing through the code I think we aren't altering TaskDefinition
s 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.
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.
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? 🤔
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.
Wrote a test first and it seemed to pass deterministically, but added a sort in anyway
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 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.)
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.
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"` |
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.
IMO I think the name pretty clear
not sure why they changed though 🤔
@@ -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 |
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.
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.
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.
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.
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.