// GuideTextForStart ... func GuideTextForStart() string { guide := colorstring.Blue("Fork the StepLib repository") + " you want to share your Step in.\n" + ` You can find the main ("official") StepLib repository at: ` + colorstring.Green("https://github.com/bitrise-io/bitrise-steplib") + ` ` + colorstring.Yellow("Note") + `: You can use any StepLib repository you like, the StepLib system is decentralized, you don't have to work with the main StepLib repository if you don't want to. Feel free to maintain and use your own (or your team's) Step Library. ` return guide }
// GuideTextForAudit ... func GuideTextForAudit(toolMode bool) string { name := "stepman" if toolMode { name = "bitrise" } guide := "You can call " + colorstring.Blue("'"+name+" audit'") + `, to perform a complete health-check on your StepLib before submitting your Pull Request. This can help you catch issues which might prevent your Step to be accepted. ` return guide }
func triggerCheck(c *cli.Context) { format := c.String(OuputFormatKey) if format == "" { format = configs.OutputFormatRaw } else if !(format == configs.OutputFormatRaw || format == configs.OutputFormatJSON) { registerFatal(fmt.Sprintf("Invalid format: %s", format), configs.OutputFormatJSON) } // Config validation bitriseConfig, err := CreateBitriseConfigFromCLIParams(c) if err != nil { registerFatal(fmt.Sprintf("Failed to create config, err: %s", err), format) } // Trigger filter validation triggerPattern := "" if len(c.Args()) < 1 { registerFatal("No trigger pattern specified", format) } else { triggerPattern = c.Args()[0] } if triggerPattern == "" { registerFatal("No trigger pattern specified", format) } workflowToRunID, err := GetWorkflowIDByPattern(bitriseConfig, triggerPattern) if err != nil { registerFatal(err.Error(), format) } switch format { case configs.OutputFormatRaw: fmt.Printf("%s -> %s\n", triggerPattern, colorstring.Blue(workflowToRunID)) break case configs.OutputFormatJSON: triggerModel := map[string]string{ "pattern": triggerPattern, "workflow": workflowToRunID, } bytes, err := json.Marshal(triggerModel) if err != nil { registerFatal(fmt.Sprintf("Failed to parse trigger model, err: %s", err), format) } fmt.Println(string(bytes)) break default: registerFatal(fmt.Sprintf("Invalid format: %s", format), configs.OutputFormatJSON) } }
func printRawStepInfo(stepInfo models.StepInfoModel, isShort, isLocal bool) { if isLocal { fmt.Println(colorstring.Bluef("Local step info, yml path (%s):", stepInfo.StepLib)) } else { fmt.Println(colorstring.Bluef("Step info in StepLib (%s):", stepInfo.StepLib)) } if stepInfo.GlobalInfo.RemovalDate != "" { fmt.Println("") fmt.Println(colorstring.Red("This step is deprecated!")) fmt.Printf("%s %s\n", colorstring.Red("removal date:"), stepInfo.GlobalInfo.RemovalDate) if stepInfo.GlobalInfo.DeprecateNotes != "" { fmt.Printf("%s\n%s\n", colorstring.Red("deprecate notes:"), stepInfo.GlobalInfo.DeprecateNotes) } } if stepInfo.ID != "" { fmt.Printf("%s: %s\n", colorstring.Blue("ID"), stepInfo.ID) } if stepInfo.Version != "" { fmt.Printf("%s: %s\n", colorstring.Blue("version"), stepInfo.Version) } if stepInfo.Latest != "" { fmt.Printf("%s: %s\n", colorstring.Blue("latest"), stepInfo.Latest) } if !isShort { fmt.Printf("%s: %s\n", colorstring.Blue("source"), stepInfo.Source) fmt.Printf("%s:\n", colorstring.Blue("description")) fmt.Printf("%s\n", stepInfo.Description) fmt.Println() if len(stepInfo.Inputs) > 0 { fmt.Printf("%s:\n", colorstring.Blue("inputs")) for _, input := range stepInfo.Inputs { printRawEnvInfo(input) } } if len(stepInfo.Outputs) > 0 { if len(stepInfo.Inputs) > 0 { fmt.Println() } fmt.Printf("%s:\n", colorstring.Blue("outputs")) for _, output := range stepInfo.Outputs { printRawEnvInfo(output) } } } fmt.Println() fmt.Println() }
func printRawValidation(validation ValidationModel) error { validConfig := true if validation.Config != nil { fmt.Println(colorstring.Blue("Config validation result:")) configValidation := *validation.Config if configValidation.IsValid { fmt.Printf("is valid: %s\n", colorstring.Greenf("%v", configValidation.IsValid)) } else { fmt.Printf("is valid: %s\n", colorstring.Redf("%v", configValidation.IsValid)) fmt.Printf("error: %s\n", colorstring.Red(configValidation.Error)) validConfig = false } fmt.Println() } validSecrets := true if validation.Secrets != nil { fmt.Println(colorstring.Blue("Secret validation result:")) secretValidation := *validation.Secrets if secretValidation.IsValid { fmt.Printf("is valid: %s\n", colorstring.Greenf("%v", secretValidation.IsValid)) } else { fmt.Printf("is valid: %s\n", colorstring.Redf("%v", secretValidation.IsValid)) fmt.Printf("error: %s\n", colorstring.Red(secretValidation.Error)) validSecrets = false } } if !validConfig && !validSecrets { return errors.New("Config and secrets are invalid") } else if !validConfig { return errors.New("Config is invalid") } else if !validSecrets { return errors.New("Secret is invalid") } return nil }
// GuideTextForShareFinish ... func GuideTextForShareFinish(toolMode bool) string { name := "stepman" if toolMode { name = "bitrise" } guide := `Almost done! You should review your Step's step.yml file (the one added to the local StepLib), and once you're happy with it call: ` + colorstring.Blue("'"+name+" share finish'") + ` This will commit & push the step.yml ` + colorstring.Yellow("into your forked StepLib repository") + `. ` return guide }
// GuideTextForShareStart ... func GuideTextForShareStart(toolMode bool) string { name := "stepman" if toolMode { name = "bitrise" } guide := "Call " + colorstring.Blue("'"+name+" share start -c STEPLIB_REPO_FORK_GIT_URL'") + ", with the " + colorstring.Yellow("git clone url") + " of " + colorstring.Yellow("your forked StepLib repository") + ".\n" + ` This will prepare your forked StepLib locally for sharing. For example, if you want to share your Step in the main StepLib repository you should call: ` + colorstring.Green(""+name+" share start -c https://github.com/[your-username]/bitrise-steplib.git") + ` ` return guide }
// GuideTextForShareCreate ... func GuideTextForShareCreate(toolMode bool) string { name := "stepman" if toolMode { name = "bitrise" } guide := "Next, call " + colorstring.Blue("'"+name+" share create --tag STEP_VERSION_TAG --git STEP_GIT_URI --stepid STEP_ID'") + `, to add your Step to your forked StepLib repository (locally). This will copy the required step.yml file from your Step's repository. This is all what's required to add your step (or a new version) to a StepLib. ` + colorstring.Yellow("Important") + `: You have to add the (version) tag to your Step's repository before you would call this! You can do that at: https://github.com/[your-username]/[step-repository]/tags An example call: ` + colorstring.Green(""+name+" share create --tag 1.0.0 --git https://github.com/[your-username]/[step-repository].git --stepid my-awesome-step") + ` ` + colorstring.Yellow("Note") + `: You'll still be able to modify the step.yml in the StepLib after this. ` return guide }
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") var stepStartTime time.Time registerStepRunResults := func(step stepmanModels.StepModel, resultCode, exitCode int, err error, isLastStep bool) { if step.Title == nil { log.Error("Step title is nil, should not happend!") step.Title = pointers.NewStringPtr("ERROR! Step title is nil!") } stepResults := models.StepRunResultsModel{ StepName: *step.Title, Status: resultCode, Idx: buildRunResults.ResultsCount(), RunTime: time.Now().Sub(stepStartTime), Error: err, ExitCode: exitCode, } switch resultCode { case models.StepRunStatusCodeSuccess: buildRunResults.SuccessSteps = append(buildRunResults.SuccessSteps, stepResults) break case models.StepRunStatusCodeFailed: log.Errorf("Step (%s) failed, error: (%v)", *step.Title, err) buildRunResults.FailedSteps = append(buildRunResults.FailedSteps, stepResults) break case models.StepRunStatusCodeFailedSkippable: log.Warnf("Step (%s) failed, but was marked as skippable, error: (%v)", *step.Title, err) 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", *step.Title) buildRunResults.SkippedSteps = append(buildRunResults.SkippedSteps, stepResults) break case models.StepRunStatusCodeSkippedWithRunIf: log.Warn("The step's (" + *step.Title + ") Run-If expression evaluated to false - skipping") log.Info("The Run-If expression was: ", colorstring.Blue(*step.RunIf)) buildRunResults.SkippedSteps = append(buildRunResults.SkippedSteps, stepResults) break default: log.Error("Unkown result code") return } bitrise.PrintStepSummary(stepResults, isLastStep) } registerStepListItemRunResults := func(stepListItem models.StepListItemModel, resultCode, exitCode int, err error, isLastStep bool) { name := "" for key := range stepListItem { name = key break } stepResults := models.StepRunResultsModel{ StepName: name, Status: resultCode, Idx: buildRunResults.ResultsCount(), RunTime: time.Now().Sub(stepStartTime), Error: err, ExitCode: exitCode, } switch resultCode { case models.StepRunStatusCodeSuccess: buildRunResults.SuccessSteps = append(buildRunResults.SuccessSteps, stepResults) break case models.StepRunStatusCodeFailed: log.Errorf("Step (%s) failed, error: (%v)", name, err) buildRunResults.FailedSteps = append(buildRunResults.FailedSteps, stepResults) break case models.StepRunStatusCodeFailedSkippable: log.Warnf("Step (%s) failed, but was marked as skippable, error: (%v)", name, err) 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", name) buildRunResults.SkippedSteps = append(buildRunResults.SkippedSteps, stepResults) break case models.StepRunStatusCodeSkippedWithRunIf: log.Warn("The step's (" + name + ") Run-If expression evaluated to false - skipping") buildRunResults.SkippedSteps = append(buildRunResults.SkippedSteps, stepResults) break default: log.Error("Unkown result code") return } bitrise.PrintStepSummary(stepResults, isLastStep) } for idx, stepListItm := range workflow.Steps { stepStartTime = time.Now() isLastStep := isLastWorkflow && (idx == len(workflow.Steps)-1) if err := bitrise.SetBuildFailedEnv(buildRunResults.IsBuildFailed()); err != nil { log.Error("Failed to set Build Status envs") } compositeStepIDStr, workflowStep, err := models.GetStepIDStepDataPair(stepListItm) if err != nil { registerStepListItemRunResults(stepListItm, models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } stepIDData, err := models.CreateStepIDDataFromString(compositeStepIDStr, defaultStepLibSource) if err != nil { registerStepListItemRunResults(stepListItm, models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } stepVersionForInfoPrint := stepIDData.Version log.Debugf("[BITRISE_CLI] - Running Step: %#v", workflowStep) if err := bitrise.CleanupStepWorkDir(); err != nil { registerStepListItemRunResults(stepListItm, models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } stepDir := bitrise.BitriseWorkStepsDirPath stepYMLPth := path.Join(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, models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } log.Debugln("stepAbsLocalPth:", stepAbsLocalPth, "|stepDir:", stepDir) if err := cmdex.CopyDir(stepAbsLocalPth, stepDir, true); err != nil { registerStepListItemRunResults(stepListItm, models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } if err := cmdex.CopyFile(path.Join(stepAbsLocalPth, "step.yml"), stepYMLPth); err != nil { registerStepListItemRunResults(stepListItm, models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } if len(stepIDData.IDorURI) > 20 { stepVersionForInfoPrint = fmt.Sprintf("path:...%s", stringutil.MaxLastChars(stepIDData.IDorURI, 17)) } else { stepVersionForInfoPrint = fmt.Sprintf("path:%s", stepIDData.IDorURI) } } 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 { registerStepListItemRunResults(stepListItm, models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } if err := cmdex.CopyFile(path.Join(stepDir, "step.yml"), stepYMLPth); err != nil { registerStepListItemRunResults(stepListItm, models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } stepVersionForInfoPrint = fmt.Sprintf("git:...%s", stringutil.MaxLastChars(stepIDData.IDorURI, 10)) if stepIDData.Version != "" { stepVersionForInfoPrint = stepVersionForInfoPrint + "@" + stepIDData.Version } } 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 { registerStepListItemRunResults(stepListItm, models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } if err := cmdex.GitCloneTagOrBranch(stepIDData.IDorURI, stepDir, stepIDData.Version); err != nil { registerStepListItemRunResults(stepListItm, models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } stepVersionForInfoPrint = "_" if stepIDData.Version != "" { if len(stepIDData.Version) > 20 { stepVersionForInfoPrint = stepVersionForInfoPrint + "@..." + stringutil.MaxLastChars(stepIDData.Version, 17) } else { stepVersionForInfoPrint = stepVersionForInfoPrint + "@" + stepIDData.Version } } } 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.StepmanSetup(stepIDData.SteplibSource); err != nil { registerStepListItemRunResults(stepListItm, models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } stepInfo, err := bitrise.StepmanStepInfo(stepIDData.SteplibSource, stepIDData.IDorURI, stepIDData.Version) if err != nil { if buildRunResults.IsStepLibUpdated(stepIDData.SteplibSource) { registerStepListItemRunResults(stepListItm, models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } // May StepLib should be updated log.Info("Step info not found in StepLib (%s) -- Updating ...") if err := bitrise.StepmanUpdate(stepIDData.SteplibSource); err != nil { registerStepListItemRunResults(stepListItm, models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } buildRunResults.StepmanUpdates[stepIDData.SteplibSource]++ stepInfo, err = bitrise.StepmanStepInfo(stepIDData.SteplibSource, stepIDData.IDorURI, stepIDData.Version) if err != nil { registerStepListItemRunResults(stepListItm, models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } } stepVersionForInfoPrint = stepInfo.StepVersion if err := bitrise.StepmanActivate(stepIDData.SteplibSource, stepIDData.IDorURI, stepIDData.Version, stepDir, stepYMLPth); err != nil { registerStepListItemRunResults(stepListItm, models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } else { log.Debugf("[BITRISE_CLI] - Step activated: (ID:%s) (version:%s)", stepIDData.IDorURI, stepIDData.Version) } } else { registerStepListItemRunResults(stepListItm, models.StepRunStatusCodeFailed, 1, fmt.Errorf("Invalid stepIDData: No SteplibSource or LocalPath defined (%v)", stepIDData), isLastStep) continue } mergedStep := workflowStep if stepYMLPth != "" { specStep, err := bitrise.ReadSpecStep(stepYMLPth) log.Debugf("Spec read from YML: %#v\n", specStep) if err != nil { registerStepListItemRunResults(stepListItm, models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } mergedStep, err = models.MergeStepWith(specStep, workflowStep) if err != nil { registerStepListItemRunResults(stepListItm, models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } } // Run step bitrise.PrintRunningStep(*mergedStep.Title, stepVersionForInfoPrint, idx) if mergedStep.RunIf != nil && *mergedStep.RunIf != "" { isRun, err := bitrise.EvaluateStepTemplateToBool(*mergedStep.RunIf, buildRunResults) if err != nil { registerStepRunResults(mergedStep, models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } if !isRun { registerStepRunResults(mergedStep, models.StepRunStatusCodeSkippedWithRunIf, 0, err, isLastStep) continue } } outEnvironments := []envmanModels.EnvironmentItemModel{} 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, models.StepRunStatusCodeSkipped, 0, err, isLastStep) } else { exit, out, err := runStep(mergedStep, stepIDData, stepDir, *environments) outEnvironments = out if err != nil { if *mergedStep.IsSkippable { registerStepRunResults(mergedStep, models.StepRunStatusCodeFailedSkippable, exit, err, isLastStep) } else { registerStepRunResults(mergedStep, models.StepRunStatusCodeFailed, exit, err, isLastStep) } } else { registerStepRunResults(mergedStep, models.StepRunStatusCodeSuccess, 0, nil, isLastStep) *environments = append(*environments, outEnvironments...) } } } return buildRunResults }
// PrintRunningWorkflow ... func PrintRunningWorkflow(title string) { fmt.Println() log.Infoln(colorstring.Blue("Switching to workflow:"), title) fmt.Println() }
func triggerCheck(c *cli.Context) error { warnings := []string{} // // Expand cli.Context prGlobalFlag := c.GlobalBool(PRKey) triggerPattern := c.String(PatternKey) if triggerPattern == "" && len(c.Args()) > 0 { triggerPattern = c.Args()[0] } pushBranch := c.String(PushBranchKey) prSourceBranch := c.String(PRSourceBranchKey) prTargetBranch := c.String(PRTargetBranchKey) bitriseConfigBase64Data := c.String(ConfigBase64Key) bitriseConfigPath := c.String(ConfigKey) deprecatedBitriseConfigPath := c.String(PathKey) if bitriseConfigPath == "" && deprecatedBitriseConfigPath != "" { warnings = append(warnings, "'path' key is deprecated, use 'config' instead!") bitriseConfigPath = deprecatedBitriseConfigPath } inventoryBase64Data := c.String(InventoryBase64Key) inventoryPath := c.String(InventoryKey) jsonParams := c.String(JSONParamsKey) jsonParamsBase64 := c.String(JSONParamsBase64Key) format := c.String(OuputFormatKey) triggerParams, err := parseTriggerCheckParams( triggerPattern, pushBranch, prSourceBranch, prTargetBranch, format, bitriseConfigPath, bitriseConfigBase64Data, inventoryPath, inventoryBase64Data, jsonParams, jsonParamsBase64) if err != nil { registerFatal(fmt.Sprintf("Failed to parse trigger check params, err: %s", err), warnings, triggerParams.Format) } // // Inventory validation inventoryEnvironments, err := CreateInventoryFromCLIParams(triggerParams.InventoryBase64Data, triggerParams.InventoryPath) if err != nil { registerFatal(fmt.Sprintf("Failed to create inventory, err: %s", err), warnings, triggerParams.Format) } // Config validation bitriseConfig, warns, err := CreateBitriseConfigFromCLIParams(triggerParams.BitriseConfigBase64Data, triggerParams.BitriseConfigPath) warnings = append(warnings, warns...) if err != nil { registerFatal(fmt.Sprintf("Failed to create config, err: %s", err), warnings, triggerParams.Format) } // Format validation if triggerParams.Format == "" { triggerParams.Format = output.FormatRaw } else if !(triggerParams.Format == output.FormatRaw || triggerParams.Format == output.FormatJSON) { registerFatal(fmt.Sprintf("Invalid format: %s", triggerParams.Format), warnings, output.FormatJSON) } // Trigger filter validation if triggerParams.TriggerPattern == "" && triggerParams.PushBranch == "" && triggerParams.PRSourceBranch == "" && triggerParams.PRTargetBranch == "" { registerFatal("No trigger pattern nor trigger params specified", warnings, triggerParams.Format) } // // // Main isPRMode, err := isPRMode(prGlobalFlag, inventoryEnvironments) if err != nil { registerFatal(fmt.Sprintf("Failed to check PR mode, err: %s", err), warnings, triggerParams.Format) } workflowToRunID, err := getWorkflowIDByParamsInCompatibleMode(bitriseConfig.TriggerMap, triggerParams, isPRMode) if err != nil { registerFatal(err.Error(), warnings, triggerParams.Format) } switch triggerParams.Format { case output.FormatRaw: fmt.Printf("%s -> %s\n", triggerParams.TriggerPattern, colorstring.Blue(workflowToRunID)) break case output.FormatJSON: triggerModel := map[string]string{ "pattern": triggerParams.TriggerPattern, "workflow": workflowToRunID, } bytes, err := json.Marshal(triggerModel) if err != nil { registerFatal(fmt.Sprintf("Failed to parse trigger model, err: %s", err), warnings, triggerParams.Format) } fmt.Println(string(bytes)) break default: registerFatal(fmt.Sprintf("Invalid format: %s", triggerParams.Format), warnings, output.FormatJSON) } // 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 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 // Holds pointer to current step info, for easy usage in local register step run result methods. // The value is filled with the current running step info. var stepInfoPtr models.StepInfoModel // ------------------------------------------ // In function method - Registration methods, for register step run results. registerStepRunResults := func(runIf string, resultCode, exitCode int, err error, isLastStep bool) { stepInfoCopy := models.StepInfoModel{ ID: stepInfoPtr.ID, Version: stepInfoPtr.Version, Latest: stepInfoPtr.Latest, } stepResults := models.StepRunResultsModel{ StepInfo: stepInfoCopy, Status: resultCode, Idx: buildRunResults.ResultsCount(), RunTime: time.Now().Sub(stepStartTime), Error: err, ExitCode: exitCode, } switch resultCode { case models.StepRunStatusCodeSuccess: buildRunResults.SuccessSteps = append(buildRunResults.SuccessSteps, stepResults) break case models.StepRunStatusCodeFailed: log.Errorf("Step (%s) failed, error: (%v)", stepInfoCopy.ID, err) buildRunResults.FailedSteps = append(buildRunResults.FailedSteps, stepResults) break case models.StepRunStatusCodeFailedSkippable: log.Warnf("Step (%s) failed, but was marked as skippable, error: (%v)", stepInfoCopy.ID, err) 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.ID) buildRunResults.SkippedSteps = append(buildRunResults.SkippedSteps, stepResults) break case models.StepRunStatusCodeSkippedWithRunIf: log.Warn("The step's (" + stepInfoCopy.ID + ") 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.PrintStepSummary(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 = models.StepInfoModel{} // 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("", models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } // // Preparing the step // Get step id & version data compositeStepIDStr, workflowStep, err := models.GetStepIDStepDataPair(stepListItm) stepInfoPtr.ID = compositeStepIDStr if workflowStep.Title != nil && *workflowStep.Title != "" { stepInfoPtr.ID = *workflowStep.Title } if err != nil { registerStepRunResults("", models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } stepIDData, err := models.CreateStepIDDataFromString(compositeStepIDStr, defaultStepLibSource) stepInfoPtr.ID = stepIDData.IDorURI if workflowStep.Title != nil && *workflowStep.Title != "" { stepInfoPtr.ID = *workflowStep.Title } stepInfoPtr.Version = stepIDData.Version if err != nil { registerStepRunResults("", models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } stepDir := bitrise.BitriseWorkStepsDirPath stepYMLPth := path.Join(bitrise.BitriseWorkDirPath, "current_step.yml") // Activating the step 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("", models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } log.Debugln("stepAbsLocalPth:", stepAbsLocalPth, "|stepDir:", stepDir) if err := cmdex.CopyDir(stepAbsLocalPth, stepDir, true); err != nil { registerStepRunResults("", models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } if err := cmdex.CopyFile(path.Join(stepAbsLocalPth, "step.yml"), stepYMLPth); err != nil { registerStepRunResults("", models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } if len(stepIDData.IDorURI) > 20 { stepInfoPtr.Version = fmt.Sprintf("path:...%s", stringutil.MaxLastChars(stepIDData.IDorURI, 17)) } else { stepInfoPtr.Version = fmt.Sprintf("path:%s", stepIDData.IDorURI) } } 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 { registerStepRunResults("", models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } if err := cmdex.CopyFile(path.Join(stepDir, "step.yml"), stepYMLPth); err != nil { registerStepRunResults("", models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } stepInfoPtr.Version = fmt.Sprintf("git:...%s", stringutil.MaxLastChars(stepIDData.IDorURI, 10)) if stepIDData.Version != "" { stepInfoPtr.Version = stepInfoPtr.Version + "@" + stepIDData.Version } } 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("", models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } if err := cmdex.GitCloneTagOrBranch(stepIDData.IDorURI, stepDir, stepIDData.Version); err != nil { registerStepRunResults("", models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } stepInfoPtr.Version = "_" if stepIDData.Version != "" { if len(stepIDData.Version) > 20 { stepInfoPtr.Version = stepInfoPtr.Version + "@..." + stringutil.MaxLastChars(stepIDData.Version, 17) } else { stepInfoPtr.Version = stepInfoPtr.Version + "@" + stepIDData.Version } } } 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.StepmanSetup(stepIDData.SteplibSource); err != nil { registerStepRunResults("", models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } stepInfo, err := bitrise.StepmanStepInfo(stepIDData.SteplibSource, stepIDData.IDorURI, stepIDData.Version) if err != nil { if buildRunResults.IsStepLibUpdated(stepIDData.SteplibSource) { registerStepRunResults("", models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } // May StepLib should be updated log.Info("Step info not found in StepLib (%s) -- Updating ...") if err := bitrise.StepmanUpdate(stepIDData.SteplibSource); err != nil { registerStepRunResults("", models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } buildRunResults.StepmanUpdates[stepIDData.SteplibSource]++ stepInfo, err = bitrise.StepmanStepInfo(stepIDData.SteplibSource, stepIDData.IDorURI, stepIDData.Version) if err != nil { registerStepRunResults("", models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } } stepInfoPtr.Version = stepInfo.Version stepInfoPtr.Latest = stepInfo.Latest if err := bitrise.StepmanActivate(stepIDData.SteplibSource, stepIDData.IDorURI, stepIDData.Version, stepDir, stepYMLPth); err != nil { registerStepRunResults("", models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } else { log.Debugf("[BITRISE_CLI] - Step activated: (ID:%s) (version:%s)", stepIDData.IDorURI, stepIDData.Version) } } else { registerStepRunResults("", models.StepRunStatusCodeFailed, 1, fmt.Errorf("Invalid stepIDData: No SteplibSource or LocalPath defined (%v)", stepIDData), isLastStep) 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("", models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } mergedStep, err = models.MergeStepWith(specStep, workflowStep) if err != nil { registerStepRunResults("", models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } } // Run step bitrise.PrintRunningStep(stepInfoPtr, idx) if mergedStep.RunIf != nil && *mergedStep.RunIf != "" { isRun, err := bitrise.EvaluateStepTemplateToBool(*mergedStep.RunIf, buildRunResults) if err != nil { registerStepRunResults(*mergedStep.RunIf, models.StepRunStatusCodeFailed, 1, err, isLastStep) continue } if !isRun { registerStepRunResults(*mergedStep.RunIf, models.StepRunStatusCodeSkippedWithRunIf, 0, err, isLastStep) continue } } outEnvironments := []envmanModels.EnvironmentItemModel{} 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.RunIf, models.StepRunStatusCodeSkipped, 0, err, isLastStep) } else { exit, out, err := runStep(mergedStep, stepIDData, stepDir, *environments) outEnvironments = out if err != nil { if *mergedStep.IsSkippable { registerStepRunResults(*mergedStep.RunIf, models.StepRunStatusCodeFailedSkippable, exit, err, isLastStep) } else { registerStepRunResults(*mergedStep.RunIf, models.StepRunStatusCodeFailed, exit, err, isLastStep) } } else { registerStepRunResults(*mergedStep.RunIf, models.StepRunStatusCodeSuccess, 0, nil, isLastStep) *environments = append(*environments, outEnvironments...) } } } return buildRunResults }
func collectAndExportProvisioningProfiles(codeSigningSettings common.CodeSigningSettings, absExportOutputDirPath string) (provprofile.ProvisioningProfileFileInfoModels, error) { provProfileFileInfos := []provprofile.ProvisioningProfileFileInfoModel{} fmt.Println() log.Println(colorstring.Green("Searching for required Provisioning Profiles"), "...") fmt.Println() provProfileUUIDLookupMap := map[string]provprofile.ProvisioningProfileFileInfoModel{} for _, aProvProfile := range codeSigningSettings.ProvProfiles { log.Infof(" * "+colorstring.Blue("Searching for required Provisioning Profile")+": %s (UUID: %s)", aProvProfile.Title, aProvProfile.UUID) provProfileFileInfo, err := provprofile.FindProvProfileByUUID(aProvProfile.UUID) if err != nil { return provProfileFileInfos, fmt.Errorf("Failed to find Provisioning Profile: %s", err) } log.Infof(" File found at: %s", provProfileFileInfo.Path) provProfileUUIDLookupMap[provProfileFileInfo.ProvisioningProfileInfo.UUID] = provProfileFileInfo } fmt.Println() log.Println(colorstring.Green("Searching for additinal, Distribution Provisioning Profiles"), "...") fmt.Println() for _, aAppBundleID := range codeSigningSettings.AppIDs { bundleOrAppIDPattern := common.BundleIDFromAppID(aAppBundleID) if bundleOrAppIDPattern == "" { // no bundle ID found in the app id bundleOrAppIDPattern = aAppBundleID } else { // bundle ID found, make it a glob pattern bundleOrAppIDPattern = "*." + bundleOrAppIDPattern } log.Infof(" * "+colorstring.Blue("Searching for Provisioning Profiles with App ID pattern")+": %s", bundleOrAppIDPattern) provProfileFileInfos, err := provprofile.FindProvProfilesByAppID(bundleOrAppIDPattern) if err != nil { return provProfileFileInfos, fmt.Errorf("Error during Provisioning Profile search: %s", err) } if len(provProfileFileInfos) < 1 { log.Warn(" No Provisioning Profile found for this Bundle ID") continue } log.Infof(" Found matching Provisioning Profile count: %d", len(provProfileFileInfos)) for _, aProvProfileFileInfo := range provProfileFileInfos { provProfileUUIDLookupMap[aProvProfileFileInfo.ProvisioningProfileInfo.UUID] = aProvProfileFileInfo } } fmt.Println() log.Println(colorstring.Green("Exporting Provisioning Profiles"), "...") fmt.Println() for _, aProvProfFileInfo := range provProfileUUIDLookupMap { provProfileFileInfos = append(provProfileFileInfos, aProvProfFileInfo) } if err := exportProvisioningProfiles(provProfileFileInfos, absExportOutputDirPath); err != nil { return provProfileFileInfos, fmt.Errorf("Failed to export the Provisioning Profile into the export directory: %s", err) } return provProfileFileInfos, nil }
func share(c *cli.Context) error { toolMode := c.Bool(ToolMode) guide := ` Do you want to ` + colorstring.Green("share ") + colorstring.Yellow("your ") + colorstring.Magenta("own ") + colorstring.Blue("Step") + ` with the world? Awesome!! To get started you can find a template Step repository at: ` + colorstring.Green("https://github.com/bitrise-steplib/step-template") + ` Once you have your Step in a ` + colorstring.Yellow("public git repository") + ` you can share it with others. To share your Step just follow these steps (pun intended ;) : 1. ` + GuideTextForStart() + ` 2. ` + GuideTextForShareStart(toolMode) + ` 3. ` + GuideTextForShareCreate(toolMode) + ` 4. ` + GuideTextForAudit(toolMode) + ` 5. ` + GuideTextForShareFinish(toolMode) + ` 6. ` + GuideTextForFinish() fmt.Println(guide) return nil }
// GuideTextForFinish ... func GuideTextForFinish() string { guide := "Everything is ready! The only remaning thing is to " + colorstring.Blue("create a Pull Request") + `. ` return guide }
func collectAndExportIdentities(codeSigningSettings common.CodeSigningSettings, additionalTeamIDs []string, absExportOutputDirPath string) error { fmt.Println() log.Println("Collecting the required Identities (Certificates) for a base Xcode Archive ...") fmt.Println() identitiesWithKeychainRefs := []osxkeychain.IdentityWithRefModel{} defer osxkeychain.ReleaseIdentityWithRefList(identitiesWithKeychainRefs) for _, aIdentity := range codeSigningSettings.Identities { log.Infof(" * "+colorstring.Blue("Searching for Identity")+": %s", aIdentity.Title) validIdentityRefs, err := osxkeychain.FindAndValidateIdentity(aIdentity.Title, true) if err != nil { return fmt.Errorf("Failed to export, error: %s", err) } if len(validIdentityRefs) < 1 { return errors.New("Identity not found in the keychain, or it was invalid (expired)!") } if len(validIdentityRefs) > 1 { log.Warning(colorstring.Yellow("Multiple matching Identities found in Keychain! Most likely you have duplicated identities in separate Keychains, e.g. one in System.keychain and one in your Login.keychain, or you have revoked versions of the Certificate.")) } else { log.Infoln(" " + colorstring.Green("Found - OK")) } identitiesWithKeychainRefs = append(identitiesWithKeychainRefs, validIdentityRefs...) } fmt.Println() log.Println("Collecting additional identities, for Distribution builds ...") fmt.Println() totalTeamIDs := append(codeSigningSettings.TeamIDs, additionalTeamIDs...) for _, aTeamID := range sliceutil.UniqueStringSlice(totalTeamIDs) { log.Infof(" * "+colorstring.Blue("Searching for Identities with Team ID")+": %s", aTeamID) validIdentityRefs, err := osxkeychain.FindAndValidateIdentity(fmt.Sprintf("(%s)", aTeamID), false) if err != nil { return fmt.Errorf("Failed to export, error: %s", err) } if len(validIdentityRefs) < 1 { log.Infoln("No valid identity found for this Team ID") } log.Infoln(" "+colorstring.Green("Found identities count")+":", len(validIdentityRefs)) identitiesWithKeychainRefs = append(identitiesWithKeychainRefs, validIdentityRefs...) } fmt.Println() log.Println(colorstring.Green("Exporting the Identities") + " (Certificates):") fmt.Println() identityKechainRefs := osxkeychain.CreateEmptyCFTypeRefSlice() for _, aIdentityWithRefItm := range identitiesWithKeychainRefs { fmt.Println(" * "+colorstring.Blue("Identity")+":", aIdentityWithRefItm.Label) identityKechainRefs = append(identityKechainRefs, aIdentityWithRefItm.KeychainRef) } fmt.Println() if isAskForPassword { log.Infoln(colorstring.Blue("Exporting from Keychain")) log.Infoln(colorstring.Yellow(" You'll be asked to provide a Passphrase for the .p12 file!")) } else { log.Infoln(colorstring.Blue("Exporting from Keychain") + ", " + colorstring.Yellow("using empty Passphrase") + " ...") log.Info(" This means that " + colorstring.Yellow("if you want to import the file the passphrase at import should be left empty") + ",") log.Info(" you don't have to type in anything, just leave the passphrase input empty.") } fmt.Println() log.Info(colorstring.Blue("You'll most likely see popups") + " (one for each Identity) from Keychain,") log.Info(colorstring.Yellow(" you will have to accept (Allow)") + " those to be able to export the Identities!") fmt.Println() if err := osxkeychain.ExportFromKeychain(identityKechainRefs, filepath.Join(absExportOutputDirPath, "Identities.p12"), isAskForPassword); err != nil { return fmt.Errorf("Failed to export from Keychain: %s", err) } return nil }
// Info ... func Info(format string, v ...interface{}) { message := fmt.Sprintf(format, v...) fmt.Println(colorstring.Blue(message)) }