Provisioning: return field paths in test error messages (#103850)

* Provisioning: Do not block connect step on error

* Display field errors

* Cleanup

* return field errors

* fix test

* convert errros to an array

* Fix history display

* Add getFormErrors

* metav1 issues

* lint

* Proper field names

* Fix notification

* Remove unused component

---------

Co-authored-by: Clarity-89 <homes89@ukr.net>
This commit is contained in:
Ryan McKinley
2025-04-11 14:26:42 +01:00
committed by GitHub
co-authored by Clarity-89
parent ed9a7e8d9f
commit 2c3422fc5c
21 changed files with 260 additions and 245 deletions
@@ -12,12 +12,11 @@ import (
"strings"
"github.com/google/go-github/v70/github"
"github.com/google/uuid"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/validation/field"
"github.com/google/uuid"
"github.com/grafana/grafana-app-sdk/logging"
provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1"
pgh "github.com/grafana/grafana/pkg/registry/apis/provisioning/repository/github"
@@ -57,18 +56,14 @@ func NewGitHub(
secrets secrets.Service,
webhookURL string,
cloneFn CloneFn,
) (*githubRepository, error) {
owner, repo, err := parseOwnerRepo(config.Spec.GitHub.URL)
if err != nil {
return nil, err
}
) *githubRepository {
owner, repo, _ := parseOwnerRepo(config.Spec.GitHub.URL)
token := config.Spec.GitHub.Token
if token == "" {
decrypted, err := secrets.Decrypt(ctx, config.Spec.GitHub.EncryptedToken)
if err != nil {
return nil, err
if err == nil {
token = string(decrypted)
}
token = string(decrypted)
}
return &githubRepository{
config: config,
@@ -78,7 +73,7 @@ func NewGitHub(
owner: owner,
repo: repo,
cloneFn: cloneFn,
}, nil
}
}
func (r *githubRepository) Config() *provisioning.Repository {
@@ -138,59 +133,48 @@ func parseOwnerRepo(giturl string) (owner string, repo string, err error) {
return parts[1], parts[2], nil
}
func fromError(err error, code int) *provisioning.TestResults {
statusErr, ok := err.(apierrors.APIStatus)
if ok {
s := statusErr.Status()
return &provisioning.TestResults{
Code: int(s.Code),
Success: false,
Errors: []string{s.Message},
}
}
return &provisioning.TestResults{
Code: code,
Success: false,
Errors: []string{err.Error()},
}
}
// Test implements provisioning.Repository.
func (r *githubRepository) Test(ctx context.Context) (*provisioning.TestResults, error) {
if err := r.gh.IsAuthenticated(ctx); err != nil {
return fromError(err, http.StatusUnauthorized), nil
return &provisioning.TestResults{
Code: http.StatusBadRequest,
Success: false,
Errors: []provisioning.ErrorDetails{{
Type: metav1.CauseTypeFieldValueInvalid,
Field: field.NewPath("spec", "github", "token").String(),
Detail: err.Error(),
}}}, nil
}
owner, repo, err := parseOwnerRepo(r.config.Spec.GitHub.URL)
url := r.config.Spec.GitHub.URL
owner, repo, err := parseOwnerRepo(url)
if err != nil {
return fromError(err, http.StatusBadRequest), nil
return fromFieldError(field.Invalid(
field.NewPath("spec", "github", "url"), url, err.Error())), nil
}
// FIXME: check token permissions
ok, err := r.gh.RepoExists(ctx, owner, repo)
if err != nil {
return fromError(err, http.StatusBadRequest), nil
return fromFieldError(field.Invalid(
field.NewPath("spec", "github", "url"), url, err.Error())), nil
}
if !ok {
return &provisioning.TestResults{
Code: http.StatusBadRequest,
Success: false,
Errors: []string{"repository does not exist"},
}, nil
return fromFieldError(field.NotFound(
field.NewPath("spec", "github", "url"), url)), nil
}
ok, err = r.gh.BranchExists(ctx, r.owner, r.repo, r.config.Spec.GitHub.Branch)
branch := r.config.Spec.GitHub.Branch
ok, err = r.gh.BranchExists(ctx, r.owner, r.repo, branch)
if err != nil {
return fromError(err, http.StatusBadRequest), nil
return fromFieldError(field.Invalid(
field.NewPath("spec", "github", "branch"), branch, err.Error())), nil
}
if !ok {
return &provisioning.TestResults{
Code: http.StatusBadRequest,
Success: false,
Errors: []string{"branch does not exist"},
}, nil
return fromFieldError(field.NotFound(
field.NewPath("spec", "github", "branch"), branch)), nil
}
return &provisioning.TestResults{