From 1544d6692687f59e552af9ac30eab4d5dd0db063 Mon Sep 17 00:00:00 2001 From: Liam Nichols Date: Wed, 22 Feb 2023 21:53:26 +0100 Subject: [PATCH 1/2] Validate step outputs and API Token usage **before** running step --- main.go | 5 +++++ outputs.go | 13 ------------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/main.go b/main.go index 36a7cd0..74e3abc 100644 --- a/main.go +++ b/main.go @@ -176,6 +176,11 @@ func validate(conf *Config) error { conf.WebhookURL = "" } + + if conf.APIToken == "" && isRequestingOutput(conf) { + return fmt.Errorf("Outputs can only be set when using the API Token.") + } + return nil } diff --git a/outputs.go b/outputs.go index a47a7f2..b09e920 100644 --- a/outputs.go +++ b/outputs.go @@ -5,7 +5,6 @@ import ( "fmt" "net/http" "os/exec" - "strings" "github.com/bitrise-io/go-utils/log" ) @@ -19,18 +18,6 @@ type SendMessageResponse struct { /// Export the output variables after a successful response func exportOutputs(conf *Config, resp *http.Response) error { - if !isRequestingOutput(conf) { - log.Debugf("Not requesting any outputs") - return nil - } - - isWebhook := strings.TrimSpace(selectValue(string(conf.WebhookURL), string(conf.WebhookURLOnError))) != "" - - // Slack webhooks do not return any useful response information - if isWebhook { - return fmt.Errorf("For output support, do not submit a WebHook URL") - } - var response SendMessageResponse parseError := json.NewDecoder(resp.Body).Decode(&response) if parseError != nil { From 3c6d8f74ca24aff71f4049c587b2697a13447429 Mon Sep 17 00:00:00 2001 From: Liam Nichols Date: Wed, 22 Feb 2023 22:04:50 +0100 Subject: [PATCH 2/2] Check Slack response 'status' when using APIToken --- main.go | 4 ++-- outputs.go | 25 +++++++++++++++++++++---- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/main.go b/main.go index 74e3abc..e0208e4 100644 --- a/main.go +++ b/main.go @@ -159,8 +159,8 @@ func postMessage(conf Config, msg Message) error { return fmt.Errorf("server error: %s, response: %s", resp.Status, body) } - if err := exportOutputs(&conf, resp); err != nil { - return fmt.Errorf("failed to export outputs: %s", err) + if err := processResponse(&conf, resp); err != nil { + return err } return nil diff --git a/outputs.go b/outputs.go index b09e920..e804eca 100644 --- a/outputs.go +++ b/outputs.go @@ -10,13 +10,25 @@ import ( ) // SendMessageResponse is the response from Slack POST +// https://api.slack.com/methods/chat.postMessage#examples type SendMessageResponse struct { + /// The status of the request. When `false`, check the Error for a reason + Ok bool `json:"ok"` + + /// Describes an error that prevented the message from being sent + Error string `json:"error"` + /// The Thread Timestamp Timestamp string `json:"ts"` } -/// Export the output variables after a successful response -func exportOutputs(conf *Config, resp *http.Response) error { +// Check the response status and set any output variables if required +func processResponse(conf *Config, resp *http.Response) error { + // if the request was made using a legacy webhook url, skip processing as there is no response. + if conf.APIToken == "" { + log.Debugf("Skipping response processing because legacy webhook urls do not return any content") + return nil + } var response SendMessageResponse parseError := json.NewDecoder(resp.Body).Decode(&response) @@ -25,6 +37,11 @@ func exportOutputs(conf *Config, resp *http.Response) error { return fmt.Errorf("Failed to parse response: %s", parseError) } + // if slack didn't return 'ok', fail with the error code + if !response.Ok { + return fmt.Errorf("Slack responded with error: %s", response.Error) + } + if string(conf.ThreadTsOutputVariableName) != "" { log.Debugf("Exporting output: %s=%s\n", string(conf.ThreadTsOutputVariableName), response.Timestamp) err := exportEnvVariable(string(conf.ThreadTsOutputVariableName), response.Timestamp) @@ -37,12 +54,12 @@ func exportOutputs(conf *Config, resp *http.Response) error { } -/// Checks if we are requesting an output of anything +// Checks if we are requesting an output of anything func isRequestingOutput(conf *Config) bool { return string(conf.ThreadTsOutputVariableName) != "" } -/// Exports env using envman +// Exports env using envman func exportEnvVariable(variable string, value string) error { c := exec.Command("envman", "add", "--key", variable, "--value", value) err := c.Run()