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