github.com/jaylevin/jenkins-library@v1.230.4/cmd/isChangeInDevelopment.go (about) 1 package cmd 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/SAP/jenkins-library/pkg/command" 8 "github.com/SAP/jenkins-library/pkg/log" 9 "github.com/SAP/jenkins-library/pkg/telemetry" 10 ) 11 12 type isChangeInDevelopmentUtils interface { 13 command.ExecRunner 14 GetExitCode() int 15 16 // Add more methods here, or embed additional interfaces, or remove/replace as required. 17 // The isChangeInDevelopmentUtils interface should be descriptive of your runtime dependencies, 18 // i.e. include everything you need to be able to mock in tests. 19 // Unit tests shall be executable in parallel (not depend on global state), and don't (re-)test dependencies. 20 } 21 22 type isChangeInDevelopmentUtilsBundle struct { 23 *command.Command 24 25 // Embed more structs as necessary to implement methods or interfaces you add to isChangeInDevelopmentUtils. 26 // Structs embedded in this way must each have a unique set of methods attached. 27 // If there is no struct which implements the method you need, attach the method to 28 // isChangeInDevelopmentUtilsBundle and forward to the implementation of the dependency. 29 } 30 31 func newIsChangeInDevelopmentUtils() isChangeInDevelopmentUtils { 32 utils := isChangeInDevelopmentUtilsBundle{ 33 Command: &command.Command{}, 34 } 35 // Reroute command output to logging framework 36 utils.Stdout(log.Writer()) 37 utils.Stderr(log.Writer()) 38 return &utils 39 } 40 41 func isChangeInDevelopment(config isChangeInDevelopmentOptions, 42 telemetryData *telemetry.CustomData, 43 commonPipelineEnvironment *isChangeInDevelopmentCommonPipelineEnvironment) { 44 // Utils can be used wherever the command.ExecRunner interface is expected. 45 // It can also be used for example as a mavenExecRunner. 46 utils := newIsChangeInDevelopmentUtils() 47 48 // For HTTP calls import piperhttp "github.com/SAP/jenkins-library/pkg/http" 49 // and use a &piperhttp.Client{} in a custom system 50 // Example: step checkmarxExecuteScan.go 51 52 // Error situations should be bubbled up until they reach the line below which will then stop execution 53 // through the log.Entry().Fatal() call leading to an os.Exit(1) in the end. 54 err := runIsChangeInDevelopment(&config, telemetryData, utils, commonPipelineEnvironment) 55 if err != nil { 56 log.Entry().WithError(err).Fatal("step execution failed") 57 } 58 } 59 60 func runIsChangeInDevelopment(config *isChangeInDevelopmentOptions, 61 telemetryData *telemetry.CustomData, 62 utils isChangeInDevelopmentUtils, 63 commonPipelineEnvironment *isChangeInDevelopmentCommonPipelineEnvironment) error { 64 65 log.Entry().Infof("Checking change status for change '%s'", config.ChangeDocumentID) 66 67 isInDevelopment, err := perform(config, utils) 68 69 if err != nil { 70 return err 71 } 72 73 commonPipelineEnvironment.custom.isChangeInDevelopment = isInDevelopment 74 75 if isInDevelopment { 76 log.Entry().Infof("Change '%s' is in status 'in development'.", config.ChangeDocumentID) 77 return nil 78 } 79 if config.FailIfStatusIsNotInDevelopment { 80 return fmt.Errorf("change '%s' is not in status 'in development'", config.ChangeDocumentID) 81 } 82 log.Entry().Warningf("Change '%s' is not in status 'in development'. Failing the step has been explicitly disabled.", config.ChangeDocumentID) 83 return nil 84 } 85 86 func perform(config *isChangeInDevelopmentOptions, utils isChangeInDevelopmentUtils) (bool, error) { 87 88 if len(config.CmClientOpts) > 0 { 89 utils.AppendEnv([]string{fmt.Sprintf("CMCLIENT_OPTS=%s", strings.Join(config.CmClientOpts, " "))}) 90 } 91 92 err := utils.RunExecutable("cmclient", 93 "--endpoint", config.Endpoint, 94 "--user", config.Username, 95 "--password", config.Password, 96 "is-change-in-development", 97 "--change-id", config.ChangeDocumentID, 98 "--return-code") 99 100 exitCode := utils.GetExitCode() 101 102 hint := "check log for details" 103 if err != nil { 104 hint = err.Error() 105 } 106 107 if exitCode == 0 { 108 return true, nil 109 } else if exitCode == 3 { 110 return false, nil 111 } else if exitCode == 2 { 112 hint = "invalid credentials" 113 } 114 115 return false, fmt.Errorf("cannot retrieve change status: %s", hint) 116 }