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

Update data sent to vercel for runs #4495

Merged
merged 10 commits into from Apr 11, 2023
2 changes: 2 additions & 0 deletions cli/integration_tests/single_package/run-summary.t
Expand Up @@ -20,9 +20,11 @@ Check
[
"attempted",
"cached",
"command",
"endTime",
"exitCode",
"failed",
"repoPath",
"startTime",
"success"
]
Expand Down
6 changes: 5 additions & 1 deletion cli/internal/run/run.go
Expand Up @@ -61,7 +61,9 @@ func optsFromArgs(args *turbostate.ParsedArgsFromRust) (*Opts, error) {

opts := getDefaultOptions()
// aliases := make(map[string]string)
scope.OptsFromArgs(&opts.scopeOpts, args)
if err := scope.OptsFromArgs(&opts.scopeOpts, args); err != nil {
return nil, err
}

// Cache flags
opts.clientOpts.Timeout = args.RemoteCacheTimeout
Expand Down Expand Up @@ -350,6 +352,7 @@ func (r *run) run(ctx gocontext.Context, targets []string) error {
startAt,
r.base.UI,
r.base.RepoRoot,
rs.Opts.scopeOpts.PackageInferenceRoot,
r.base.TurboVersion,
r.base.APIClient,
rs.Opts.runOpts,
Expand All @@ -361,6 +364,7 @@ func (r *run) run(ctx gocontext.Context, targets []string) error {
globalHashable.globalCacheKey,
globalHashable.pipeline,
),
rs.Opts.SynthesizeCommand(rs.Targets),
)

// Dry Run
Expand Down
32 changes: 32 additions & 0 deletions cli/internal/run/run_spec.go
Expand Up @@ -3,6 +3,8 @@
package run

import (
"strings"

"github.com/vercel/turbo/cli/internal/cache"
"github.com/vercel/turbo/cli/internal/client"
"github.com/vercel/turbo/cli/internal/runcache"
Expand Down Expand Up @@ -45,6 +47,36 @@ type Opts struct {
scopeOpts scope.Opts
}

// SynthesizeCommand produces a command that produces an equivalent set of packages, tasks,
// and task arguments to what the current set of opts selects.
func (o *Opts) SynthesizeCommand(tasks []string) string {
cmd := "turbo run"
cmd += " " + strings.Join(tasks, " ")
for _, filterPattern := range o.scopeOpts.FilterPatterns {
cmd += " --filter=" + filterPattern
}
for _, filterPattern := range o.scopeOpts.LegacyFilter.AsFilterPatterns() {
cmd += " --filter=" + filterPattern
}
if o.runOpts.Parallel {
cmd += " --parallel"
}
if o.runOpts.ContinueOnError {
cmd += " --continue"
}
if o.runOpts.DryRun {
if o.runOpts.DryRunJSON {
cmd += " --dry=json"
} else {
cmd += " --dry"
}
}
if len(o.runOpts.PassThroughArgs) > 0 {
cmd += " -- " + strings.Join(o.runOpts.PassThroughArgs, " ")
}
return cmd
}

// getDefaultOptions returns the default set of Opts for every run
func getDefaultOptions() *Opts {
return &Opts{
Expand Down
107 changes: 107 additions & 0 deletions cli/internal/run/run_spec_test.go
@@ -0,0 +1,107 @@
package run

import (
"testing"

"github.com/vercel/turbo/cli/internal/scope"
"github.com/vercel/turbo/cli/internal/util"
)

func TestSynthesizeCommand(t *testing.T) {
testCases := []struct {
filterPatterns []string
legacyFilter scope.LegacyFilter
passThroughArgs []string
parallel bool
continueOnError bool
dryRun bool
dryRunJSON bool
tasks []string
expected string
}{
{
filterPatterns: []string{"my-app"},
tasks: []string{"build"},
expected: "turbo run build --filter=my-app",
},
{
filterPatterns: []string{"my-app"},
tasks: []string{"build"},
passThroughArgs: []string{"-v", "--foo=bar"},
expected: "turbo run build --filter=my-app -- -v --foo=bar",
},
{
legacyFilter: scope.LegacyFilter{
Entrypoints: []string{"my-app"},
SkipDependents: true,
},
tasks: []string{"build"},
passThroughArgs: []string{"-v", "--foo=bar"},
expected: "turbo run build --filter=my-app -- -v --foo=bar",
},
{
legacyFilter: scope.LegacyFilter{
Entrypoints: []string{"my-app"},
SkipDependents: true,
},
filterPatterns: []string{"other-app"},
tasks: []string{"build"},
passThroughArgs: []string{"-v", "--foo=bar"},
expected: "turbo run build --filter=other-app --filter=my-app -- -v --foo=bar",
},
{
legacyFilter: scope.LegacyFilter{
Entrypoints: []string{"my-app"},
IncludeDependencies: true,
Since: "some-ref",
},
filterPatterns: []string{"other-app"},
tasks: []string{"build"},
expected: "turbo run build --filter=other-app --filter=...my-app...[some-ref]...",
},
{
filterPatterns: []string{"my-app"},
tasks: []string{"build"},
parallel: true,
continueOnError: true,
expected: "turbo run build --filter=my-app --parallel --continue",
},
{
filterPatterns: []string{"my-app"},
tasks: []string{"build"},
dryRun: true,
expected: "turbo run build --filter=my-app --dry",
},
{
filterPatterns: []string{"my-app"},
tasks: []string{"build"},
dryRun: true,
dryRunJSON: true,
expected: "turbo run build --filter=my-app --dry=json",
},
}

for _, testCase := range testCases {
testCase := testCase
t.Run(testCase.expected, func(t *testing.T) {
o := Opts{
scopeOpts: scope.Opts{
FilterPatterns: testCase.filterPatterns,
LegacyFilter: testCase.legacyFilter,
},
runOpts: util.RunOpts{
PassThroughArgs: testCase.passThroughArgs,
Parallel: testCase.parallel,
ContinueOnError: testCase.continueOnError,
DryRun: testCase.dryRun,
DryRunJSON: testCase.dryRunJSON,
},
}
cmd := o.SynthesizeCommand(testCase.tasks)
if cmd != testCase.expected {
t.Errorf("SynthesizeCommand() got %v, want %v", cmd, testCase.expected)
}
})
}

}
39 changes: 26 additions & 13 deletions cli/internal/runsummary/execution_summary.go
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/vercel/turbo/cli/internal/chrometracing"
"github.com/vercel/turbo/cli/internal/fs"
"github.com/vercel/turbo/cli/internal/turbopath"

"github.com/mitchellh/cli"
)
Expand Down Expand Up @@ -72,6 +73,10 @@ type TaskExecutionSummary struct {
exitCode *int // pointer so we can distinguish between 0 and unknown.
}

func (ts *TaskExecutionSummary) endTime() time.Time {
return ts.startAt.Add(ts.Duration)
}

// MarshalJSON munges the TaskExecutionSummary into a format we want
// We'll use an anonmyous, private struct for this, so it's not confusingly duplicated
func (ts *TaskExecutionSummary) MarshalJSON() ([]byte, error) {
Expand All @@ -82,7 +87,7 @@ func (ts *TaskExecutionSummary) MarshalJSON() ([]byte, error) {
ExitCode *int `json:"exitCode"`
}{
Start: ts.startAt.UnixMilli(),
End: ts.startAt.Add(ts.Duration).UnixMilli(),
End: ts.endTime().UnixMilli(),
Err: ts.err,
ExitCode: ts.exitCode,
}
Expand All @@ -108,10 +113,12 @@ type executionSummary struct {
profileFilename string

// These get serialized to JSON
success int // number of tasks that exited successfully (does not include cache hits)
failure int // number of tasks that exited with failure
cached int // number of tasks that had a cache hit
attempted int // number of tasks that started
command string // a synthesized turbo command to produce this invocation
repoPath turbopath.RelativeSystemPath // the (possibly empty) path from the turborepo root to where the command was run
success int // number of tasks that exited successfully (does not include cache hits)
failure int // number of tasks that exited with failure
cached int // number of tasks that had a cache hit
attempted int // number of tasks that started
startedAt time.Time
endedAt time.Time
exitCode int
Expand All @@ -121,14 +128,18 @@ type executionSummary struct {
// We'll use an anonmyous, private struct for this, so it's not confusingly duplicated.
func (es *executionSummary) MarshalJSON() ([]byte, error) {
serializable := struct {
Success int `json:"success"`
Failure int `json:"failed"`
Cached int `json:"cached"`
Attempted int `json:"attempted"`
StartTime int64 `json:"startTime"`
EndTime int64 `json:"endTime"`
ExitCode int `json:"exitCode"`
Command string `json:"command"`
RepoPath string `json:"repoPath"`
Success int `json:"success"`
Failure int `json:"failed"`
Cached int `json:"cached"`
Attempted int `json:"attempted"`
StartTime int64 `json:"startTime"`
EndTime int64 `json:"endTime"`
ExitCode int `json:"exitCode"`
}{
Command: es.command,
RepoPath: es.repoPath.ToString(),
StartTime: es.startedAt.UnixMilli(),
EndTime: es.endedAt.UnixMilli(),
Success: es.success,
Expand All @@ -142,12 +153,14 @@ func (es *executionSummary) MarshalJSON() ([]byte, error) {
}

// newExecutionSummary creates a executionSummary instance to track events in a `turbo run`.`
func newExecutionSummary(start time.Time, tracingProfile string) *executionSummary {
func newExecutionSummary(command string, repoPath turbopath.RelativeSystemPath, start time.Time, tracingProfile string) *executionSummary {
if tracingProfile != "" {
chrometracing.EnableTracing()
}

return &executionSummary{
command: command,
repoPath: repoPath,
success: 0,
failure: 0,
cached: 0,
Expand Down