func TestPrintRunningStepFooter(t *testing.T) { stepInfo := stepmanModels.StepInfoModel{ Title: longStr, Version: longStr, } result := models.StepRunResultsModel{ StepInfo: stepInfo, Status: models.StepRunStatusCodeSuccess, Idx: 0, RunTime: 10000000, Error: errors.New(longStr), ExitCode: 1, } PrintRunningStepFooter(result, true) PrintRunningStepFooter(result, false) stepInfo.Title = "" result = models.StepRunResultsModel{ StepInfo: stepInfo, Status: models.StepRunStatusCodeSuccess, Idx: 0, RunTime: 0, Error: nil, ExitCode: 0, } PrintRunningStepFooter(result, true) PrintRunningStepFooter(result, false) }
func TestPrintSummary(t *testing.T) { PrintSummary(models.BuildRunResultsModel{}) stepInfo := stepmanModels.StepInfoModel{ Title: longStr, Version: longStr, } result1 := models.StepRunResultsModel{ StepInfo: stepInfo, Status: models.StepRunStatusCodeSuccess, Idx: 0, RunTime: 10000000, Error: errors.New(longStr), ExitCode: 1, } stepInfo.Title = "" result2 := models.StepRunResultsModel{ StepInfo: stepInfo, Status: models.StepRunStatusCodeSuccess, Idx: 0, RunTime: 0, Error: nil, ExitCode: 0, } buildResults := models.BuildRunResultsModel{ StartTime: time.Now(), StepmanUpdates: map[string]int{}, SuccessSteps: []models.StepRunResultsModel{result1, result2}, } PrintSummary(buildResults) }
func TestGetRunningStepFooterMainSection(t *testing.T) { stepInfo := stepmanModels.StepInfoModel{ Title: longStr, Version: longStr, } result := models.StepRunResultsModel{ StepInfo: stepInfo, Status: models.StepRunStatusCodeFailed, Idx: 0, RunTime: 10000000, Error: errors.New(longStr), ExitCode: 1, } cell := getRunningStepFooterMainSection(result) require.Equal(t, "| 🚫 | \x1b[31;1mThis is a very long string,\nthis is a very ... (exit code: 1)\x1b[0m| 0.01 sec |", cell) stepInfo.Title = "" result = models.StepRunResultsModel{ StepInfo: stepInfo, Status: models.StepRunStatusCodeSuccess, Idx: 0, RunTime: 0, Error: nil, ExitCode: 0, } cell = getRunningStepFooterMainSection(result) require.Equal(t, "| ✅ | \x1b[32;1m\x1b[0m | 0.00 sec |", cell) }
func TestGetTrimmedStepName(t *testing.T) { stepInfo := stepmanModels.StepInfoModel{ Title: longStr, Version: longStr, } result := models.StepRunResultsModel{ StepInfo: stepInfo, Status: models.StepRunStatusCodeSuccess, Idx: 0, RunTime: 10000000, Error: errors.New(longStr), ExitCode: 1, } stepName := getTrimmedStepName(result) require.Equal(t, "This is a very long string,\nthis is a very long string,\nth...", stepName) stepInfo.Title = "" result = models.StepRunResultsModel{ StepInfo: stepInfo, Status: models.StepRunStatusCodeSuccess, Idx: 0, RunTime: 0, Error: nil, ExitCode: 0, } stepName = getTrimmedStepName(result) require.Equal(t, "", stepName) }
func TestPrintRunningStepHeader(t *testing.T) { stepInfo := stepmanModels.StepInfoModel{ Title: "", Version: "", } PrintRunningStepHeader(stepInfo, 0) stepInfo.Title = longStr stepInfo.Version = "" PrintRunningStepHeader(stepInfo, 0) stepInfo.Title = "" stepInfo.Version = longStr PrintRunningStepHeader(stepInfo, 0) stepInfo.Title = longStr stepInfo.Version = longStr PrintRunningStepHeader(stepInfo, 0) }
func stepInfo(c *cli.Context) error { // Input validation format := c.String(FormatKey) collectionURI := c.String(CollectionKey) YMLPath := c.String(StepYMLKey) isShort := c.Bool(ShortKey) id := c.String(IDKey) version := c.String(VersionKey) if format == "" { format = OutputFormatRaw } else if !(format == OutputFormatRaw || format == OutputFormatJSON) { return fmt.Errorf("Invalid output format: %s", format) } if YMLPath == "" && collectionURI == "" { return fmt.Errorf("Missing required input: no StepLib, nor step.yml path defined as step info source") } if YMLPath != "" { // // Local step info step, err := stepman.ParseStepYml(YMLPath, false) if err != nil { return fmt.Errorf("Failed to parse step.yml (path:%s), err: %s", YMLPath, err) } inputs, err := getEnvInfos(step.Inputs) if err != nil { return fmt.Errorf("Failed to get step (path:%s) input infos, err: %s", YMLPath, err) } outputs, err := getEnvInfos(step.Outputs) if err != nil { return fmt.Errorf("Failed to get step (path:%s) output infos, err: %s", YMLPath, err) } stepInfo := models.StepInfoModel{ StepLib: YMLPath, Description: *step.Description, Source: *step.SourceCodeURL, Inputs: inputs, Outputs: outputs, } if err := printStepInfo(stepInfo, format, isShort, true); err != nil { return fmt.Errorf("Failed to print step info, err: %s", err) } } else { // // StepLib step info // Input validation if id == "" { return errors.New("Missing required input: step id") } // Check if setup was done for collection if exist, err := stepman.RootExistForCollection(collectionURI); err != nil { return fmt.Errorf("Failed to check if setup was done for steplib (%s), error: %s", collectionURI, err) } else if !exist { if err := setupSteplib(collectionURI, format != OutputFormatRaw); err != nil { return errors.New("Failed to setup steplib") } } // Check if step exist in collection collection, err := stepman.ReadStepSpec(collectionURI) if err != nil { return fmt.Errorf("Failed to read steps spec (spec.json), err: %s", err) } step, stepFound := collection.GetStep(id, version) if !stepFound { if version == "" { return fmt.Errorf("Collection doesn't contain any version of step (id:%s)", id) } return fmt.Errorf("Collection doesn't contain step (id:%s) (version:%s)", id, version) } latest, err := collection.GetLatestStepVersion(id) if err != nil { return fmt.Errorf("Failed to get latest version of step (id:%s)", id) } if version == "" { version = latest } inputs, err := getEnvInfos(step.Inputs) if err != nil { return fmt.Errorf("Failed to get step (id:%s) input infos, err: %s", id, err) } outputs, err := getEnvInfos(step.Outputs) if err != nil { return fmt.Errorf("Failed to get step (id:%s) output infos, err: %s", id, err) } stepInfo := models.StepInfoModel{ ID: id, Version: version, Latest: latest, Description: *step.Description, StepLib: collectionURI, Source: *step.SourceCodeURL, Inputs: inputs, Outputs: outputs, } route, found := stepman.ReadRoute(collectionURI) if !found { return fmt.Errorf("No route found for collection: %s", collectionURI) } globalStepInfoPth := stepman.GetStepGlobalInfoPath(route, id) if globalStepInfoPth != "" { globalInfo, found, err := stepman.ParseGlobalStepInfoYML(globalStepInfoPth) if err != nil { return fmt.Errorf("Failed to get step (path:%s) output infos, err: %s", globalStepInfoPth, err) } if found { stepInfo.GlobalInfo = globalInfo } } if err := printStepInfo(stepInfo, format, isShort, false); err != nil { return fmt.Errorf("Failed to print step info, err: %s", err) } } return nil }
func activateAndRunSteps(workflow models.WorkflowModel, defaultStepLibSource string, buildRunResults models.BuildRunResultsModel, environments *[]envmanModels.EnvironmentItemModel, isLastWorkflow bool) models.BuildRunResultsModel { log.Debugln("[BITRISE_CLI] - Activating and running steps") // ------------------------------------------ // In function global variables - These are global for easy use in local register step run result methods. var stepStartTime time.Time // ------------------------------------------ // In function method - Registration methods, for register step run results. registerStepRunResults := func(step stepmanModels.StepModel, stepInfoPtr stepmanModels.StepInfoModel, stepIdxPtr int, runIf string, resultCode, exitCode int, err error, isLastStep, printStepHeader bool) { if printStepHeader { bitrise.PrintRunningStepHeader(stepInfoPtr, step, stepIdxPtr) } stepInfoCopy := stepmanModels.StepInfoModel{ ID: stepInfoPtr.ID, Title: stepInfoPtr.Title, Version: stepInfoPtr.Version, Latest: stepInfoPtr.Latest, SupportURL: stepInfoPtr.SupportURL, SourceCodeURL: stepInfoPtr.SourceCodeURL, GlobalInfo: stepInfoPtr.GlobalInfo, } stepResults := models.StepRunResultsModel{ StepInfo: stepInfoCopy, Status: resultCode, Idx: buildRunResults.ResultsCount(), RunTime: time.Now().Sub(stepStartTime), Error: err, ExitCode: exitCode, } isExitStatusError := true if err != nil { isExitStatusError = errorutil.IsExitStatusError(err) } switch resultCode { case models.StepRunStatusCodeSuccess: buildRunResults.SuccessSteps = append(buildRunResults.SuccessSteps, stepResults) break case models.StepRunStatusCodeFailed: if !isExitStatusError { log.Errorf("Step (%s) failed, error: %s", stepInfoCopy.Title, err) } buildRunResults.FailedSteps = append(buildRunResults.FailedSteps, stepResults) break case models.StepRunStatusCodeFailedSkippable: if !isExitStatusError { log.Warnf("Step (%s) failed, but was marked as skippable, error: %s", stepInfoCopy.Title, err) } else { log.Warnf("Step (%s) failed, but was marked as skippable", stepInfoCopy.Title) } buildRunResults.FailedSkippableSteps = append(buildRunResults.FailedSkippableSteps, stepResults) break case models.StepRunStatusCodeSkipped: log.Warnf("A previous step failed, and this step (%s) was not marked as IsAlwaysRun, skipped", stepInfoCopy.Title) buildRunResults.SkippedSteps = append(buildRunResults.SkippedSteps, stepResults) break case models.StepRunStatusCodeSkippedWithRunIf: log.Warn("The step's (" + stepInfoCopy.Title + ") Run-If expression evaluated to false - skipping") if runIf != "" { log.Info("The Run-If expression was: ", colorstring.Blue(runIf)) } buildRunResults.SkippedSteps = append(buildRunResults.SkippedSteps, stepResults) break default: log.Error("Unkown result code") return } bitrise.PrintRunningStepFooter(stepResults, isLastStep) } // ------------------------------------------ // Main - Preparing & running the steps for idx, stepListItm := range workflow.Steps { // Per step variables stepStartTime = time.Now() isLastStep := isLastWorkflow && (idx == len(workflow.Steps)-1) stepInfoPtr := stepmanModels.StepInfoModel{} stepIdxPtr := idx // Per step cleanup if err := bitrise.SetBuildFailedEnv(buildRunResults.IsBuildFailed()); err != nil { log.Error("Failed to set Build Status envs") } if err := bitrise.CleanupStepWorkDir(); err != nil { registerStepRunResults(stepmanModels.StepModel{}, stepInfoPtr, stepIdxPtr, "", models.StepRunStatusCodeFailed, 1, err, isLastStep, true) continue } // // Preparing the step if err := tools.EnvmanInitAtPath(configs.InputEnvstorePath); err != nil { registerStepRunResults(stepmanModels.StepModel{}, stepInfoPtr, stepIdxPtr, "", models.StepRunStatusCodeFailed, 1, err, isLastStep, true) continue } if err := bitrise.ExportEnvironmentsList(*environments); err != nil { registerStepRunResults(stepmanModels.StepModel{}, stepInfoPtr, stepIdxPtr, "", models.StepRunStatusCodeFailed, 1, err, isLastStep, true) continue } // Get step id & version data compositeStepIDStr, workflowStep, err := models.GetStepIDStepDataPair(stepListItm) if err != nil { registerStepRunResults(stepmanModels.StepModel{}, stepInfoPtr, stepIdxPtr, "", models.StepRunStatusCodeFailed, 1, err, isLastStep, true) continue } stepInfoPtr.ID = compositeStepIDStr if workflowStep.Title != nil && *workflowStep.Title != "" { stepInfoPtr.Title = *workflowStep.Title } else { stepInfoPtr.Title = compositeStepIDStr } stepIDData, err := models.CreateStepIDDataFromString(compositeStepIDStr, defaultStepLibSource) if err != nil { registerStepRunResults(stepmanModels.StepModel{}, stepInfoPtr, stepIdxPtr, "", models.StepRunStatusCodeFailed, 1, err, isLastStep, true) continue } stepInfoPtr.ID = stepIDData.IDorURI if stepInfoPtr.Title == "" { stepInfoPtr.Title = stepIDData.IDorURI } stepInfoPtr.Version = stepIDData.Version stepInfoPtr.StepLib = stepIDData.SteplibSource // // Activating the step stepDir := configs.BitriseWorkStepsDirPath stepYMLPth := filepath.Join(configs.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 { registerStepRunResults(stepmanModels.StepModel{}, stepInfoPtr, stepIdxPtr, "", models.StepRunStatusCodeFailed, 1, err, isLastStep, true) continue } log.Debugln("stepAbsLocalPth:", stepAbsLocalPth, "|stepDir:", stepDir) if err := cmdex.CopyDir(stepAbsLocalPth, stepDir, true); err != nil { registerStepRunResults(stepmanModels.StepModel{}, stepInfoPtr, stepIdxPtr, "", models.StepRunStatusCodeFailed, 1, err, isLastStep, true) continue } if err := cmdex.CopyFile(filepath.Join(stepAbsLocalPth, "step.yml"), stepYMLPth); err != nil { registerStepRunResults(stepmanModels.StepModel{}, stepInfoPtr, stepIdxPtr, "", models.StepRunStatusCodeFailed, 1, err, isLastStep, true) 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 := cmdex.GitCloneTagOrBranch(stepIDData.IDorURI, stepDir, stepIDData.Version); err != nil { if strings.HasPrefix(stepIDData.IDorURI, "git@") { fmt.Println(colorstring.Yellow(`Note: if the step's repository is an open source one,`)) fmt.Println(colorstring.Yellow(`you should probably use a "https://..." git clone URL,`)) fmt.Println(colorstring.Yellow(`instead of the "git@..." git clone URL which usually requires authentication`)) fmt.Println(colorstring.Yellow(`even if the repository is open source!`)) } registerStepRunResults(stepmanModels.StepModel{}, stepInfoPtr, stepIdxPtr, "", models.StepRunStatusCodeFailed, 1, err, isLastStep, true) continue } if err := cmdex.CopyFile(filepath.Join(stepDir, "step.yml"), stepYMLPth); err != nil { registerStepRunResults(stepmanModels.StepModel{}, stepInfoPtr, stepIdxPtr, "", models.StepRunStatusCodeFailed, 1, err, isLastStep, true) continue } } else if stepIDData.SteplibSource == "_" { log.Debugf("[BITRISE_CLI] - Steplib independent step, with direct git uri: (uri:%s) (tag-or-branch:%s)", stepIDData.IDorURI, stepIDData.Version) // Steplib independent steps are completly defined in workflow stepYMLPth = "" if err := workflowStep.FillMissingDefaults(); err != nil { registerStepRunResults(stepmanModels.StepModel{}, stepInfoPtr, stepIdxPtr, "", models.StepRunStatusCodeFailed, 1, err, isLastStep, true) continue } if err := cmdex.GitCloneTagOrBranch(stepIDData.IDorURI, stepDir, stepIDData.Version); err != nil { registerStepRunResults(stepmanModels.StepModel{}, stepInfoPtr, stepIdxPtr, "", models.StepRunStatusCodeFailed, 1, err, isLastStep, true) 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 := tools.StepmanSetup(stepIDData.SteplibSource); err != nil { registerStepRunResults(stepmanModels.StepModel{}, stepInfoPtr, stepIdxPtr, "", models.StepRunStatusCodeFailed, 1, err, isLastStep, true) continue } isLatestVersionOfStep := (stepIDData.Version == "") if isLatestVersionOfStep && !buildRunResults.IsStepLibUpdated(stepIDData.SteplibSource) { log.Infof("Step uses latest version -- Updating StepLib ...") if err := tools.StepmanUpdate(stepIDData.SteplibSource); err != nil { log.Warnf("Step uses latest version, but failed to update StepLib, err: %s", err) } else { buildRunResults.StepmanUpdates[stepIDData.SteplibSource]++ } } outStr, err := tools.StepmanJSONStepLibStepInfo(stepIDData.SteplibSource, stepIDData.IDorURI, stepIDData.Version) if err != nil { if buildRunResults.IsStepLibUpdated(stepIDData.SteplibSource) { registerStepRunResults(stepmanModels.StepModel{}, stepInfoPtr, stepIdxPtr, "", models.StepRunStatusCodeFailed, 1, fmt.Errorf("StepmanJSONStepLibStepInfo failed, err: %s", err), isLastStep, true) continue } // May StepLib should be updated log.Infof("Step info not found in StepLib (%s) -- Updating ...", stepIDData.SteplibSource) if err := tools.StepmanUpdate(stepIDData.SteplibSource); err != nil { registerStepRunResults(stepmanModels.StepModel{}, stepInfoPtr, stepIdxPtr, "", models.StepRunStatusCodeFailed, 1, err, isLastStep, true) continue } buildRunResults.StepmanUpdates[stepIDData.SteplibSource]++ outStr, err = tools.StepmanJSONStepLibStepInfo(stepIDData.SteplibSource, stepIDData.IDorURI, stepIDData.Version) if err != nil { registerStepRunResults(stepmanModels.StepModel{}, stepInfoPtr, stepIdxPtr, "", models.StepRunStatusCodeFailed, 1, fmt.Errorf("StepmanJSONStepLibStepInfo failed, err: %s", err), isLastStep, true) continue } } stepInfo, err := stepmanModels.StepInfoModel{}.CreateFromJSON(outStr) if err != nil { registerStepRunResults(stepmanModels.StepModel{}, stepInfoPtr, stepIdxPtr, "", models.StepRunStatusCodeFailed, 1, fmt.Errorf("CreateFromJSON failed, err: %s", err), isLastStep, true) continue } stepInfoPtr.ID = stepInfo.ID if stepInfoPtr.Title == "" { stepInfoPtr.Title = stepInfo.ID } stepInfoPtr.Version = stepInfo.Version stepInfoPtr.Latest = stepInfo.Latest stepInfoPtr.GlobalInfo = stepInfo.GlobalInfo if err := tools.StepmanActivate(stepIDData.SteplibSource, stepIDData.IDorURI, stepIDData.Version, stepDir, stepYMLPth); err != nil { registerStepRunResults(stepmanModels.StepModel{}, stepInfoPtr, stepIdxPtr, "", models.StepRunStatusCodeFailed, 1, err, isLastStep, true) continue } else { log.Debugf("[BITRISE_CLI] - Step activated: (ID:%s) (version:%s)", stepIDData.IDorURI, stepIDData.Version) } } else { registerStepRunResults(stepmanModels.StepModel{}, stepInfoPtr, stepIdxPtr, "", models.StepRunStatusCodeFailed, 1, fmt.Errorf("Invalid stepIDData: No SteplibSource or LocalPath defined (%v)", stepIDData), isLastStep, true) continue } // Fill step info with default step info, if exist mergedStep := workflowStep if stepYMLPth != "" { specStep, err := bitrise.ReadSpecStep(stepYMLPth) log.Debugf("Spec read from YML: %#v\n", specStep) if err != nil { registerStepRunResults(stepmanModels.StepModel{}, stepInfoPtr, stepIdxPtr, "", models.StepRunStatusCodeFailed, 1, err, isLastStep, true) continue } mergedStep, err = models.MergeStepWith(specStep, workflowStep) if err != nil { registerStepRunResults(stepmanModels.StepModel{}, stepInfoPtr, stepIdxPtr, "", models.StepRunStatusCodeFailed, 1, err, isLastStep, true) continue } } if mergedStep.SupportURL != nil { stepInfoPtr.SupportURL = *mergedStep.SupportURL } if mergedStep.SourceCodeURL != nil { stepInfoPtr.SourceCodeURL = *mergedStep.SourceCodeURL } // // Run step bitrise.PrintRunningStepHeader(stepInfoPtr, mergedStep, idx) if mergedStep.RunIf != nil && *mergedStep.RunIf != "" { outStr, err := tools.EnvmanJSONPrint(configs.InputEnvstorePath) if err != nil { registerStepRunResults(mergedStep, stepInfoPtr, stepIdxPtr, *mergedStep.RunIf, models.StepRunStatusCodeFailed, 1, fmt.Errorf("EnvmanJSONPrint failed, err: %s", err), isLastStep, false) continue } envList, err := envmanModels.NewEnvJSONList(outStr) if err != nil { registerStepRunResults(mergedStep, stepInfoPtr, stepIdxPtr, *mergedStep.RunIf, models.StepRunStatusCodeFailed, 1, fmt.Errorf("CreateFromJSON failed, err: %s", err), isLastStep, false) continue } isRun, err := bitrise.EvaluateTemplateToBool(*mergedStep.RunIf, configs.IsCIMode, configs.IsPullRequestMode, buildRunResults, envList) if err != nil { registerStepRunResults(mergedStep, stepInfoPtr, stepIdxPtr, *mergedStep.RunIf, models.StepRunStatusCodeFailed, 1, err, isLastStep, false) continue } if !isRun { registerStepRunResults(mergedStep, stepInfoPtr, stepIdxPtr, *mergedStep.RunIf, models.StepRunStatusCodeSkippedWithRunIf, 0, err, isLastStep, false) continue } } isAlwaysRun := stepmanModels.DefaultIsAlwaysRun if mergedStep.IsAlwaysRun != nil { isAlwaysRun = *mergedStep.IsAlwaysRun } else { log.Warn("Step (%s) mergedStep.IsAlwaysRun is nil, should not!", stepIDData.IDorURI) } if buildRunResults.IsBuildFailed() && !isAlwaysRun { registerStepRunResults(mergedStep, stepInfoPtr, stepIdxPtr, *mergedStep.RunIf, models.StepRunStatusCodeSkipped, 0, err, isLastStep, false) } else { exit, outEnvironments, err := runStep(mergedStep, stepIDData, stepDir, *environments, buildRunResults) *environments = append(*environments, outEnvironments...) if err != nil { if *mergedStep.IsSkippable { registerStepRunResults(mergedStep, stepInfoPtr, stepIdxPtr, *mergedStep.RunIf, models.StepRunStatusCodeFailedSkippable, exit, err, isLastStep, false) } else { registerStepRunResults(mergedStep, stepInfoPtr, stepIdxPtr, *mergedStep.RunIf, models.StepRunStatusCodeFailed, exit, err, isLastStep, false) } } else { registerStepRunResults(mergedStep, stepInfoPtr, stepIdxPtr, *mergedStep.RunIf, models.StepRunStatusCodeSuccess, 0, nil, isLastStep, false) } } } return buildRunResults }
func stepInfo(c *cli.Context) error { // Input validation format := c.String(FormatKey) collectionURI := c.String(CollectionKey) YMLPath := c.String(StepYMLKey) isShort := c.Bool(ShortKey) id := c.String(IDKey) version := c.String(VersionKey) if format == "" { format = OutputFormatRaw } else if !(format == OutputFormatRaw || format == OutputFormatJSON) { return fmt.Errorf("Invalid output format: %s", format) } if YMLPath == "" && collectionURI == "" { return fmt.Errorf("Missing required input: no StepLib, nor step.yml path defined as step info source") } if YMLPath != "" { // // Local step info step, err := stepman.ParseStepYml(YMLPath, false) if err != nil { return fmt.Errorf("Failed to parse step.yml (path:%s), err: %s", YMLPath, err) } inputs, err := getEnvInfos(step.Inputs) if err != nil { return fmt.Errorf("Failed to get step (path:%s) input infos, err: %s", YMLPath, err) } outputs, err := getEnvInfos(step.Outputs) if err != nil { return fmt.Errorf("Failed to get step (path:%s) output infos, err: %s", YMLPath, err) } stepInfo := models.StepInfoModel{ StepLib: YMLPath, Description: *step.Description, Source: *step.SourceCodeURL, Inputs: inputs, Outputs: outputs, } if err := printStepInfo(stepInfo, format, isShort, true); err != nil { return fmt.Errorf("Failed to print step info, err: %s", err) } } else { // // StepLib step info stepVersion, err := ReadStepInfo(collectionURI, id, version, true, format != OutputFormatRaw) if err != nil { return fmt.Errorf("Failed to read Step information, error: %s", err) } if version == "" { version = stepVersion.Version } step := stepVersion.Step inputs, err := getEnvInfos(step.Inputs) if err != nil { return fmt.Errorf("Failed to get step (id:%s) input infos, err: %s", id, err) } outputs, err := getEnvInfos(step.Outputs) if err != nil { return fmt.Errorf("Failed to get step (id:%s) output infos, err: %s", id, err) } stepInfo := models.StepInfoModel{ ID: id, Version: version, Latest: stepVersion.LatestAvailableVersion, Description: *step.Description, StepLib: collectionURI, Source: *step.SourceCodeURL, Inputs: inputs, Outputs: outputs, } route, found := stepman.ReadRoute(collectionURI) if !found { return fmt.Errorf("No route found for collection: %s", collectionURI) } globalStepInfoPth := stepman.GetStepGlobalInfoPath(route, id) if globalStepInfoPth != "" { globalInfo, found, err := stepman.ParseGlobalStepInfoYML(globalStepInfoPth) if err != nil { return fmt.Errorf("Failed to get step (path:%s) output infos, err: %s", globalStepInfoPth, err) } if found { stepInfo.GlobalInfo = globalInfo } } if err := printStepInfo(stepInfo, format, isShort, false); err != nil { return fmt.Errorf("Failed to print step info, err: %s", err) } } return nil }