github.com/pulumi/terraform@v1.4.0/pkg/cloud/backend_taskStage_taskResults.go (about)

     1  package cloud
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/hashicorp/go-tfe"
     8  )
     9  
    10  type taskResultSummary struct {
    11  	unreachable     bool
    12  	pending         int
    13  	failed          int
    14  	failedMandatory int
    15  	passed          int
    16  }
    17  
    18  type taskResultSummarizer struct {
    19  	finished bool
    20  	cloud    *Cloud
    21  	counter  int
    22  }
    23  
    24  func newTaskResultSummarizer(b *Cloud, ts *tfe.TaskStage) taskStageSummarizer {
    25  	if len(ts.TaskResults) == 0 {
    26  		return nil
    27  	}
    28  	return &taskResultSummarizer{
    29  		finished: false,
    30  		cloud:    b,
    31  	}
    32  }
    33  
    34  func (trs *taskResultSummarizer) Summarize(context *IntegrationContext, output IntegrationOutputWriter, ts *tfe.TaskStage) (bool, *string, error) {
    35  	if trs.finished {
    36  		return false, nil, nil
    37  	}
    38  	trs.counter++
    39  
    40  	counts := summarizeTaskResults(ts.TaskResults)
    41  
    42  	if counts.pending != 0 {
    43  		pendingMessage := "%d tasks still pending, %d passed, %d failed ... "
    44  		message := fmt.Sprintf(pendingMessage, counts.pending, counts.passed, counts.failed)
    45  		return true, &message, nil
    46  	}
    47  	if counts.unreachable {
    48  		output.Output("Skipping task results.")
    49  		output.End()
    50  		return false, nil, nil
    51  	}
    52  
    53  	// Print out the summary
    54  	trs.runTasksWithTaskResults(output, ts.TaskResults, counts)
    55  
    56  	// Mark as finished
    57  	trs.finished = true
    58  
    59  	return false, nil, nil
    60  }
    61  
    62  func summarizeTaskResults(taskResults []*tfe.TaskResult) *taskResultSummary {
    63  	var pendingCount, errCount, errMandatoryCount, passedCount int
    64  	for _, task := range taskResults {
    65  		if task.Status == tfe.TaskUnreachable {
    66  			return &taskResultSummary{
    67  				unreachable: true,
    68  			}
    69  		} else if task.Status == tfe.TaskRunning || task.Status == tfe.TaskPending {
    70  			pendingCount++
    71  		} else if task.Status == tfe.TaskPassed {
    72  			passedCount++
    73  		} else {
    74  			// Everything else is a failure
    75  			errCount++
    76  			if task.WorkspaceTaskEnforcementLevel == tfe.Mandatory {
    77  				errMandatoryCount++
    78  			}
    79  		}
    80  	}
    81  
    82  	return &taskResultSummary{
    83  		unreachable:     false,
    84  		pending:         pendingCount,
    85  		failed:          errCount,
    86  		failedMandatory: errMandatoryCount,
    87  		passed:          passedCount,
    88  	}
    89  }
    90  
    91  func (trs *taskResultSummarizer) runTasksWithTaskResults(output IntegrationOutputWriter, taskResults []*tfe.TaskResult, count *taskResultSummary) {
    92  	// Track the first task name that is a mandatory enforcement level breach.
    93  	var firstMandatoryTaskFailed *string = nil
    94  
    95  	if trs.counter == 0 {
    96  		output.Output(fmt.Sprintf("All tasks completed! %d passed, %d failed", count.passed, count.failed))
    97  	} else {
    98  		output.OutputElapsed(fmt.Sprintf("All tasks completed! %d passed, %d failed", count.passed, count.failed), 50)
    99  	}
   100  
   101  	output.Output("")
   102  
   103  	for _, t := range taskResults {
   104  		capitalizedStatus := string(t.Status)
   105  		capitalizedStatus = strings.ToUpper(capitalizedStatus[:1]) + capitalizedStatus[1:]
   106  
   107  		status := "[green]" + capitalizedStatus
   108  		if t.Status != "passed" {
   109  			level := string(t.WorkspaceTaskEnforcementLevel)
   110  			level = strings.ToUpper(level[:1]) + level[1:]
   111  			status = fmt.Sprintf("[red]%s (%s)", capitalizedStatus, level)
   112  
   113  			if t.WorkspaceTaskEnforcementLevel == "mandatory" && firstMandatoryTaskFailed == nil {
   114  				firstMandatoryTaskFailed = &t.TaskName
   115  			}
   116  		}
   117  
   118  		title := fmt.Sprintf(`%s ⸺   %s`, t.TaskName, status)
   119  		output.SubOutput(title)
   120  
   121  		if len(t.Message) > 0 {
   122  			output.SubOutput(fmt.Sprintf("[dim]%s", t.Message))
   123  		}
   124  		if len(t.URL) > 0 {
   125  			output.SubOutput(fmt.Sprintf("[dim]Details: %s", t.URL))
   126  		}
   127  		output.SubOutput("")
   128  	}
   129  
   130  	// If a mandatory enforcement level is breached, return an error.
   131  	var overall string = "[green]Passed"
   132  	if firstMandatoryTaskFailed != nil {
   133  		overall = "[red]Failed"
   134  		if count.failedMandatory > 1 {
   135  			output.Output(fmt.Sprintf("[reset][bold][red]Error:[reset][bold]the run failed because %d mandatory tasks are required to succeed", count.failedMandatory))
   136  		} else {
   137  			output.Output(fmt.Sprintf("[reset][bold][red]Error: [reset][bold]the run failed because the run task, %s, is required to succeed", *firstMandatoryTaskFailed))
   138  		}
   139  	} else if count.failed > 0 { // we have failures but none of them mandatory
   140  		overall = "[green]Passed with advisory failures"
   141  	}
   142  
   143  	output.SubOutput("")
   144  	output.SubOutput("[bold]Overall Result: " + overall)
   145  
   146  	output.End()
   147  }