Provisioning: Include URLs in ResourceWrapper response (#101511)
This commit is contained in:
1 parent
585fb5defe
commit
de9febcab7
20 files changed
+435
-106
No files matched your search
@@ -26,15 +26,15 @@ type JobList struct {
|
||||
type JobAction string
|
||||
|
||||
const (
|
||||
// Update a pull request -- send preview images, links etc
|
||||
JobActionPullRequest JobAction = "pr"
|
||||
|
||||
// Sync the remote branch with the grafana instance
|
||||
JobActionSync JobAction = "pull"
|
||||
|
||||
// Export from grafana into the remote repository
|
||||
JobActionExport JobAction = "push"
|
||||
|
||||
// Process a pull request -- apply comments with preview images, links etc
|
||||
JobActionPullRequest JobAction = "pr"
|
||||
|
||||
// Migration task -- this will migrate an full instance from SQL > Git
|
||||
JobActionMigrate JobAction = "migrate"
|
||||
)
|
||||
@@ -69,11 +69,11 @@ type JobSpec struct {
|
||||
// Pull request options
|
||||
PullRequest *PullRequestJobOptions `json:"pr,omitempty"`
|
||||
|
||||
// Required when the action is `export`
|
||||
Export *ExportJobOptions `json:"export,omitempty"`
|
||||
// Required when the action is `push`
|
||||
Push *ExportJobOptions `json:"push,omitempty"`
|
||||
|
||||
// Required when the action is `sync`
|
||||
Sync *SyncJobOptions `json:"sync,omitempty"`
|
||||
// Required when the action is `pull`
|
||||
Pull *SyncJobOptions `json:"pull,omitempty"`
|
||||
|
||||
// Required when the action is `migrate`
|
||||
Migrate *MigrateJobOptions `json:"migrate,omitempty"`
|
||||
|
||||
@@ -219,12 +219,18 @@ type ResourceWrapper struct {
|
||||
// Path to the remote file
|
||||
Path string `json:"path,omitempty"`
|
||||
|
||||
// The commit hash (if exists)
|
||||
// The request ref (or branch if exists)
|
||||
Ref string `json:"ref,omitempty"`
|
||||
|
||||
// The repo hash value
|
||||
Hash string `json:"hash,omitempty"`
|
||||
|
||||
// Basic repository info
|
||||
Repository ResourceRepositoryInfo `json:"repository"`
|
||||
|
||||
// Typed links for this file (only supported by external systems, github etc)
|
||||
URLs *ResourceURLs `json:"urls,omitempty"`
|
||||
|
||||
// The modified time in the remote file system
|
||||
Timestamp *metav1.Time `json:"timestamp,omitempty"`
|
||||
|
||||
@@ -264,6 +270,34 @@ type ResourceObjects struct {
|
||||
DryRun common.Unstructured `json:"dryRun,omitempty"`
|
||||
}
|
||||
|
||||
type ResourceRepositoryInfo struct {
|
||||
// The repository type
|
||||
Type RepositoryType `json:"type"`
|
||||
|
||||
// The display name for this repository
|
||||
Title string `json:"title"`
|
||||
|
||||
// The namespace this belongs to
|
||||
Namespace string `json:"namespace"`
|
||||
|
||||
// The name (identifier)
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type ResourceURLs struct {
|
||||
// A URL pointing to the this file in the repository
|
||||
SourceURL string `json:"sourceURL,omitempty"`
|
||||
|
||||
// A URL pointing to the repository this lives in
|
||||
RepositoryURL string `json:"repositoryURL,omitempty"`
|
||||
|
||||
// A URL that will create a new pull requeset for this branch
|
||||
NewPullRequestURL string `json:"newPullRequestURL,omitempty"`
|
||||
|
||||
// Compare this version to the target branch
|
||||
CompareURL string `json:"compareURL,omitempty"`
|
||||
}
|
||||
|
||||
// Information we can get just from the file listing
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type FileList struct {
|
||||
|
||||
@@ -276,13 +276,13 @@ func (in *JobSpec) DeepCopyInto(out *JobSpec) {
|
||||
*out = new(PullRequestJobOptions)
|
||||
**out = **in
|
||||
}
|
||||
if in.Export != nil {
|
||||
in, out := &in.Export, &out.Export
|
||||
if in.Push != nil {
|
||||
in, out := &in.Push, &out.Push
|
||||
*out = new(ExportJobOptions)
|
||||
**out = **in
|
||||
}
|
||||
if in.Sync != nil {
|
||||
in, out := &in.Sync, &out.Sync
|
||||
if in.Pull != nil {
|
||||
in, out := &in.Pull, &out.Pull
|
||||
*out = new(SyncJobOptions)
|
||||
**out = **in
|
||||
}
|
||||
@@ -634,6 +634,22 @@ func (in *ResourceObjects) DeepCopy() *ResourceObjects {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ResourceRepositoryInfo) DeepCopyInto(out *ResourceRepositoryInfo) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceRepositoryInfo.
|
||||
func (in *ResourceRepositoryInfo) DeepCopy() *ResourceRepositoryInfo {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ResourceRepositoryInfo)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ResourceStats) DeepCopyInto(out *ResourceStats) {
|
||||
*out = *in
|
||||
@@ -681,10 +697,32 @@ func (in *ResourceType) DeepCopy() *ResourceType {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ResourceURLs) DeepCopyInto(out *ResourceURLs) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceURLs.
|
||||
func (in *ResourceURLs) DeepCopy() *ResourceURLs {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ResourceURLs)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ResourceWrapper) DeepCopyInto(out *ResourceWrapper) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.Repository = in.Repository
|
||||
if in.URLs != nil {
|
||||
in, out := &in.URLs, &out.URLs
|
||||
*out = new(ResourceURLs)
|
||||
**out = **in
|
||||
}
|
||||
if in.Timestamp != nil {
|
||||
in, out := &in.Timestamp, &out.Timestamp
|
||||
*out = (*in).DeepCopy()
|
||||
|
||||
@@ -40,8 +40,10 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
|
||||
"github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.ResourceList": schema_pkg_apis_provisioning_v0alpha1_ResourceList(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.ResourceListItem": schema_pkg_apis_provisioning_v0alpha1_ResourceListItem(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.ResourceObjects": schema_pkg_apis_provisioning_v0alpha1_ResourceObjects(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.ResourceRepositoryInfo": schema_pkg_apis_provisioning_v0alpha1_ResourceRepositoryInfo(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.ResourceStats": schema_pkg_apis_provisioning_v0alpha1_ResourceStats(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.ResourceType": schema_pkg_apis_provisioning_v0alpha1_ResourceType(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.ResourceURLs": schema_pkg_apis_provisioning_v0alpha1_ResourceURLs(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.ResourceWrapper": schema_pkg_apis_provisioning_v0alpha1_ResourceWrapper(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.SyncJobOptions": schema_pkg_apis_provisioning_v0alpha1_SyncJobOptions(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.SyncOptions": schema_pkg_apis_provisioning_v0alpha1_SyncOptions(ref),
|
||||
@@ -618,11 +620,11 @@ func schema_pkg_apis_provisioning_v0alpha1_JobSpec(ref common.ReferenceCallback)
|
||||
Properties: map[string]spec.Schema{
|
||||
"action": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Possible enum values:\n - `\"export\"` Export from grafana into the remote repository\n - `\"migrate\"` Migration task -- this will migrate an full instance from SQL > Git\n - `\"pr\"` Update a pull request -- send preview images, links etc\n - `\"sync\"` Sync the remote branch with the grafana instance",
|
||||
Description: "Possible enum values:\n - `\"migrate\"` Migration task -- this will migrate an full instance from SQL > Git\n - `\"pr\"` Process a pull request -- apply comments with preview images, links etc\n - `\"pull\"` Sync the remote branch with the grafana instance\n - `\"push\"` Export from grafana into the remote repository",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
Enum: []interface{}{"export", "migrate", "pr", "sync"},
|
||||
Enum: []interface{}{"migrate", "pr", "pull", "push"},
|
||||
},
|
||||
},
|
||||
"repository": {
|
||||
@@ -639,15 +641,15 @@ func schema_pkg_apis_provisioning_v0alpha1_JobSpec(ref common.ReferenceCallback)
|
||||
Ref: ref("github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.PullRequestJobOptions"),
|
||||
},
|
||||
},
|
||||
"export": {
|
||||
"push": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Required when the action is `export`",
|
||||
Description: "Required when the action is `push`",
|
||||
Ref: ref("github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.ExportJobOptions"),
|
||||
},
|
||||
},
|
||||
"sync": {
|
||||
"pull": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Required when the action is `sync`",
|
||||
Description: "Required when the action is `pull`",
|
||||
Ref: ref("github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.SyncJobOptions"),
|
||||
},
|
||||
},
|
||||
@@ -1387,6 +1389,52 @@ func schema_pkg_apis_provisioning_v0alpha1_ResourceObjects(ref common.ReferenceC
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_provisioning_v0alpha1_ResourceRepositoryInfo(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"type": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The repository type\n\nPossible enum values:\n - `\"github\"`\n - `\"local\"`",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
Enum: []interface{}{"github", "local"},
|
||||
},
|
||||
},
|
||||
"title": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The display name for this repository",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"namespace": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The namespace this belongs to",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"name": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The name (identifier)",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"type", "title", "namespace", "name"},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_provisioning_v0alpha1_ResourceStats(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
@@ -1484,6 +1532,46 @@ func schema_pkg_apis_provisioning_v0alpha1_ResourceType(ref common.ReferenceCall
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_provisioning_v0alpha1_ResourceURLs(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"sourceURL": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A URL pointing to the this file in the repository",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"repositoryURL": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A URL pointing to the repository this lives in",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"newPullRequestURL": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A URL that will create a new pull requeset for this branch",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"compareURL": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Compare this version to the target branch",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_provisioning_v0alpha1_ResourceWrapper(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
@@ -1514,7 +1602,7 @@ func schema_pkg_apis_provisioning_v0alpha1_ResourceWrapper(ref common.ReferenceC
|
||||
},
|
||||
"ref": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The commit hash (if exists)",
|
||||
Description: "The request ref (or branch if exists)",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
@@ -1526,6 +1614,19 @@ func schema_pkg_apis_provisioning_v0alpha1_ResourceWrapper(ref common.ReferenceC
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"repository": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Basic repository info",
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.ResourceRepositoryInfo"),
|
||||
},
|
||||
},
|
||||
"urls": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Typed links for this file (only supported by external systems, github etc)",
|
||||
Ref: ref("github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.ResourceURLs"),
|
||||
},
|
||||
},
|
||||
"timestamp": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The modified time in the remote file system",
|
||||
@@ -1560,11 +1661,11 @@ func schema_pkg_apis_provisioning_v0alpha1_ResourceWrapper(ref common.ReferenceC
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"resource"},
|
||||
Required: []string{"repository", "resource"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.ResourceObjects", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"},
|
||||
"github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.ResourceObjects", "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.ResourceRepositoryInfo", "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.ResourceURLs", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,5 +12,6 @@ API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provis
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,WebhookStatus,SubscribedEvents
|
||||
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,JobSpec,PullRequest
|
||||
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,RepositorySpec,GitHub
|
||||
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,ResourceWrapper,URLs
|
||||
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,SyncStatus,JobID
|
||||
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,WebhookResponse,Message
|
||||
@@ -366,7 +366,7 @@ func (rc *RepositoryController) addSyncJob(ctx context.Context, obj *provisionin
|
||||
Spec: provisioning.JobSpec{
|
||||
Repository: obj.GetName(),
|
||||
Action: provisioning.JobActionSync,
|
||||
Sync: syncOptions,
|
||||
Pull: syncOptions,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -71,7 +71,7 @@ func (c *exportConnector) Connect(
|
||||
Spec: provisioning.JobSpec{
|
||||
Action: provisioning.JobActionExport,
|
||||
Repository: cfg.Name,
|
||||
Export: options,
|
||||
Push: options,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -48,7 +48,7 @@ func (r *ExportWorker) IsSupported(ctx context.Context, job provisioning.Job) bo
|
||||
|
||||
// Process will start a job
|
||||
func (r *ExportWorker) Process(ctx context.Context, repo repository.Repository, job provisioning.Job, progress jobs.JobProgressRecorder) error {
|
||||
options := job.Spec.Export
|
||||
options := job.Spec.Push
|
||||
if options == nil {
|
||||
return errors.New("missing export settings")
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ func (w *MigrationWorker) Process(ctx context.Context, repo repository.Repositor
|
||||
} else {
|
||||
err = w.exportWorker.Process(ctx, rw, provisioning.Job{
|
||||
Spec: provisioning.JobSpec{
|
||||
Export: &provisioning.ExportJobOptions{
|
||||
Push: &provisioning.ExportJobOptions{
|
||||
Identifier: options.Identifier,
|
||||
},
|
||||
},
|
||||
@@ -210,7 +210,7 @@ func (w *MigrationWorker) Process(ctx context.Context, repo repository.Repositor
|
||||
// Delegate the import to a sync (from the already checked out go-git repository!)
|
||||
err = w.syncWorker.Process(ctx, rw, provisioning.Job{
|
||||
Spec: provisioning.JobSpec{
|
||||
Sync: &provisioning.SyncJobOptions{
|
||||
Pull: &provisioning.SyncJobOptions{
|
||||
Incremental: false,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -175,12 +175,12 @@ func (s *jobStore) Add(ctx context.Context, job *provisioning.Job) (*provisionin
|
||||
if job.Spec.Action == "" {
|
||||
return nil, apierrors.NewBadRequest("missing spec.action")
|
||||
}
|
||||
if job.Spec.Action == provisioning.JobActionExport && job.Spec.Export == nil {
|
||||
return nil, apierrors.NewBadRequest("missing spec.export")
|
||||
if job.Spec.Action == provisioning.JobActionExport && job.Spec.Push == nil {
|
||||
return nil, apierrors.NewBadRequest("missing spec.push")
|
||||
}
|
||||
|
||||
if job.Spec.Action == provisioning.JobActionSync && job.Spec.Sync == nil {
|
||||
return nil, apierrors.NewBadRequest("missing spec.sync")
|
||||
if job.Spec.Action == provisioning.JobActionSync && job.Spec.Pull == nil {
|
||||
return nil, apierrors.NewBadRequest("missing spec.pull")
|
||||
}
|
||||
|
||||
// Only for add
|
||||
|
||||
@@ -101,7 +101,7 @@ func (r *SyncWorker) Process(ctx context.Context, repo repository.Repository, jo
|
||||
return fmt.Errorf("failed to create sync job: %w", err)
|
||||
}
|
||||
|
||||
syncError := syncJob.run(ctx, *job.Spec.Sync)
|
||||
syncError := syncJob.run(ctx, *job.Spec.Pull)
|
||||
jobStatus := progress.Complete(ctx, syncError)
|
||||
syncStatus = jobStatus.ToSyncStatus(job.Name)
|
||||
|
||||
|
||||
@@ -38,11 +38,12 @@ type githubRepository struct {
|
||||
}
|
||||
|
||||
var (
|
||||
_ Repository = (*githubRepository)(nil)
|
||||
_ Hooks = (*githubRepository)(nil)
|
||||
_ Versioned = (*githubRepository)(nil)
|
||||
_ Writer = (*githubRepository)(nil)
|
||||
_ Reader = (*githubRepository)(nil)
|
||||
_ Repository = (*githubRepository)(nil)
|
||||
_ Hooks = (*githubRepository)(nil)
|
||||
_ Versioned = (*githubRepository)(nil)
|
||||
_ Writer = (*githubRepository)(nil)
|
||||
_ Reader = (*githubRepository)(nil)
|
||||
_ RepositoryWithURLs = (*githubRepository)(nil)
|
||||
)
|
||||
|
||||
func NewGitHub(
|
||||
@@ -561,7 +562,7 @@ func (r *githubRepository) parsePushEvent(event *github.PushEvent) (*provisionin
|
||||
Job: &provisioning.JobSpec{
|
||||
Repository: r.Config().GetName(),
|
||||
Action: provisioning.JobActionSync,
|
||||
Sync: &provisioning.SyncJobOptions{
|
||||
Pull: &provisioning.SyncJobOptions{
|
||||
Incremental: true,
|
||||
},
|
||||
},
|
||||
@@ -709,6 +710,33 @@ func (r *githubRepository) CommentPullRequestFile(ctx context.Context, prNumber
|
||||
return r.gh.CreatePullRequestFileComment(ctx, r.owner, r.repo, prNumber, fileComment)
|
||||
}
|
||||
|
||||
// ResourceURLs implements RepositoryWithURLs.
|
||||
func (r *githubRepository) ResourceURLs(ctx context.Context, file *FileInfo) (*provisioning.ResourceURLs, error) {
|
||||
cfg := r.config.Spec.GitHub
|
||||
if file.Path == "" || cfg == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
ref := file.Ref
|
||||
if ref == "" {
|
||||
ref = cfg.Branch
|
||||
}
|
||||
|
||||
urls := &provisioning.ResourceURLs{
|
||||
RepositoryURL: cfg.URL,
|
||||
SourceURL: fmt.Sprintf("%s/blob/%s/%s", cfg.URL, ref, file.Path),
|
||||
}
|
||||
|
||||
if ref != cfg.Branch {
|
||||
urls.CompareURL = fmt.Sprintf("%s/compare/%s...%s", cfg.URL, cfg.Branch, ref)
|
||||
|
||||
// Create a new pull request
|
||||
urls.NewPullRequestURL = fmt.Sprintf("%s?quick_pull=1&labels=grafana", urls.CompareURL)
|
||||
}
|
||||
|
||||
return urls, nil
|
||||
}
|
||||
|
||||
func (r *githubRepository) createWebhook(ctx context.Context) (pgh.WebhookConfig, error) {
|
||||
secret, err := uuid.NewRandom()
|
||||
if err != nil {
|
||||
|
||||
@@ -84,7 +84,7 @@ func TestParseWebhooks(t *testing.T) {
|
||||
Job: &provisioning.JobSpec{ // we want to always push a sync job
|
||||
Repository: "unit-test-repo",
|
||||
Action: provisioning.JobActionSync,
|
||||
Sync: &provisioning.SyncJobOptions{
|
||||
Pull: &provisioning.SyncJobOptions{
|
||||
Incremental: true,
|
||||
},
|
||||
},
|
||||
@@ -94,7 +94,7 @@ func TestParseWebhooks(t *testing.T) {
|
||||
Job: &provisioning.JobSpec{
|
||||
Repository: "unit-test-repo",
|
||||
Action: provisioning.JobActionSync,
|
||||
Sync: &provisioning.SyncJobOptions{
|
||||
Pull: &provisioning.SyncJobOptions{
|
||||
Incremental: true,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -99,6 +99,14 @@ type ReaderWriter interface {
|
||||
Writer
|
||||
}
|
||||
|
||||
// Hooks called after the repository has been created, updated or deleted
|
||||
type RepositoryWithURLs interface {
|
||||
Repository
|
||||
|
||||
// Get resource URLs for a file inside a repository
|
||||
ResourceURLs(ctx context.Context, file *FileInfo) (*provisioning.ResourceURLs, error)
|
||||
}
|
||||
|
||||
// Hooks called after the repository has been created, updated or deleted
|
||||
type Hooks interface {
|
||||
Repository
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1"
|
||||
@@ -97,10 +96,8 @@ spec:
|
||||
require.NoError(t, err)
|
||||
|
||||
parser := &Parser{
|
||||
repo: &provisioning.Repository{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test",
|
||||
},
|
||||
repo: provisioning.ResourceRepositoryInfo{
|
||||
Name: "test",
|
||||
},
|
||||
client: &DynamicClient{},
|
||||
kinds: &StaticKindsLookup{},
|
||||
|
||||
@@ -35,8 +35,15 @@ func (f *ParserFactory) GetParser(ctx context.Context, repo repository.Reader) (
|
||||
return nil, err
|
||||
}
|
||||
|
||||
urls, _ := repo.(repository.RepositoryWithURLs)
|
||||
parser := &Parser{
|
||||
repo: config,
|
||||
repo: provisioning.ResourceRepositoryInfo{
|
||||
Type: config.Spec.Type,
|
||||
Title: config.Spec.Title,
|
||||
Namespace: config.Namespace,
|
||||
Name: config.Name,
|
||||
},
|
||||
urls: urls,
|
||||
client: client,
|
||||
kinds: kinds,
|
||||
}
|
||||
@@ -46,7 +53,10 @@ func (f *ParserFactory) GetParser(ctx context.Context, repo repository.Reader) (
|
||||
|
||||
type Parser struct {
|
||||
// The target repository
|
||||
repo *provisioning.Repository
|
||||
repo provisioning.ResourceRepositoryInfo
|
||||
|
||||
// for repositories that have URL support
|
||||
urls repository.RepositoryWithURLs
|
||||
|
||||
// client helper (for this namespace?)
|
||||
client *DynamicClient
|
||||
@@ -57,6 +67,12 @@ type ParsedResource struct {
|
||||
// Original file Info
|
||||
Info *repository.FileInfo
|
||||
|
||||
// The repository details
|
||||
Repo provisioning.ResourceRepositoryInfo
|
||||
|
||||
// Resource URLs
|
||||
URLs *provisioning.ResourceURLs
|
||||
|
||||
// Check for classic file types (dashboard.json, etc)
|
||||
Classic provisioning.ClassicFileType
|
||||
|
||||
@@ -94,6 +110,7 @@ func (r *Parser) Parse(ctx context.Context, info *repository.FileInfo, validate
|
||||
logger := logging.FromContext(ctx).With("path", info.Path, "validate", validate)
|
||||
parsed = &ParsedResource{
|
||||
Info: info,
|
||||
Repo: r.repo,
|
||||
}
|
||||
|
||||
if ShouldIgnorePath(info.Path) && info.Path != "" {
|
||||
@@ -110,7 +127,15 @@ func (r *Parser) Parse(ctx context.Context, info *repository.FileInfo, validate
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the internal UID,version and id if they exist
|
||||
if r.urls != nil {
|
||||
parsed.URLs, err = r.urls.ResourceURLs(ctx, info)
|
||||
if err != nil {
|
||||
logger.Debug("failed to load resource URLs", "error", err)
|
||||
return parsed, err
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the internal dashboard UID,version and id if they exist
|
||||
if parsed.GVK.Group == dashboard.GROUP && parsed.GVK.Kind == "Dashboard" {
|
||||
unstructured.RemoveNestedField(parsed.Obj.Object, "spec", "uid")
|
||||
unstructured.RemoveNestedField(parsed.Obj.Object, "spec", "version")
|
||||
@@ -122,17 +147,16 @@ func (r *Parser) Parse(ctx context.Context, info *repository.FileInfo, validate
|
||||
return nil, err
|
||||
}
|
||||
obj := parsed.Obj
|
||||
cfg := r.repo
|
||||
|
||||
// Validate the namespace
|
||||
if obj.GetNamespace() != "" && obj.GetNamespace() != cfg.GetNamespace() {
|
||||
if obj.GetNamespace() != "" && obj.GetNamespace() != r.repo.Namespace {
|
||||
parsed.Errors = append(parsed.Errors, ErrNamespaceMismatch)
|
||||
}
|
||||
|
||||
obj.SetNamespace(cfg.GetNamespace())
|
||||
obj.SetNamespace(r.repo.Namespace)
|
||||
parsed.Meta.SetManagerProperties(utils.ManagerProperties{
|
||||
Kind: utils.ManagerKindRepo,
|
||||
Identity: cfg.Name,
|
||||
Identity: r.repo.Name,
|
||||
})
|
||||
parsed.Meta.SetSourceProperties(utils.SourceProperties{
|
||||
Path: info.Path, // joinPathWithRef(info.Path, info.Ref),
|
||||
@@ -141,7 +165,7 @@ func (r *Parser) Parse(ctx context.Context, info *repository.FileInfo, validate
|
||||
|
||||
// Calculate name+folder from the file path
|
||||
if info.Path != "" {
|
||||
objName, folderName := NamesFromHashedRepoPath(cfg.Name, info.Path)
|
||||
objName, folderName := NamesFromHashedRepoPath(r.repo.Name, info.Path)
|
||||
parsed.Meta.SetFolder(folderName)
|
||||
if obj.GetName() == "" {
|
||||
obj.SetName(objName) // use the name saved in config
|
||||
@@ -243,11 +267,13 @@ func (f *ParsedResource) AsResourceWrapper() *provisioning.ResourceWrapper {
|
||||
res.DryRun = v0alpha1.Unstructured{Object: f.DryRunResponse.Object}
|
||||
}
|
||||
wrap := &provisioning.ResourceWrapper{
|
||||
Path: info.Path,
|
||||
Ref: info.Ref,
|
||||
Hash: info.Hash,
|
||||
Timestamp: info.Modified,
|
||||
Resource: res,
|
||||
Path: info.Path,
|
||||
Ref: info.Ref,
|
||||
Hash: info.Hash,
|
||||
Repository: f.Repo,
|
||||
URLs: f.URLs,
|
||||
Timestamp: info.Modified,
|
||||
Resource: res,
|
||||
}
|
||||
for _, err := range f.Errors {
|
||||
wrap.Errors = append(wrap.Errors, err.Error())
|
||||
|
||||
@@ -74,7 +74,7 @@ func (c *syncConnector) Connect(
|
||||
Spec: provisioning.JobSpec{
|
||||
Action: provisioning.JobActionSync,
|
||||
Repository: cfg.Name,
|
||||
Sync: &options,
|
||||
Pull: &options,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -3171,22 +3171,14 @@
|
||||
],
|
||||
"properties": {
|
||||
"action": {
|
||||
"description": "Possible enum values:\n - `\"export\"` Export from grafana into the remote repository\n - `\"migrate\"` Migration task -- this will migrate an full instance from SQL \u003e Git\n - `\"pr\"` Update a pull request -- send preview images, links etc\n - `\"sync\"` Sync the remote branch with the grafana instance",
|
||||
"description": "Possible enum values:\n - `\"migrate\"` Migration task -- this will migrate an full instance from SQL \u003e Git\n - `\"pr\"` Process a pull request -- apply comments with preview images, links etc\n - `\"pull\"` Sync the remote branch with the grafana instance\n - `\"push\"` Export from grafana into the remote repository",
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"enum": [
|
||||
"export",
|
||||
"migrate",
|
||||
"pr",
|
||||
"sync"
|
||||
]
|
||||
},
|
||||
"export": {
|
||||
"description": "Required when the action is `export`",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.ExportJobOptions"
|
||||
}
|
||||
"pull",
|
||||
"push"
|
||||
]
|
||||
},
|
||||
"migrate": {
|
||||
@@ -3205,18 +3197,26 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"repository": {
|
||||
"description": "The the repository reference (for now also in labels)",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"sync": {
|
||||
"description": "Required when the action is `sync`",
|
||||
"pull": {
|
||||
"description": "Required when the action is `pull`",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.SyncJobOptions"
|
||||
}
|
||||
]
|
||||
},
|
||||
"push": {
|
||||
"description": "Required when the action is `push`",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.ExportJobOptions"
|
||||
}
|
||||
]
|
||||
},
|
||||
"repository": {
|
||||
"description": "The the repository reference (for now also in labels)",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -3776,6 +3776,41 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.ResourceRepositoryInfo": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type",
|
||||
"title",
|
||||
"namespace",
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "The name (identifier)",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"namespace": {
|
||||
"description": "The namespace this belongs to",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"title": {
|
||||
"description": "The display name for this repository",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"type": {
|
||||
"description": "The repository type\n\nPossible enum values:\n - `\"github\"`\n - `\"local\"`",
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"enum": [
|
||||
"github",
|
||||
"local"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.ResourceStats": {
|
||||
"description": "Information we can get just from the file listing",
|
||||
"type": "object",
|
||||
@@ -3831,10 +3866,32 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.ResourceURLs": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"compareURL": {
|
||||
"description": "Compare this version to the target branch",
|
||||
"type": "string"
|
||||
},
|
||||
"newPullRequestURL": {
|
||||
"description": "A URL that will create a new pull requeset for this branch",
|
||||
"type": "string"
|
||||
},
|
||||
"repositoryURL": {
|
||||
"description": "A URL pointing to the repository this lives in",
|
||||
"type": "string"
|
||||
},
|
||||
"sourceURL": {
|
||||
"description": "A URL pointing to the this file in the repository",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.ResourceWrapper": {
|
||||
"description": "This is a container type for any resource type",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"repository",
|
||||
"resource"
|
||||
],
|
||||
"properties": {
|
||||
@@ -3864,9 +3921,18 @@
|
||||
"type": "string"
|
||||
},
|
||||
"ref": {
|
||||
"description": "The commit hash (if exists)",
|
||||
"description": "The request ref (or branch if exists)",
|
||||
"type": "string"
|
||||
},
|
||||
"repository": {
|
||||
"description": "Basic repository info",
|
||||
"default": {},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.ResourceRepositoryInfo"
|
||||
}
|
||||
]
|
||||
},
|
||||
"resource": {
|
||||
"description": "Different flavors of the same object",
|
||||
"default": {},
|
||||
@@ -3883,6 +3949,14 @@
|
||||
"$ref": "#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.Time"
|
||||
}
|
||||
]
|
||||
},
|
||||
"urls": {
|
||||
"description": "Typed links for this file (only supported by external systems, github etc)",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.ResourceURLs"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"x-kubernetes-group-version-kind": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Alert, Icon, Stack } from '@grafana/ui';
|
||||
import { DashboardPageRouteSearchParams } from 'app/features/dashboard/containers/types';
|
||||
import { useGetRepositoryFilesWithPathQuery, useGetRepositoryQuery } from 'app/features/provisioning/api';
|
||||
import { useGetRepositoryFilesWithPathQuery } from 'app/features/provisioning/api';
|
||||
import { usePullRequestParam } from 'app/features/provisioning/hooks';
|
||||
import { DashboardRoutes } from 'app/types';
|
||||
|
||||
@@ -25,10 +25,6 @@ function DashboardPreviewBannerContent({ queryParams, slug, path }: DashboardPre
|
||||
const prParam = usePullRequestParam();
|
||||
const file = useGetRepositoryFilesWithPathQuery({ name: slug, path, ref: queryParams.ref });
|
||||
|
||||
// Required to create the new PR link
|
||||
// TODO?? can the relevant links be in the file response???
|
||||
const repo = useGetRepositoryQuery({ name: slug });
|
||||
|
||||
if (file.data?.errors) {
|
||||
return (
|
||||
<Alert title="Error loading dashboard" severity="error" style={{ flex: 0 }}>
|
||||
@@ -59,10 +55,8 @@ function DashboardPreviewBannerContent({ queryParams, slug, path }: DashboardPre
|
||||
}
|
||||
|
||||
// Check if this is a github link
|
||||
const githubSpec = repo.data?.spec?.type === 'github' ? repo.data.spec.github : undefined;
|
||||
if (queryParams.ref?.length && githubSpec) {
|
||||
const url = `${githubSpec.url}/compare/${githubSpec.branch}...${queryParams.ref}?quick_pull=1&labels=grafana`;
|
||||
|
||||
const githubURL = file.data?.urls?.newPullRequestURL ?? file.data?.urls?.compareURL;
|
||||
if (githubURL) {
|
||||
return (
|
||||
<Alert
|
||||
{...commonAlertProps}
|
||||
@@ -73,7 +67,7 @@ function DashboardPreviewBannerContent({ queryParams, slug, path }: DashboardPre
|
||||
<Icon name="external-link-alt" />
|
||||
</Stack>
|
||||
}
|
||||
onRemove={() => window.open(url, '_blank')}
|
||||
onRemove={() => window.open(githubURL, '_blank')}
|
||||
>
|
||||
The value is <strong>not yet</strong> saved in the grafana database
|
||||
</Alert>
|
||||
|
||||
@@ -738,16 +738,6 @@ export type ObjectMeta = {
|
||||
Populated by the system. Read-only. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids */
|
||||
uid?: string;
|
||||
};
|
||||
export type ExportJobOptions = {
|
||||
/** Target branch for export (only git) */
|
||||
branch?: string;
|
||||
/** The source folder (or empty) to export */
|
||||
folder?: string;
|
||||
/** Include the identifier in the exported metadata */
|
||||
identifier: boolean;
|
||||
/** Prefix in target file system */
|
||||
prefix?: string;
|
||||
};
|
||||
export type MigrateJobOptions = {
|
||||
/** Preserve history (if possible) */
|
||||
history?: boolean;
|
||||
@@ -769,23 +759,33 @@ export type SyncJobOptions = {
|
||||
/** Incremental synchronization for versioned repositories */
|
||||
incremental: boolean;
|
||||
};
|
||||
export type ExportJobOptions = {
|
||||
/** Target branch for export (only git) */
|
||||
branch?: string;
|
||||
/** The source folder (or empty) to export */
|
||||
folder?: string;
|
||||
/** Include the identifier in the exported metadata */
|
||||
identifier: boolean;
|
||||
/** Prefix in target file system */
|
||||
prefix?: string;
|
||||
};
|
||||
export type JobSpec = {
|
||||
/** Possible enum values:
|
||||
- `"export"` Export from grafana into the remote repository
|
||||
- `"migrate"` Migration task -- this will migrate an full instance from SQL > Git
|
||||
- `"pr"` Update a pull request -- send preview images, links etc
|
||||
- `"sync"` Sync the remote branch with the grafana instance */
|
||||
action: 'export' | 'migrate' | 'pr' | 'sync';
|
||||
/** Required when the action is `export` */
|
||||
export?: ExportJobOptions;
|
||||
- `"pr"` Process a pull request -- apply comments with preview images, links etc
|
||||
- `"pull"` Sync the remote branch with the grafana instance
|
||||
- `"push"` Export from grafana into the remote repository */
|
||||
action: 'migrate' | 'pr' | 'pull' | 'push';
|
||||
/** Required when the action is `migrate` */
|
||||
migrate?: MigrateJobOptions;
|
||||
/** Pull request options */
|
||||
pr?: PullRequestJobOptions;
|
||||
/** Required when the action is `pull` */
|
||||
pull?: SyncJobOptions;
|
||||
/** Required when the action is `push` */
|
||||
push?: ExportJobOptions;
|
||||
/** The the repository reference (for now also in labels) */
|
||||
repository: string;
|
||||
/** Required when the action is `sync` */
|
||||
sync?: SyncJobOptions;
|
||||
};
|
||||
export type JobResourceSummary = {
|
||||
create?: number;
|
||||
@@ -1034,6 +1034,20 @@ export type DeleteOptions = {
|
||||
/** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */
|
||||
propagationPolicy?: string;
|
||||
};
|
||||
export type ResourceRepositoryInfo = {
|
||||
/** The name (identifier) */
|
||||
name: string;
|
||||
/** The namespace this belongs to */
|
||||
namespace: string;
|
||||
/** The display name for this repository */
|
||||
title: string;
|
||||
/** The repository type
|
||||
|
||||
Possible enum values:
|
||||
- `"github"`
|
||||
- `"local"` */
|
||||
type: 'github' | 'local';
|
||||
};
|
||||
export type Unstructured = {
|
||||
[key: string]: any;
|
||||
};
|
||||
@@ -1068,6 +1082,16 @@ export type ResourceObjects = {
|
||||
/** The identified type for this object */
|
||||
type: ResourceType;
|
||||
};
|
||||
export type ResourceUrLs = {
|
||||
/** Compare this version to the target branch */
|
||||
compareURL?: string;
|
||||
/** A URL that will create a new pull requeset for this branch */
|
||||
newPullRequestURL?: string;
|
||||
/** A URL pointing to the repository this lives in */
|
||||
repositoryURL?: string;
|
||||
/** A URL pointing to the this file in the repository */
|
||||
sourceURL?: string;
|
||||
};
|
||||
export type ResourceWrapper = {
|
||||
/** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */
|
||||
apiVersion?: string;
|
||||
@@ -1079,12 +1103,16 @@ export type ResourceWrapper = {
|
||||
kind?: string;
|
||||
/** Path to the remote file */
|
||||
path?: string;
|
||||
/** The commit hash (if exists) */
|
||||
/** The request ref (or branch if exists) */
|
||||
ref?: string;
|
||||
/** Basic repository info */
|
||||
repository: ResourceRepositoryInfo;
|
||||
/** Different flavors of the same object */
|
||||
resource: ResourceObjects;
|
||||
/** The modified time in the remote file system */
|
||||
timestamp?: Time;
|
||||
/** Typed links for this file (only supported by external systems, github etc) */
|
||||
urls?: ResourceUrLs;
|
||||
};
|
||||
export type ResourceListItem = {
|
||||
folder?: string;
|
||||
|
||||
Reference in new issue
Block a user