7e0eae99a6
* Modify error API to not include exception, but to test on type * reformat * address renames and documentations from the review * test is errors * document
146 lines
3.3 KiB
Go
146 lines
3.3 KiB
Go
package scaleset
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
// Header names for request IDs
|
|
const (
|
|
headerActionsActivityID = "ActivityId"
|
|
headerGitHubRequestID = "X-GitHub-Request-Id"
|
|
)
|
|
|
|
type GitHubAPIError struct {
|
|
StatusCode int
|
|
RequestID string
|
|
Err error
|
|
}
|
|
|
|
func (e *GitHubAPIError) Error() string {
|
|
return fmt.Sprintf("github api error: StatusCode %d, RequestID %q: %v", e.StatusCode, e.RequestID, e.Err)
|
|
}
|
|
|
|
func (e *GitHubAPIError) Unwrap() error {
|
|
return e.Err
|
|
}
|
|
|
|
type ActionsError struct {
|
|
ActivityID string
|
|
StatusCode int
|
|
Err error
|
|
}
|
|
|
|
func (e *ActionsError) Error() string {
|
|
return fmt.Sprintf("actions error: StatusCode %d, ActivityId %q: %v", e.StatusCode, e.ActivityID, e.Err)
|
|
}
|
|
|
|
func (e *ActionsError) Unwrap() error {
|
|
return e.Err
|
|
}
|
|
|
|
func (e *ActionsError) IsAgentNotFound() bool {
|
|
return e.isException("AgentNotFoundException")
|
|
}
|
|
|
|
func (e *ActionsError) IsJobStillRunning() bool {
|
|
return e.isException("JobStillRunningException")
|
|
}
|
|
|
|
func (e *ActionsError) IsMessageQueueTokenExpired() bool {
|
|
if e == nil {
|
|
return false
|
|
}
|
|
var err *messageQueueTokenExpiredError
|
|
return errors.As(e.Err, &err)
|
|
}
|
|
|
|
func (e *ActionsError) IsAgentExists() bool {
|
|
return e.isException("AgentExistsException")
|
|
}
|
|
|
|
func (e *ActionsError) isException(target string) bool {
|
|
if e == nil {
|
|
return false
|
|
}
|
|
if ex, ok := e.Err.(*actionsExceptionError); ok {
|
|
return strings.Contains(ex.ExceptionName, target)
|
|
}
|
|
return false
|
|
}
|
|
|
|
type actionsExceptionError struct {
|
|
ExceptionName string `json:"typeName,omitempty"`
|
|
Message string `json:"message,omitempty"`
|
|
}
|
|
|
|
func (e *actionsExceptionError) Error() string {
|
|
return fmt.Sprintf("%s: %s", e.ExceptionName, e.Message)
|
|
}
|
|
|
|
func ParseActionsErrorFromResponse(response *http.Response) error {
|
|
if response.ContentLength == 0 {
|
|
return &ActionsError{
|
|
ActivityID: response.Header.Get(headerActionsActivityID),
|
|
StatusCode: response.StatusCode,
|
|
Err: errors.New("unknown exception"),
|
|
}
|
|
}
|
|
|
|
body, err := io.ReadAll(response.Body)
|
|
if err != nil {
|
|
return &ActionsError{
|
|
ActivityID: response.Header.Get(headerActionsActivityID),
|
|
StatusCode: response.StatusCode,
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
body = trimByteOrderMark(body)
|
|
contentType := response.Header.Get("Content-Type")
|
|
if len(contentType) > 0 && strings.Contains(contentType, "text/plain") {
|
|
message := string(body)
|
|
return &ActionsError{
|
|
ActivityID: response.Header.Get(headerActionsActivityID),
|
|
StatusCode: response.StatusCode,
|
|
Err: errors.New(message),
|
|
}
|
|
}
|
|
|
|
var exception actionsExceptionError
|
|
if err := json.Unmarshal(body, &exception); err != nil {
|
|
return &ActionsError{
|
|
ActivityID: response.Header.Get(headerActionsActivityID),
|
|
StatusCode: response.StatusCode,
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
return &ActionsError{
|
|
ActivityID: response.Header.Get(headerActionsActivityID),
|
|
StatusCode: response.StatusCode,
|
|
Err: &exception,
|
|
}
|
|
}
|
|
|
|
type messageQueueTokenExpiredError struct {
|
|
message string
|
|
}
|
|
|
|
func (e *messageQueueTokenExpiredError) Error() string {
|
|
return fmt.Sprintf("message queue token expired: %s", e.message)
|
|
}
|
|
|
|
// NewMessageQueueTokenExpiredError creates a new MessageQueueTokenExpiredError.
|
|
//
|
|
// This function is mostly used by tests.
|
|
func NewMessageQueueTokenExpiredError(message string) error {
|
|
return &messageQueueTokenExpiredError{
|
|
message: message,
|
|
}
|
|
}
|