From 9be50f9ce6c6fac84ccc36c215c59d7da583d964 Mon Sep 17 00:00:00 2001 From: Mehul Kar Date: Thu, 20 Apr 2023 15:29:45 -0700 Subject: [PATCH] Include logs when posting task summary (#4642) --- cli/internal/run/dry_run.go | 2 +- cli/internal/run/real_run.go | 2 +- cli/internal/runsummary/run_summary.go | 21 ++++++++++++--- cli/internal/runsummary/spaces.go | 34 ++++++++----------------- cli/internal/runsummary/task_summary.go | 11 ++++++++ 5 files changed, 40 insertions(+), 30 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/runsummary/run_summary.go b/cli/internal/runsummary/run_summary.go index 115b3fd9aa00f..9f006e53b3997 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" @@ -124,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) } @@ -161,8 +163,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(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 { @@ -234,7 +247,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 +263,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"`