diff --git a/cmd/request/request.go b/cmd/request/request.go index dc317639..385b640f 100644 --- a/cmd/request/request.go +++ b/cmd/request/request.go @@ -42,6 +42,7 @@ The command offers a cURL-like experience to interact with the Ping platform ser cmd.Flags().AddFlag(options.RequestHTTPMethodOption.Flag) cmd.Flags().AddFlag(options.RequestServiceOption.Flag) cmd.Flags().AddFlag(options.RequestDataOption.Flag) + cmd.Flags().AddFlag(options.RequestFailOption.Flag) return cmd } diff --git a/internal/commands/request/request_internal.go b/internal/commands/request/request_internal.go index b39662c5..f36b2a2c 100644 --- a/internal/commands/request/request_internal.go +++ b/internal/commands/request/request_internal.go @@ -57,6 +57,11 @@ func runInternalPingOneRequest(uri string) (err error) { return err } + failOption, err := profiles.GetOptionValue(options.RequestFailOption) + if err != nil { + return err + } + apiURL := fmt.Sprintf("https://api.pingone.%s/v1/%s", topLevelDomain, uri) httpMethod, err := profiles.GetOptionValue(options.RequestHTTPMethodOption) @@ -102,9 +107,10 @@ func runInternalPingOneRequest(uri string) (err error) { } if res.StatusCode < 200 || res.StatusCode >= 300 { - // Note we don't os.Exit(1) here because pingcli has executed - // without issue, despite a failed response to the custom request output.UserError("Failed Custom Request", fields) + if failOption == "true" { + os.Exit(1) + } } else { output.Success("Custom request successful", fields) } diff --git a/internal/commands/request/request_internal_test.go b/internal/commands/request/request_internal_test.go index b7e26cab..476600dc 100644 --- a/internal/commands/request/request_internal_test.go +++ b/internal/commands/request/request_internal_test.go @@ -3,6 +3,7 @@ package request_internal import ( "fmt" "os" + "os/exec" "testing" "github.com/pingidentity/pingcli/internal/configuration/options" @@ -21,6 +22,31 @@ func Test_RunInternalRequest(t *testing.T) { testutils.CheckExpectedError(t, err, nil) } +// Test RunInternalRequest function with fail +func Test_RunInternalRequestWithFail(t *testing.T) { + + if os.Getenv("RUN_INTERNAL_FAIL_TEST") == "true" { + testutils_viper.InitVipers(t) + t.Setenv(options.RequestServiceOption.EnvVar, "pingone") + options.RequestFailOption.Flag.Changed = true + err := options.RequestFailOption.Flag.Value.Set("true") + if err != nil { + t.Fatal(err) + } + _ = RunInternalRequest("environments/failTest") + t.Fatal("This should never run due to internal request resulting in os.Exit(1)") + } else { + cmdName := os.Args[0] + cmd := exec.Command(cmdName, "-test.run=Test_RunInternalRequestWithFail") + cmd.Env = append(os.Environ(), "RUN_INTERNAL_FAIL_TEST=true") + err := cmd.Run() + if exitError, ok := err.(*exec.ExitError); ok && !exitError.Success() { + return + } + t.Fatalf("The process did not exit with a non-zero: %s", err) + } +} + // Test RunInternalRequest function with empty service func Test_RunInternalRequest_EmptyService(t *testing.T) { testutils_viper.InitVipers(t) diff --git a/internal/configuration/options/options.go b/internal/configuration/options/options.go index 0cc98e6d..6bef857e 100644 --- a/internal/configuration/options/options.go +++ b/internal/configuration/options/options.go @@ -77,6 +77,7 @@ func Options() []Option { RequestServiceOption, RequestAccessTokenOption, RequestAccessTokenExpiryOption, + RequestFailOption, } } @@ -145,4 +146,5 @@ var ( RequestServiceOption Option RequestAccessTokenOption Option RequestAccessTokenExpiryOption Option + RequestFailOption Option ) diff --git a/internal/configuration/request/request.go b/internal/configuration/request/request.go index 7ff1e795..9b95e30b 100644 --- a/internal/configuration/request/request.go +++ b/internal/configuration/request/request.go @@ -15,7 +15,7 @@ func InitRequestOptions() { initServiceOption() initAccessTokenOption() initAccessTokenExpiryOption() - + initFailOption() } func initDataOption() { @@ -123,3 +123,25 @@ func initAccessTokenExpiryOption() { ViperKey: "request.accessTokenExpiry", } } + +func initFailOption() { + cobraParamName := "fail" + cobraValue := new(customtypes.Bool) + defaultValue := customtypes.Bool(false) + + options.RequestFailOption = options.Option{ + CobraParamName: cobraParamName, + CobraParamValue: cobraValue, + DefaultValue: &defaultValue, + Flag: &pflag.Flag{ + Name: cobraParamName, + NoOptDefVal: "true", + Shorthand: "f", + Usage: "Return non-zero exit code when HTTP custom request returns a failure status code.", + Value: cobraValue, + }, + + Type: options.ENUM_BOOL, + ViperKey: "request.fail", + } +}