aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/cli/internal/runsummary/execution_summary.go
diff options
context:
space:
mode:
Diffstat (limited to 'cli/internal/runsummary/execution_summary.go')
-rw-r--r--cli/internal/runsummary/execution_summary.go282
1 files changed, 0 insertions, 282 deletions
diff --git a/cli/internal/runsummary/execution_summary.go b/cli/internal/runsummary/execution_summary.go
deleted file mode 100644
index fabb690..0000000
--- a/cli/internal/runsummary/execution_summary.go
+++ /dev/null
@@ -1,282 +0,0 @@
-package runsummary
-
-import (
- "encoding/json"
- "fmt"
- "os"
- "sync"
- "time"
-
- "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"
-)
-
-// executionEvent represents a single event in the build process, i.e. a target starting or finishing
-// building, or reaching some milestone within those steps.
-type executionEvent struct {
- // Timestamp of this event
- Time time.Time
- // Duration of this event
- Duration time.Duration
- // Target which has just changed
- Label string
- // Its current status
- Status executionEventName
- // Error, only populated for failure statuses
- Err string
-
- exitCode *int
-}
-
-// executionEventName represents the status of a target when we log a build result.
-type executionEventName int
-
-// The collection of expected build result statuses.
-const (
- targetInitialized executionEventName = iota
- TargetBuilding
- TargetBuildStopped
- TargetExecuted
- TargetBuilt
- TargetCached
- TargetBuildFailed
-)
-
-func (en executionEventName) toString() string {
- switch en {
- case targetInitialized:
- return "initialized"
- case TargetBuilding:
- return "building"
- case TargetBuildStopped:
- return "buildStopped"
- case TargetExecuted:
- return "executed"
- case TargetBuilt:
- return "built"
- case TargetCached:
- return "cached"
- case TargetBuildFailed:
- return "buildFailed"
- }
-
- return ""
-}
-
-// TaskExecutionSummary contains data about the state of a single task in a turbo run.
-// Some fields are updated over time as the task prepares to execute and finishes execution.
-type TaskExecutionSummary struct {
- startAt time.Time // set once
- status executionEventName // current status, updated during execution
- err string // only populated for failure statuses
- Duration time.Duration // updated during the task execution
- 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) {
- serializable := struct {
- Start int64 `json:"startTime"`
- End int64 `json:"endTime"`
- Err string `json:"error,omitempty"`
- ExitCode *int `json:"exitCode"`
- }{
- Start: ts.startAt.UnixMilli(),
- End: ts.endTime().UnixMilli(),
- Err: ts.err,
- ExitCode: ts.exitCode,
- }
-
- return json.Marshal(&serializable)
-}
-
-// ExitCode access exit code nil means no exit code was received
-func (ts *TaskExecutionSummary) ExitCode() *int {
- var exitCode int
- if ts.exitCode == nil {
- return nil
- }
- exitCode = *ts.exitCode
- return &exitCode
-}
-
-// executionSummary is the state of the entire `turbo run`. Individual task state in `Tasks` field
-type executionSummary struct {
- // mu guards reads/writes to the `state` field
- mu sync.Mutex
- tasks map[string]*TaskExecutionSummary // key is a taskID
- profileFilename string
-
- // These get serialized to JSON
- 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
-}
-
-// MarshalJSON munges the executionSummary into a format we want
-// We'll use an anonmyous, private struct for this, so it's not confusingly duplicated.
-func (es *executionSummary) MarshalJSON() ([]byte, error) {
- serializable := struct {
- 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,
- Failure: es.failure,
- Cached: es.cached,
- Attempted: es.attempted,
- ExitCode: es.exitCode,
- }
-
- return json.Marshal(&serializable)
-}
-
-// newExecutionSummary creates a executionSummary instance to track events in a `turbo run`.`
-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,
- attempted: 0,
- tasks: make(map[string]*TaskExecutionSummary),
- startedAt: start,
- profileFilename: tracingProfile,
- }
-}
-
-// Run starts the Execution of a single task. It returns a function that can
-// be used to update the state of a given taskID with the executionEventName enum
-func (es *executionSummary) run(taskID string) (func(outcome executionEventName, err error, exitCode *int), *TaskExecutionSummary) {
- start := time.Now()
- taskExecutionSummary := es.add(&executionEvent{
- Time: start,
- Label: taskID,
- Status: targetInitialized,
- })
-
- tracer := chrometracing.Event(taskID)
-
- // This function can be called with an enum and an optional error to update
- // the state of a given taskID.
- tracerFn := func(outcome executionEventName, err error, exitCode *int) {
- defer tracer.Done()
- now := time.Now()
- result := &executionEvent{
- Time: now,
- Duration: now.Sub(start),
- Label: taskID,
- Status: outcome,
- // We'll assign this here regardless of whether it is nil, but we'll check for nil
- // when we assign it to the taskExecutionSummary.
- exitCode: exitCode,
- }
-
- if err != nil {
- result.Err = err.Error()
- }
-
- // Ignore the return value here
- es.add(result)
- }
-
- return tracerFn, taskExecutionSummary
-}
-
-func (es *executionSummary) add(event *executionEvent) *TaskExecutionSummary {
- es.mu.Lock()
- defer es.mu.Unlock()
-
- var taskExecSummary *TaskExecutionSummary
- if ts, ok := es.tasks[event.Label]; ok {
- // If we already know about this task, we'll update it with the new event
- taskExecSummary = ts
- } else {
- // If we don't know about it yet, init and add it into the parent struct
- // (event.Status should always be `targetBuilding` here.)
- taskExecSummary = &TaskExecutionSummary{startAt: event.Time}
- es.tasks[event.Label] = taskExecSummary
- }
-
- // Update the Status, Duration, and Err fields
- taskExecSummary.status = event.Status
- taskExecSummary.err = event.Err
- taskExecSummary.Duration = event.Duration
-
- if event.exitCode != nil {
- taskExecSummary.exitCode = event.exitCode
- }
-
- switch {
- case event.Status == TargetBuilding:
- es.attempted++
- case event.Status == TargetBuildFailed:
- es.failure++
- case event.Status == TargetCached:
- es.cached++
- case event.Status == TargetBuilt:
- es.success++
- }
-
- return es.tasks[event.Label]
-}
-
-// writeChromeTracing writes to a profile name if the `--profile` flag was passed to turbo run
-func writeChrometracing(filename string, terminal cli.Ui) error {
- outputPath := chrometracing.Path()
- if outputPath == "" {
- // tracing wasn't enabled
- return nil
- }
-
- name := fmt.Sprintf("turbo-%s.trace", time.Now().Format(time.RFC3339))
- if filename != "" {
- name = filename
- }
- if err := chrometracing.Close(); err != nil {
- terminal.Warn(fmt.Sprintf("Failed to flush tracing data: %v", err))
- }
- cwdRaw, err := os.Getwd()
- if err != nil {
- return err
- }
- root, err := fs.GetCwd(cwdRaw)
- if err != nil {
- return err
- }
- // chrometracing.Path() is absolute by default, but can still be relative if overriden via $CHROMETRACING_DIR
- // so we have to account for that before converting to turbopath.AbsoluteSystemPath
- if err := fs.CopyFile(&fs.LstatCachedFile{Path: fs.ResolveUnknownPath(root, outputPath)}, name); err != nil {
- return err
- }
- return nil
-}