func printStepSummary(title string, resultCode int, duration time.Duration, exitCode int) { runTime := bitrise.TimeToFormattedSeconds(duration, " sec") content := fmt.Sprintf("%s | .... | %s", title, runTime) if resultCode == stepRunResultCodeFailed || resultCode == stepRunResultCodeFailedNotImportant { content = fmt.Sprintf("%s | .... | exit code: %d | %s", title, exitCode, runTime) } if len(content) > stepRunSummaryBoxMaxWidthChars { dif := len(content) - stepRunSummaryBoxMaxWidthChars title = title[0:(len(title) - dif)] content = fmt.Sprintf("%s | .... | %s", title, runTime) if resultCode == stepRunResultCodeFailed || resultCode == stepRunResultCodeFailedNotImportant { content = fmt.Sprintf("%s | .... | exit code: %d | %s", title, exitCode, runTime) } } sep := strings.Repeat("-", len(content)+2) log.Info(sep) switch resultCode { case stepRunResultCodeSuccess: runStateIcon := "✅ " content = fmt.Sprintf("%s | %s | %s", runStateIcon, colorstring.Green(title), runTime) break case stepRunResultCodeFailed: runStateIcon := "❌ " content = fmt.Sprintf("%s | %s | %s | exit code: %d", runStateIcon, colorstring.Red(title), runTime, exitCode) break case stepRunResultCodeFailedNotImportant: runStateIcon := "❌ " content = fmt.Sprintf("%s | %s | %s | exit code: %d", runStateIcon, colorstring.Yellow(title), runTime, exitCode) break case stepRunResultCodeSkipped, stepRunResultCodeSkippedWithRunIf: runStateIcon := "➡ " content = fmt.Sprintf("%s | %s | %s", runStateIcon, colorstring.White(title), runTime) break default: log.Error("Unkown result code") return } log.Infof("| " + content + " |") log.Info(sep) fmt.Println() }
func activateAndRunSteps(workflow models.WorkflowModel, defaultStepLibSource string) (workflowRunResults models.BuildRunResultsModel) { log.Debugln("[BITRISE_CLI] - Activating and running steps") var stepStartTime time.Time registerStepRunResults := func(step stepmanModels.StepModel, resultCode int, exitCode int, err error) { stepResults := models.StepRunResultsModel{ StepName: *step.Title, Error: err, ExitCode: exitCode, } switch resultCode { case stepRunResultCodeSuccess: workflowRunResults.SuccessSteps = append(workflowRunResults.SuccessSteps, stepResults) break case stepRunResultCodeFailed: log.Errorf("Step (%s) failed, error: (%v)", *step.Title, err) workflowRunResults.FailedSteps = append(workflowRunResults.FailedSteps, stepResults) break case stepRunResultCodeFailedNotImportant: log.Warnf("Step (%s) failed, but was marked as not important, error: (%v)", *step.Title, err) workflowRunResults.FailedNotImportantSteps = append(workflowRunResults.FailedNotImportantSteps, stepResults) break case stepRunResultCodeSkipped: log.Warnf("A previous step failed, and this step (%s) was not marked as IsAlwaysRun, skipped", *step.Title) workflowRunResults.SkippedSteps = append(workflowRunResults.SkippedSteps, stepResults) break case stepRunResultCodeSkippedWithRunIf: log.Warn("The step's (" + *step.Title + ") Run-If expression evaluated to false - skipping") log.Info("The Run-If expression was: ", colorstring.White(*step.RunIf)) workflowRunResults.SkippedSteps = append(workflowRunResults.SkippedSteps, stepResults) break default: log.Error("Unkown result code") return } if resultCode != stepRunResultCodeSuccess { if err := setBuildFailedEnv(true); err != nil { log.Error("Failed to set Build Status envs") } } printStepSummary(*step.Title, resultCode, time.Now().Sub(stepStartTime), exitCode) } registerStepListItemRunResults := func(stepListItem models.StepListItemModel, resultCode int, exitCode int, err error) { name := "" for key := range stepListItem { name = key break } stepResults := models.StepRunResultsModel{ StepName: name, Error: err, ExitCode: exitCode, } switch resultCode { case stepRunResultCodeSuccess: workflowRunResults.SuccessSteps = append(workflowRunResults.SuccessSteps, stepResults) break case stepRunResultCodeFailed: log.Errorf("Step (%s) failed, error: (%v)", name, err) workflowRunResults.FailedSteps = append(workflowRunResults.FailedSteps, stepResults) break case stepRunResultCodeFailedNotImportant: log.Warnf("Step (%s) failed, but was marked as not important, error: (%v)", name, err) workflowRunResults.FailedNotImportantSteps = append(workflowRunResults.FailedNotImportantSteps, stepResults) break case stepRunResultCodeSkipped: log.Warnf("A previous step failed, and this step (%s) was not marked as IsAlwaysRun, skipped", name) workflowRunResults.SkippedSteps = append(workflowRunResults.SkippedSteps, stepResults) break case stepRunResultCodeSkippedWithRunIf: log.Warn("The step's (" + name + ") Run-If expression evaluated to false - skipping") workflowRunResults.SkippedSteps = append(workflowRunResults.SkippedSteps, stepResults) break default: log.Error("Unkown result code") return } if resultCode != stepRunResultCodeSuccess { if err := setBuildFailedEnv(true); err != nil { log.Error("Failed to set Build Status envs") } } printStepSummary(name, resultCode, time.Now().Sub(stepStartTime), exitCode) } for idx, stepListItm := range workflow.Steps { stepStartTime = time.Now() if err := setBuildFailedEnv(buildRunResults.IsBuildFailed()); err != nil { log.Error("Failed to set Build Status envs") } compositeStepIDStr, workflowStep, err := models.GetStepIDStepDataPair(stepListItm) if err != nil { registerStepListItemRunResults(stepListItm, stepRunResultCodeFailed, 1, err) continue } stepIDData, err := models.CreateStepIDDataFromString(compositeStepIDStr, defaultStepLibSource) if err != nil { registerStepListItemRunResults(stepListItm, stepRunResultCodeFailed, 1, err) continue } log.Debugf("[BITRISE_CLI] - Running Step: %#v", workflowStep) if err := cleanupStepWorkDir(); err != nil { registerStepListItemRunResults(stepListItm, stepRunResultCodeFailed, 1, err) continue } stepDir := bitrise.BitriseWorkStepsDirPath stepYMLPth := bitrise.BitriseWorkDirPath + "/current_step.yml" if stepIDData.SteplibSource == "path" { log.Debugf("[BITRISE_CLI] - Local step found: (path:%s)", stepIDData.IDorURI) stepAbsLocalPth, err := pathutil.AbsPath(stepIDData.IDorURI) if err != nil { registerStepListItemRunResults(stepListItm, stepRunResultCodeFailed, 1, err) continue } log.Debugln("stepAbsLocalPth:", stepAbsLocalPth, "|stepDir:", stepDir) if err := bitrise.RunCopyDir(stepAbsLocalPth, stepDir, true); err != nil { registerStepListItemRunResults(stepListItm, stepRunResultCodeFailed, 1, err) continue } if err := bitrise.RunCopyFile(stepAbsLocalPth+"/step.yml", stepYMLPth); err != nil { registerStepListItemRunResults(stepListItm, stepRunResultCodeFailed, 1, err) continue } } else if stepIDData.SteplibSource == "git" { log.Debugf("[BITRISE_CLI] - Remote step, with direct git uri: (uri:%s) (tag-or-branch:%s)", stepIDData.IDorURI, stepIDData.Version) if err := bitrise.RunGitClone(stepIDData.IDorURI, stepDir, stepIDData.Version); err != nil { registerStepListItemRunResults(stepListItm, stepRunResultCodeFailed, 1, err) continue } if err := bitrise.RunCopyFile(stepDir+"/step.yml", stepYMLPth); err != nil { registerStepListItemRunResults(stepListItm, stepRunResultCodeFailed, 1, err) continue } } else if stepIDData.SteplibSource != "" { log.Debugf("[BITRISE_CLI] - Steplib (%s) step (id:%s) (version:%s) found, activating step", stepIDData.SteplibSource, stepIDData.IDorURI, stepIDData.Version) if err := bitrise.RunStepmanSetup(stepIDData.SteplibSource); err != nil { registerStepListItemRunResults(stepListItm, stepRunResultCodeFailed, 1, err) continue } if err := bitrise.RunStepmanActivate(stepIDData.SteplibSource, stepIDData.IDorURI, stepIDData.Version, stepDir, stepYMLPth); err != nil { registerStepListItemRunResults(stepListItm, stepRunResultCodeFailed, 1, err) continue } else { log.Debugf("[BITRISE_CLI] - Step activated: (ID:%s) (version:%s)", stepIDData.IDorURI, stepIDData.Version) } } else { registerStepListItemRunResults(stepListItm, stepRunResultCodeFailed, 1, fmt.Errorf("Invalid stepIDData: No SteplibSource or LocalPath defined (%v)", stepIDData)) continue } specStep, err := bitrise.ReadSpecStep(stepYMLPth) log.Debugf("Spec read from YML: %#v\n", specStep) if err != nil { registerStepListItemRunResults(stepListItm, stepRunResultCodeFailed, 1, err) continue } mergedStep, err := models.MergeStepWith(specStep, workflowStep) if err != nil { registerStepListItemRunResults(stepListItm, stepRunResultCodeFailed, 1, err) continue } printRunningStep(*mergedStep.Title, idx) if mergedStep.RunIf != nil && *mergedStep.RunIf != "" { isRun, err := bitrise.EvaluateStepTemplateToBool(*mergedStep.RunIf, workflowRunResults, IsCIMode) if err != nil { registerStepRunResults(mergedStep, stepRunResultCodeFailed, 1, err) continue } if !isRun { registerStepRunResults(mergedStep, stepRunResultCodeSkippedWithRunIf, 0, err) continue } } if workflowRunResults.IsBuildFailed() && !*mergedStep.IsAlwaysRun { registerStepRunResults(mergedStep, stepRunResultCodeSkipped, 0, err) continue } else { exit, err := runStep(mergedStep, stepIDData, stepDir) if err != nil { registerStepRunResults(mergedStep, stepRunResultCodeFailed, exit, err) continue } else { registerStepRunResults(mergedStep, stepRunResultCodeSuccess, 0, nil) } } } return workflowRunResults }