Files
Roberto Jiménez Sánchez 3cb62e370b Provisioning: Add pure git repository type (#106815)
* Add repository type git to spec
* Register git type
* Update test checks
2025-06-18 09:05:37 +02:00

110 lines
3.5 KiB
Go

package repository
import (
"context"
"fmt"
"net/http"
"slices"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/validation/field"
provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1"
)
// Tester is a struct that implements the Tester interface
// it's temporary
// FIXME: remove as soon as controller and jobs refactoring PRs are merged
type Tester struct{}
func (t *Tester) TestRepository(ctx context.Context, repo Repository) (*provisioning.TestResults, error) {
return TestRepository(ctx, repo)
}
func TestRepository(ctx context.Context, repo Repository) (*provisioning.TestResults, error) {
errors := ValidateRepository(repo)
if len(errors) > 0 {
rsp := &provisioning.TestResults{
Code: http.StatusUnprocessableEntity, // Invalid
Success: false,
Errors: make([]provisioning.ErrorDetails, len(errors)),
}
for i, err := range errors {
rsp.Errors[i] = provisioning.ErrorDetails{
Type: metav1.CauseType(err.Type),
Field: err.Field,
Detail: err.Detail,
}
}
return rsp, nil
}
return repo.Test(ctx)
}
func ValidateRepository(repo Repository) field.ErrorList {
list := repo.Validate()
cfg := repo.Config()
if cfg.Spec.Title == "" {
list = append(list, field.Required(field.NewPath("spec", "title"), "a repository title must be given"))
}
if cfg.Spec.Sync.Enabled && cfg.Spec.Sync.Target == "" {
list = append(list, field.Required(field.NewPath("spec", "sync", "target"),
"The target type is required when sync is enabled"))
}
if cfg.Spec.Sync.Enabled && cfg.Spec.Sync.IntervalSeconds < 10 {
list = append(list, field.Invalid(field.NewPath("spec", "sync", "intervalSeconds"),
cfg.Spec.Sync.IntervalSeconds, fmt.Sprintf("Interval must be at least %d seconds", 10)))
}
// Reserved names (for now)
reserved := []string{"classic", "sql", "SQL", "plugins", "legacy", "new", "job", "github", "s3", "gcs", "file", "new", "create", "update", "delete"}
if slices.Contains(reserved, cfg.Name) {
list = append(list, field.Invalid(field.NewPath("metadata", "name"), cfg.Name, "Name is reserved, choose a different identifier"))
}
if cfg.Spec.Type != provisioning.LocalRepositoryType && cfg.Spec.Local != nil {
list = append(list, field.Invalid(field.NewPath("spec", "local"),
cfg.Spec.GitHub, "Local config only valid when type is local"))
}
if cfg.Spec.Type != provisioning.GitHubRepositoryType && cfg.Spec.GitHub != nil {
list = append(list, field.Invalid(field.NewPath("spec", "github"),
cfg.Spec.GitHub, "Github config only valid when type is github"))
}
if cfg.Spec.Type != provisioning.GitRepositoryType && cfg.Spec.Git != nil {
list = append(list, field.Invalid(field.NewPath("spec", "git"),
cfg.Spec.Git, "Git config only valid when type is git"))
}
for _, w := range cfg.Spec.Workflows {
switch w {
case provisioning.WriteWorkflow: // valid; no fall thru
case provisioning.BranchWorkflow:
if !cfg.Spec.Type.IsGit() {
list = append(list, field.Invalid(field.NewPath("spec", "workflow"), w, "branch is only supported on git repositories"))
}
default:
list = append(list, field.Invalid(field.NewPath("spec", "workflow"), w, "invalid workflow"))
}
}
return list
}
func fromFieldError(err *field.Error) *provisioning.TestResults {
return &provisioning.TestResults{
Code: http.StatusBadRequest,
Success: false,
Errors: []provisioning.ErrorDetails{{
Type: metav1.CauseType(err.Type),
Field: err.Field,
Detail: err.Detail,
}},
}
}