diff --git a/internal/locale/locales/en-us.yaml b/internal/locale/locales/en-us.yaml index bf6e64f9db..c291b94cf2 100644 --- a/internal/locale/locales/en-us.yaml +++ b/internal/locale/locales/en-us.yaml @@ -1031,6 +1031,8 @@ buildplan_err_cropped: other: "Could not plan build. Platform responded with:\n{{.V0}}\n{{.V1}}" err_buildplanner_head_on_branch_moved: other: The branch you're trying to update has changed remotely. Please run '[ACTIONABLE]state pull[/RESET]'. +err_buildplanner_forbidden: + other: "Operation forbidden: {{.V0}}. Received message: {{.V1}}" transient_solver_tip: other: You may want to retry this command if the failure was related to a resourcing or networking issue. warning_git_project_mismatch: diff --git a/internal/runners/pull/rationalize.go b/internal/runners/pull/rationalize.go index 6bcdea0a11..26cb3dabcd 100644 --- a/internal/runners/pull/rationalize.go +++ b/internal/runners/pull/rationalize.go @@ -24,7 +24,7 @@ func rationalizeError(err *error) { case errors.As(*err, &mergeCommitErr): switch mergeCommitErr.Type { // Custom target does not have a compatible history - case types.NoCommonBaseFoundType: + case types.NoCommonBaseFoundErrorType: *err = errs.WrapUserFacing(*err, locale.Tl("err_pull_no_common_base", "Could not merge. No common base found between local and remote commits", diff --git a/internal/runners/push/rationalize.go b/internal/runners/push/rationalize.go index 90af8e6774..ab8e8b25ca 100644 --- a/internal/runners/push/rationalize.go +++ b/internal/runners/push/rationalize.go @@ -82,7 +82,7 @@ func rationalizeError(err *error) { errs.SetTips(locale.T("err_tip_push_outdated"))) // Custom target does not have a compatible history - case types.NoCommonBaseFoundType: + case types.NoCommonBaseFoundErrorType: *err = errs.WrapUserFacing(*err, locale.T("err_push_target_invalid_history"), errs.SetInput()) diff --git a/pkg/platform/api/buildplanner/request/createproject.go b/pkg/platform/api/buildplanner/request/createproject.go index 8f3c52aca0..92c086e49c 100644 --- a/pkg/platform/api/buildplanner/request/createproject.go +++ b/pkg/platform/api/buildplanner/request/createproject.go @@ -37,11 +37,18 @@ mutation ($organization: String!, $project: String!, $private: Boolean!, $expr: ... on ParseError { __typename message - path + subErrors { + message + buildExprPath + } } ... on ValidationError { __typename message + subErrors { + message + buildExprPath + } } ... on Forbidden { __typename diff --git a/pkg/platform/api/buildplanner/request/mergecommit.go b/pkg/platform/api/buildplanner/request/mergecommit.go index b1868d5f2d..ad34cf57c0 100644 --- a/pkg/platform/api/buildplanner/request/mergecommit.go +++ b/pkg/platform/api/buildplanner/request/mergecommit.go @@ -48,10 +48,18 @@ mutation ($organization: String!, $project: String!, $targetRef: String!, $other ... on ParseError { __typename message + subErrors { + message + buildExprPath + } } ... on ValidationError { __typename message + subErrors { + message + buildExprPath + } } ... on Forbidden { __typename @@ -68,6 +76,10 @@ mutation ($organization: String!, $project: String!, $targetRef: String!, $other message commitId } + ... on InvalidInput { + __typename + message + } } } ` diff --git a/pkg/platform/api/buildplanner/request/revertcommit.go b/pkg/platform/api/buildplanner/request/revertcommit.go index 1a2e4fbe5a..25844ac787 100644 --- a/pkg/platform/api/buildplanner/request/revertcommit.go +++ b/pkg/platform/api/buildplanner/request/revertcommit.go @@ -42,6 +42,10 @@ mutation ($organization: String!, $project: String!, $commitId: String!, $target targetCommitId conflictPaths } + ... on CommitNotInTargetHistory { + __typename + message + } ... on CommitHasNoParent { __typename message @@ -54,11 +58,18 @@ mutation ($organization: String!, $project: String!, $commitId: String!, $target ... on ParseError { __typename message - path + subErrors { + message + buildExprPath + } } ... on ValidationError { __typename message + subErrors { + message + buildExprPath + } } ... on Forbidden { __typename @@ -72,6 +83,10 @@ mutation ($organization: String!, $project: String!, $commitId: String!, $target message commitId } + ... on InvalidInput { + __typename + message + } } }` } diff --git a/pkg/platform/api/buildplanner/request/stagecommit.go b/pkg/platform/api/buildplanner/request/stagecommit.go index 16b5f9d30c..42725f51ad 100644 --- a/pkg/platform/api/buildplanner/request/stagecommit.go +++ b/pkg/platform/api/buildplanner/request/stagecommit.go @@ -212,7 +212,10 @@ mutation ($organization: String!, $project: String!, $parentCommit: ID!, $descri ... on ParseError { __typename message - path + subErrors { + message + buildExprPath + } } ... on Forbidden { __typename diff --git a/pkg/platform/api/buildplanner/response/commit.go b/pkg/platform/api/buildplanner/response/commit.go index 127613883b..732a708334 100644 --- a/pkg/platform/api/buildplanner/response/commit.go +++ b/pkg/platform/api/buildplanner/response/commit.go @@ -54,7 +54,7 @@ func (c *ProjectCommitResponse) PostProcess() error { func ProcessBuildError(build *BuildResponse, fallbackMessage string) error { logging.Debug("ProcessBuildError: build.Type=%s", build.Type) if build.Type == types.PlanningErrorType { - return processPlanningError(build.Message, build.SubErrors) + return processPlanningError(build.Message, build.Error.SubErrors) } else if build.Error == nil { return errs.New(fallbackMessage) } @@ -133,9 +133,9 @@ type TargetNotFound struct { PossibleTargets []string `json:"possibleTargets"` } -type ValidationError struct { - SubErrors []*BuildExprError `json:"subErrors"` -} +// ValidationError represents a validation error that occurred during planning. +// Contains message and subErrors which is handled separately +type ValidationError struct{} // Commit contains the build and any errors. type Commit struct { diff --git a/pkg/platform/api/buildplanner/response/commiterror.go b/pkg/platform/api/buildplanner/response/commiterror.go index e5efef0793..1a0f53192a 100644 --- a/pkg/platform/api/buildplanner/response/commiterror.go +++ b/pkg/platform/api/buildplanner/response/commiterror.go @@ -27,9 +27,19 @@ func ProcessCommitError(commit *Commit, fallbackMessage string) error { locale.NewInputError("err_buildplanner_commit_not_found", "Could not find commit. Received message: {{.V0}}", commit.Message), } case types.ParseErrorType: + var subErrorMessages []string + for _, e := range commit.SubErrors { + subErrorMessages = append(subErrorMessages, e.Message) + } + if len(subErrorMessages) > 0 { + return &CommitError{ + commit.Type, commit.Message, + locale.NewInputError("err_buildplanner_commit_parse_error_sub_messages", "The platform failed to parse the build expression. Received message: {{.V0}}, with sub errors: {{.V1}}", commit.Message, strings.Join(subErrorMessages, ", ")), + } + } return &CommitError{ commit.Type, commit.Message, - locale.NewInputError("err_buildplanner_parse_error", "The platform failed to parse the build expression. Received message: {{.V0}}. Path: {{.V1}}", commit.Message, commit.ParseError.Path), + locale.NewInputError("err_buildplanner_commit_parse_error", "The platform failed to parse the build expression. Received message: {{.V0}}", commit.Message), } case types.ValidationErrorType: var subErrorMessages []string @@ -39,17 +49,17 @@ func ProcessCommitError(commit *Commit, fallbackMessage string) error { if len(subErrorMessages) > 0 { return &CommitError{ commit.Type, commit.Message, - locale.NewInputError("err_buildplanner_validation_error_sub_messages", "The platform encountered a validation error. Received message: {{.V0}}, with sub errors: {{.V1}}", commit.Message, strings.Join(subErrorMessages, ", ")), + locale.NewInputError("err_buildplanner_commit_validation_error_sub_messages", "The platform encountered a validation error. Received message: {{.V0}}, with sub errors: {{.V1}}", commit.Message, strings.Join(subErrorMessages, ", ")), } } return &CommitError{ commit.Type, commit.Message, - locale.NewInputError("err_buildplanner_validation_error", "The platform encountered a validation error. Received message: {{.V0}}", commit.Message), + locale.NewInputError("err_buildplanner_commit_validation_error", "The platform encountered a validation error. Received message: {{.V0}}", commit.Message), } case types.ForbiddenErrorType: return &CommitError{ commit.Type, commit.Message, - locale.NewInputError("err_buildplanner_forbidden", "Operation forbidden: {{.V0}}. Received message: {{.V1}}", commit.Operation, commit.Message), + locale.NewInputError("err_buildplanner_forbidden", commit.Operation, commit.Message), } case types.HeadOnBranchMovedErrorType: return errs.Wrap(&CommitError{ @@ -69,29 +79,79 @@ func ProcessCommitError(commit *Commit, fallbackMessage string) error { type RevertCommitError struct { Type string Message string + *locale.LocalizedError } func (m *RevertCommitError) Error() string { return m.Message } func ProcessRevertCommitError(rcErr *revertedCommit, fallbackMessage string) error { - if rcErr.Type != "" { - return &RevertCommitError{rcErr.Type, rcErr.Message} + if rcErr.Error == nil { + return errs.New(fallbackMessage) + } + + switch rcErr.Type { + case types.RevertConflictErrorType: + return &RevertCommitError{ + rcErr.Type, rcErr.Message, + locale.NewInputError("err_buildplanner_revert_conflict", "The revert operation could not be completed due to a conflict. Received message: {{.V0}}", rcErr.Message), + } + case types.CommitNotInTargetHistoryErrorType: + return &RevertCommitError{ + rcErr.Type, rcErr.Message, + locale.NewInputError("err_buildplanner_commit_revert_not_in_target_history", "The commit to revert is not in the target history. Received message: {{.V0}}", rcErr.Message), + } + case types.ComitHasNoParentErrorType: + return &RevertCommitError{ + rcErr.Type, rcErr.Message, + locale.NewInputError("err_buildplanner_commit_revert_has_no_parent", "The commit to revert has no parent. Received message: {{.V0}}", rcErr.Message), + } + case types.InvalidInputErrorType: + return &RevertCommitError{ + rcErr.Type, rcErr.Message, + locale.NewInputError("err_buildplanner_revert_invalid_input", "The input to the revert operation was invalid. Received message: {{.V0}}", rcErr.Message), + } + default: + return errs.New(fallbackMessage) } - return errs.New(fallbackMessage) } type MergedCommitError struct { Type string Message string + *locale.LocalizedError } func (m *MergedCommitError) Error() string { return m.Message } func ProcessMergedCommitError(mcErr *mergedCommit, fallbackMessage string) error { - if mcErr.Type != "" { - return &MergedCommitError{mcErr.Type, mcErr.Message} + if mcErr.Error == nil { + return errs.New(fallbackMessage) + } + + switch mcErr.Type { + case types.MergeConflictErrorType: + return &MergedCommitError{ + mcErr.Type, mcErr.Message, + locale.NewInputError("err_buildplanner_merge_conflict", "The platform encountered a merge conflict. Received message: {{.V0}}", mcErr.Message), + } + case types.FastForwardErrorType: + return &MergedCommitError{ + mcErr.Type, mcErr.Message, + locale.NewInputError("err_buildplanner_merge_fast_forward_error", "The platform could not merge with the Fast Forward strategy. Received message: {{.V0}}", mcErr.Message), + } + case types.NoCommonBaseFoundErrorType: + return &MergedCommitError{ + mcErr.Type, mcErr.Message, + locale.NewInputError("err_buildplanner_merge_no_common_base_found", "The platform could not find a common base for the merge. Received message: {{.V0}}", mcErr.Message), + } + case types.InvalidInputErrorType: + return &MergedCommitError{ + mcErr.Type, mcErr.Message, + locale.NewInputError("err_buildplanner_merge_invalid_input", "The input to the merge commit mutation was invalid. Received message: {{.V0}}", mcErr.Message), + } + default: + return errs.New(fallbackMessage) } - return errs.New(fallbackMessage) } // HeadOnBranchMovedError represents an error that occurred because the head on diff --git a/pkg/platform/api/buildplanner/response/shared.go b/pkg/platform/api/buildplanner/response/shared.go index 627bfcb949..ed958b6a61 100644 --- a/pkg/platform/api/buildplanner/response/shared.go +++ b/pkg/platform/api/buildplanner/response/shared.go @@ -85,7 +85,7 @@ func IsErrorResponse(errorType string) bool { errorType == types.PlanningErrorType || errorType == types.MergeConflictType || errorType == types.FastForwardErrorType || - errorType == types.NoCommonBaseFoundType || + errorType == types.NoCommonBaseFoundErrorType || errorType == types.ValidationErrorType || errorType == types.MergeConflictErrorType || errorType == types.RevertConflictErrorType || @@ -101,6 +101,7 @@ type NotFoundError struct { } // ParseError is an error that occurred while parsing the build expression. +// SubErrors are handled separately type ParseError struct { Path string `json:"path"` } @@ -111,7 +112,8 @@ type ForbiddenError struct { // Error contains an error message. type Error struct { - Message string `json:"message"` + Message string `json:"message"` + SubErrors []*BuildExprError `json:"subErrors"` } type TargetNotFoundError struct { diff --git a/pkg/platform/api/buildplanner/types/errors.go b/pkg/platform/api/buildplanner/types/errors.go index e3f234d30a..d34dae9ea9 100644 --- a/pkg/platform/api/buildplanner/types/errors.go +++ b/pkg/platform/api/buildplanner/types/errors.go @@ -14,11 +14,12 @@ const ( PlanningErrorType = "PlanningError" MergeConflictType = "MergeConflict" FastForwardErrorType = "FastForwardError" - NoCommonBaseFoundType = "NoCommonBaseFound" + NoCommonBaseFoundErrorType = "NoCommonBaseFound" ValidationErrorType = "ValidationError" MergeConflictErrorType = "MergeConflict" RevertConflictErrorType = "RevertConflict" CommitNotInTargetHistoryErrorType = "CommitNotInTargetHistory" ComitHasNoParentErrorType = "CommitHasNoParent" TargetNotFoundErrorType = "TargetNotFound" + InvalidInputErrorType = "InvalidInput" )