Files
Roberto Jiménez Sánchez 047499a363 Provisioning: introduce concept of provisioning extras (#104981)
* Spike: Extras

* Attempt to wire it up

* Hack

* Fix issue with jobs

* Wire more things up

* Fix more wiring stuff

* Remove webhook secret key from main registration

* Move secret encryption also outside register

* Add TODOs in code

* Add more explanations

* Move connectors to different package

* Move pull request job into webhooks

* Separate registration

* Remove duplicate files

* Fix missing function

* Extract webhook repository logic out of the core github repository

* Use status patcher in webhook connector

* Fix change in go mod

* Change hooks signature

* Remove TODOs

* Remove Webhook methos from go-git

* Remove leftover

* Fix mistake in OpenAPI spec

* Fix some tests

* Fix some issues

* Fix linting
2025-05-13 09:50:43 +02:00

123 lines
3.8 KiB
Go

package pullrequest
import (
"context"
"errors"
"fmt"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"github.com/grafana/grafana-app-sdk/logging"
provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1"
"github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs"
"github.com/grafana/grafana/pkg/registry/apis/provisioning/repository"
"github.com/grafana/grafana/pkg/registry/apis/provisioning/resources"
)
//go:generate mockery --name=PullRequestRepo --structname=MockPullRequestRepo --inpackage --filename=mock_pullrequest_repo.go --with-expecter
type PullRequestRepo interface {
Config() *provisioning.Repository
Read(ctx context.Context, path, ref string) (*repository.FileInfo, error)
CompareFiles(ctx context.Context, base, ref string) ([]repository.VersionedFileChange, error)
CommentPullRequest(ctx context.Context, pr int, comment string) error
}
//go:generate mockery --name=Evaluator --structname=MockEvaluator --inpackage --filename=mock_evaluator.go --with-expecter
type Evaluator interface {
Evaluate(ctx context.Context, repo repository.Reader, opts provisioning.PullRequestJobOptions, changes []repository.VersionedFileChange, progress jobs.JobProgressRecorder) (changeInfo, error)
}
//go:generate mockery --name=Commenter --structname=MockCommenter --inpackage --filename=mock_commenter.go --with-expecter
type Commenter interface {
Comment(ctx context.Context, repo PullRequestRepo, pr int, changeInfo changeInfo) error
}
type PullRequestWorker struct {
evaluator Evaluator
commenter Commenter
}
func NewPullRequestWorker(evaluator Evaluator, commenter Commenter) *PullRequestWorker {
return &PullRequestWorker{
evaluator: evaluator,
commenter: commenter,
}
}
func (c *PullRequestWorker) IsSupported(ctx context.Context, job provisioning.Job) bool {
return job.Spec.Action == provisioning.JobActionPullRequest
}
func (c *PullRequestWorker) Process(ctx context.Context,
repo repository.Repository,
job provisioning.Job,
progress jobs.JobProgressRecorder,
) error {
cfg := repo.Config().Spec
opts := job.Spec.PullRequest
if opts == nil {
return apierrors.NewBadRequest("missing spec.pr")
}
if opts.Ref == "" {
return apierrors.NewBadRequest("missing spec.ref")
}
// FIXME: this is leaky because it's supposed to be already a PullRequestRepo
if cfg.GitHub == nil {
return apierrors.NewBadRequest("expecting github configuration")
}
reader, ok := repo.(repository.Reader)
if !ok {
return errors.New("pull request job submitted targeting repository that is not a Reader")
}
prRepo, ok := repo.(PullRequestRepo)
if !ok {
return fmt.Errorf("repository is not a pull request repository")
}
logger := logging.FromContext(ctx).With("pr", opts.PR)
logger.Info("process pull request")
defer logger.Info("pull request processed")
progress.SetMessage(ctx, "listing pull request files")
// FIXME: this is leaky because it's supposed to be already a PullRequestRepo
base := cfg.GitHub.Branch
files, err := prRepo.CompareFiles(ctx, base, opts.Ref)
if err != nil {
return fmt.Errorf("failed to list pull request files: %w", err)
}
files = onlySupportedFiles(files)
if len(files) == 0 {
progress.SetFinalMessage(ctx, "no files to process")
return nil
}
changeInfo, err := c.evaluator.Evaluate(ctx, reader, *opts, files, progress)
if err != nil {
return fmt.Errorf("calculate changes: %w", err)
}
if err := c.commenter.Comment(ctx, prRepo, opts.PR, changeInfo); err != nil {
return fmt.Errorf("comment pull request: %w", err)
}
logger.Info("preview comment added")
return nil
}
// Remove files we should not try to process
func onlySupportedFiles(files []repository.VersionedFileChange) (ret []repository.VersionedFileChange) {
for _, file := range files {
if file.Action == repository.FileActionIgnored || resources.IsPathSupported(file.Path) != nil {
continue
}
ret = append(ret, file)
}
return
}