From 893a92e45985528761876cb33a9c0d0ec1fae617 Mon Sep 17 00:00:00 2001 From: Mehul Kar Date: Wed, 19 Apr 2023 13:59:06 -0700 Subject: [PATCH 1/3] Send logs with task summaries --- cli/internal/runsummary/run_summary.go | 4 +-- cli/internal/runsummary/spaces.go | 34 ++++++++----------------- cli/internal/runsummary/task_summary.go | 11 ++++++++ 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/cli/internal/runsummary/run_summary.go b/cli/internal/runsummary/run_summary.go index 115b3fd9aa00f..5fbf4a1f8b9d9 100644 --- a/cli/internal/runsummary/run_summary.go +++ b/cli/internal/runsummary/run_summary.go @@ -234,7 +234,7 @@ func (rsm *Meta) record() (string, []error) { payload := rsm.newSpacesRunCreatePayload() if startPayload, err := json.Marshal(payload); err == nil { if resp, err := rsm.apiClient.JSONPost(createRunEndpoint, startPayload); err != nil { - errs = append(errs, err) + errs = append(errs, fmt.Errorf("POST %s: %w", createRunEndpoint, err)) } else { if err := json.Unmarshal(resp, response); err != nil { errs = append(errs, fmt.Errorf("Error unmarshaling response: %w", err)) @@ -250,7 +250,7 @@ func (rsm *Meta) record() (string, []error) { if donePayload, err := json.Marshal(newSpacesDonePayload(rsm.RunSummary)); err == nil { patchURL := fmt.Sprintf(runsPatchEndpoint, rsm.spaceID, response.ID) if _, err := rsm.apiClient.JSONPatch(patchURL, donePayload); err != nil { - errs = append(errs, fmt.Errorf("Error marking run as done: %w", err)) + errs = append(errs, fmt.Errorf("PATCH %s: %w", patchURL, err)) } } } diff --git a/cli/internal/runsummary/spaces.go b/cli/internal/runsummary/spaces.go index 8ded4b799a772..bf19941806a43 100644 --- a/cli/internal/runsummary/spaces.go +++ b/cli/internal/runsummary/spaces.go @@ -11,30 +11,14 @@ type spacesRunResponse struct { } type spacesRunPayload struct { - // StartTime is when this run was started - StartTime int64 `json:"startTime,omitempty"` - - // EndTime is when this run ended. We will never be submitting start and endtime at the same time. - EndTime int64 `json:"endTime,omitempty"` - - // Status is - Status string `json:"status,omitempty"` - - // Type should be hardcoded to TURBO - Type string `json:"type,omitempty"` - - // ExitCode is the exit code for the full run - ExitCode int `json:"exitCode,omitempty"` - - // The command that kicked off the turbo run - Command string `json:"command,omitempty"` - - // RepositoryPath is the relative directory from the turborepo root to where - // the command was invoked. - RepositoryPath string `json:"repositoryPath,omitempty"` - - // Context is the host on which this Run was executed (e.g. Github Action, Vercel, etc) - Context string `json:"context,omitempty"` + StartTime int64 `json:"startTime,omitempty"` // when the run was started + EndTime int64 `json:"endTime,omitempty"` // when the run ended. we should never submit start and end at the same time. + Status string `json:"status,omitempty"` // Status is "running" or "completed" + Type string `json:"type,omitempty"` // hardcoded to "TURBO" + ExitCode int `json:"exitCode,omitempty"` // exit code for the full run + Command string `json:"command,omitempty"` // the thing that kicked off the turbo run + RepositoryPath string `json:"repositoryPath,omitempty"` // where the command was invoked from + Context string `json:"context,omitempty"` // the host on which this Run was executed (e.g. Github Action, Vercel, etc) // TODO: we need to add these in // originationUser string @@ -64,6 +48,7 @@ type spacesTask struct { ExitCode int `json:"exitCode,omitempty"` Dependencies []string `json:"dependencies,omitempty"` Dependents []string `json:"dependents,omitempty"` + Logs string `json:"log"` } func (rsm *Meta) newSpacesRunCreatePayload() *spacesRunPayload { @@ -106,5 +91,6 @@ func newSpacesTaskPayload(taskSummary *TaskSummary) *spacesTask { ExitCode: *taskSummary.Execution.exitCode, Dependencies: taskSummary.Dependencies, Dependents: taskSummary.Dependents, + Logs: string(taskSummary.GetLogs()), } } diff --git a/cli/internal/runsummary/task_summary.go b/cli/internal/runsummary/task_summary.go index 7aa470cb5816b..fb0cb30a5e8a4 100644 --- a/cli/internal/runsummary/task_summary.go +++ b/cli/internal/runsummary/task_summary.go @@ -1,6 +1,8 @@ package runsummary import ( + "os" + "github.com/vercel/turbo/cli/internal/cache" "github.com/vercel/turbo/cli/internal/fs" "github.com/vercel/turbo/cli/internal/turbopath" @@ -76,6 +78,15 @@ type TaskSummary struct { Execution *TaskExecutionSummary `json:"execution,omitempty"` // omit when it's not set } +// GetLogs reads the Logfile and returns the data +func (ts *TaskSummary) GetLogs() []byte { + bytes, err := os.ReadFile(ts.LogFile) + if err != nil { + return []byte{} + } + return bytes +} + // TaskEnvVarSummary contains the environment variables that impacted a task's hash type TaskEnvVarSummary struct { Configured []string `json:"configured"` From c6f15224967c5371884c73a7e0a33bb4948b88ba Mon Sep 17 00:00:00 2001 From: Mehul Kar Date: Wed, 19 Apr 2023 14:18:37 -0700 Subject: [PATCH 2/3] Add a spinner after 1s while uploading --- cli/internal/run/run.go | 1 + cli/internal/runsummary/run_summary.go | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/cli/internal/run/run.go b/cli/internal/run/run.go index 2ac114121187d..a650686e390c4 100644 --- a/cli/internal/run/run.go +++ b/cli/internal/run/run.go @@ -362,6 +362,7 @@ func (r *run) run(ctx gocontext.Context, targets []string) error { // RunSummary contains information that is statically analyzable about // the tasks that we expect to run based on the user command. summary := runsummary.NewRunSummary( + ctx, startAt, r.base.UI, r.base.RepoRoot, diff --git a/cli/internal/runsummary/run_summary.go b/cli/internal/runsummary/run_summary.go index 5fbf4a1f8b9d9..3caffa3f0e166 100644 --- a/cli/internal/runsummary/run_summary.go +++ b/cli/internal/runsummary/run_summary.go @@ -2,6 +2,7 @@ package runsummary import ( + "context" "encoding/json" "fmt" "path/filepath" @@ -11,6 +12,7 @@ import ( "github.com/mitchellh/cli" "github.com/segmentio/ksuid" "github.com/vercel/turbo/cli/internal/client" + "github.com/vercel/turbo/cli/internal/spinner" "github.com/vercel/turbo/cli/internal/turbopath" "github.com/vercel/turbo/cli/internal/util" "github.com/vercel/turbo/cli/internal/workspace" @@ -41,6 +43,7 @@ const ( // about the Run and references to other things that we need. type Meta struct { RunSummary *RunSummary + ctx context.Context ui cli.Ui repoRoot turbopath.AbsoluteSystemPath // used to write run summary repoPath turbopath.RelativeSystemPath @@ -66,6 +69,7 @@ type RunSummary struct { // NewRunSummary returns a RunSummary instance func NewRunSummary( + ctx context.Context, startAt time.Time, ui cli.Ui, repoRoot turbopath.AbsoluteSystemPath, @@ -105,6 +109,7 @@ func NewRunSummary( GlobalHashSummary: globalHashSummary, }, ui: ui, + ctx: ctx, runType: runType, repoRoot: repoRoot, singlePackage: singlePackage, @@ -161,8 +166,19 @@ func (rsm *Meta) Close(exitCode int, workspaceInfos workspace.Catalog) error { return nil } - url, errs := rsm.record() + // Wrap the record function so we can hoist out url/errors but keep + // the function signature/type the spinner.WaitFor expects. + var url string + var errs []error + record := func() { + url, errs = rsm.record() + } + + func() { + _ = spinner.WaitFor(rsm.ctx, record, rsm.ui, "...sending run summary...", 1000*time.Millisecond) + }() + // After the spinner is done if len(errs) > 0 { rsm.ui.Warn("Errors recording run to Spaces") for _, err := range errs { From 7a378b6dd45f0a40cdef9c73cf8d5fda49e77c88 Mon Sep 17 00:00:00 2001 From: Mehul Kar Date: Thu, 20 Apr 2023 14:54:23 -0700 Subject: [PATCH 3/3] Pass in context where its used --- cli/internal/run/dry_run.go | 2 +- cli/internal/run/real_run.go | 2 +- cli/internal/run/run.go | 1 - cli/internal/runsummary/run_summary.go | 7 ++----- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/cli/internal/run/dry_run.go b/cli/internal/run/dry_run.go index f4b04aa41ebf7..eeee431cb0052 100644 --- a/cli/internal/run/dry_run.go +++ b/cli/internal/run/dry_run.go @@ -86,7 +86,7 @@ func DryRun( // The exitCode isn't really used by the Run Summary Close() method for dry runs // but we pass in a successful value to match Real Runs. - return summary.Close(0, g.WorkspaceInfos) + return summary.Close(ctx, 0, g.WorkspaceInfos) } func populateCacheState(turboCache cache.Cache, taskSummaries []*runsummary.TaskSummary) { diff --git a/cli/internal/run/real_run.go b/cli/internal/run/real_run.go index b72c6f6ebb3c2..32c79659f3e28 100644 --- a/cli/internal/run/real_run.go +++ b/cli/internal/run/real_run.go @@ -172,7 +172,7 @@ func RealRun( } } - if err := runSummary.Close(exitCode, g.WorkspaceInfos); err != nil { + if err := runSummary.Close(ctx, exitCode, g.WorkspaceInfos); err != nil { // We don't need to throw an error, but we can warn on this. // Note: this method doesn't actually return an error for Real Runs at the time of writing. base.UI.Info(fmt.Sprintf("Failed to close Run Summary %v", err)) diff --git a/cli/internal/run/run.go b/cli/internal/run/run.go index a650686e390c4..2ac114121187d 100644 --- a/cli/internal/run/run.go +++ b/cli/internal/run/run.go @@ -362,7 +362,6 @@ func (r *run) run(ctx gocontext.Context, targets []string) error { // RunSummary contains information that is statically analyzable about // the tasks that we expect to run based on the user command. summary := runsummary.NewRunSummary( - ctx, startAt, r.base.UI, r.base.RepoRoot, diff --git a/cli/internal/runsummary/run_summary.go b/cli/internal/runsummary/run_summary.go index 3caffa3f0e166..9f006e53b3997 100644 --- a/cli/internal/runsummary/run_summary.go +++ b/cli/internal/runsummary/run_summary.go @@ -43,7 +43,6 @@ const ( // about the Run and references to other things that we need. type Meta struct { RunSummary *RunSummary - ctx context.Context ui cli.Ui repoRoot turbopath.AbsoluteSystemPath // used to write run summary repoPath turbopath.RelativeSystemPath @@ -69,7 +68,6 @@ type RunSummary struct { // NewRunSummary returns a RunSummary instance func NewRunSummary( - ctx context.Context, startAt time.Time, ui cli.Ui, repoRoot turbopath.AbsoluteSystemPath, @@ -109,7 +107,6 @@ func NewRunSummary( GlobalHashSummary: globalHashSummary, }, ui: ui, - ctx: ctx, runType: runType, repoRoot: repoRoot, singlePackage: singlePackage, @@ -129,7 +126,7 @@ func (rsm *Meta) getPath() turbopath.AbsoluteSystemPath { } // Close wraps up the RunSummary at the end of a `turbo run`. -func (rsm *Meta) Close(exitCode int, workspaceInfos workspace.Catalog) error { +func (rsm *Meta) Close(ctx context.Context, exitCode int, workspaceInfos workspace.Catalog) error { if rsm.runType == runTypeDryJSON || rsm.runType == runTypeDryText { return rsm.closeDryRun(workspaceInfos) } @@ -175,7 +172,7 @@ func (rsm *Meta) Close(exitCode int, workspaceInfos workspace.Catalog) error { } func() { - _ = spinner.WaitFor(rsm.ctx, record, rsm.ui, "...sending run summary...", 1000*time.Millisecond) + _ = spinner.WaitFor(ctx, record, rsm.ui, "...sending run summary...", 1000*time.Millisecond) }() // After the spinner is done