Provisioning: Introduce Repository Factory with extras (#110018)
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
package github
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/logging"
|
||||
provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/repository"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/repository/git"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/webhooks"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
type extra struct {
|
||||
factory *Factory
|
||||
decrypter repository.Decrypter
|
||||
webhookBuilder *webhooks.WebhookExtraBuilder
|
||||
}
|
||||
|
||||
func Extra(decrypter repository.Decrypter, factory *Factory, webhookBuilder *webhooks.WebhookExtraBuilder) repository.Extra {
|
||||
return &extra{
|
||||
decrypter: decrypter,
|
||||
factory: factory,
|
||||
webhookBuilder: webhookBuilder,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *extra) Type() provisioning.RepositoryType {
|
||||
return provisioning.GitHubRepositoryType
|
||||
}
|
||||
|
||||
func (e *extra) Build(ctx context.Context, r *provisioning.Repository) (repository.Repository, error) {
|
||||
logger := logging.FromContext(ctx).With("url", r.Spec.GitHub.URL, "branch", r.Spec.GitHub.Branch, "path", r.Spec.GitHub.Path)
|
||||
logger.Info("Instantiating Github repository")
|
||||
|
||||
secure := e.decrypter(r)
|
||||
cfg := r.Spec.GitHub
|
||||
if cfg == nil {
|
||||
return nil, fmt.Errorf("github configuration is required")
|
||||
}
|
||||
|
||||
token, err := secure.Token(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to decrypt token: %w", err)
|
||||
}
|
||||
|
||||
gitRepo, err := git.NewRepository(ctx, r, git.RepositoryConfig{
|
||||
URL: cfg.URL,
|
||||
Branch: cfg.Branch,
|
||||
Path: cfg.Path,
|
||||
Token: token,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating git repository: %w", err)
|
||||
}
|
||||
|
||||
ghRepo, err := NewRepository(ctx, r, gitRepo, e.factory, token)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating github repository: %w", err)
|
||||
}
|
||||
|
||||
if e.webhookBuilder == nil {
|
||||
return ghRepo, nil
|
||||
}
|
||||
|
||||
webhookURL := e.webhookBuilder.WebhookURL(ctx, r)
|
||||
if len(webhookURL) == 0 {
|
||||
logger.Debug("Skipping webhook setup as no webhooks are not configured")
|
||||
return ghRepo, nil
|
||||
}
|
||||
|
||||
webhookSecret, err := secure.WebhookSecret(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decrypt webhookSecret: %w", err)
|
||||
}
|
||||
|
||||
return NewGithubWebhookRepository(ghRepo, webhookURL, webhookSecret), nil
|
||||
}
|
||||
|
||||
func (e *extra) Mutate(ctx context.Context, obj runtime.Object) error {
|
||||
return Mutate(ctx, obj)
|
||||
}
|
||||
@@ -7,29 +7,26 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/controller"
|
||||
)
|
||||
|
||||
func Mutator() controller.Mutator {
|
||||
return func(ctx context.Context, obj runtime.Object) error {
|
||||
repo, ok := obj.(*provisioning.Repository)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if repo.Spec.GitHub == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Trim trailing ".git" and any trailing slash from the GitHub URL, if present, using the strings package.
|
||||
if repo.Spec.GitHub.URL != "" {
|
||||
url := repo.Spec.GitHub.URL
|
||||
url = strings.TrimRight(url, "/")
|
||||
url = strings.TrimSuffix(url, ".git")
|
||||
url = strings.TrimRight(url, "/")
|
||||
repo.Spec.GitHub.URL = url
|
||||
}
|
||||
|
||||
func Mutate(ctx context.Context, obj runtime.Object) error {
|
||||
repo, ok := obj.(*provisioning.Repository)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if repo.Spec.GitHub == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Trim trailing ".git" and any trailing slash from the GitHub URL, if present, using the strings package.
|
||||
if repo.Spec.GitHub.URL != "" {
|
||||
url := repo.Spec.GitHub.URL
|
||||
url = strings.TrimRight(url, "/")
|
||||
url = strings.TrimSuffix(url, ".git")
|
||||
url = strings.TrimRight(url, "/")
|
||||
repo.Spec.GitHub.URL = url
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -106,9 +106,7 @@ func TestMutator(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mutator := Mutator()
|
||||
err := mutator(context.Background(), tt.obj)
|
||||
|
||||
err := Mutate(context.Background(), tt.obj)
|
||||
if tt.expectedError != "" {
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), tt.expectedError)
|
||||
|
||||
@@ -42,7 +42,7 @@ type GithubRepository interface {
|
||||
Client() Client
|
||||
}
|
||||
|
||||
func NewGitHub(
|
||||
func NewRepository(
|
||||
ctx context.Context,
|
||||
config *provisioning.Repository,
|
||||
gitRepo git.GitRepository,
|
||||
|
||||
@@ -82,7 +82,7 @@ func TestNewGitHub(t *testing.T) {
|
||||
gitRepo := git.NewMockGitRepository(t)
|
||||
|
||||
// Call the function under test
|
||||
repo, err := NewGitHub(
|
||||
repo, err := NewRepository(
|
||||
context.Background(),
|
||||
tt.config,
|
||||
gitRepo,
|
||||
|
||||
Vendored
+231
@@ -0,0 +1,231 @@
|
||||
{
|
||||
"action": "created",
|
||||
"issue": {
|
||||
"id": 2726065547,
|
||||
"number": 12,
|
||||
"state": "open",
|
||||
"locked": false,
|
||||
"title": "Webhook test PR",
|
||||
"author_association": "MEMBER",
|
||||
"user": {
|
||||
"login": "ryantxu",
|
||||
"id": 705951,
|
||||
"node_id": "MDQ6VXNlcjcwNTk1MQ==",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/705951?v=4",
|
||||
"html_url": "https://github.com/ryantxu",
|
||||
"gravatar_id": "",
|
||||
"type": "User",
|
||||
"site_admin": false,
|
||||
"url": "https://api.github.com/users/ryantxu",
|
||||
"events_url": "https://api.github.com/users/ryantxu/events{/privacy}",
|
||||
"following_url": "https://api.github.com/users/ryantxu/following{/other_user}",
|
||||
"followers_url": "https://api.github.com/users/ryantxu/followers",
|
||||
"gists_url": "https://api.github.com/users/ryantxu/gists{/gist_id}",
|
||||
"organizations_url": "https://api.github.com/users/ryantxu/orgs",
|
||||
"received_events_url": "https://api.github.com/users/ryantxu/received_events",
|
||||
"repos_url": "https://api.github.com/users/ryantxu/repos",
|
||||
"starred_url": "https://api.github.com/users/ryantxu/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ryantxu/subscriptions"
|
||||
},
|
||||
"comments": 1,
|
||||
"created_at": "2024-12-09T05:53:14Z",
|
||||
"updated_at": "2024-12-09T06:03:21Z",
|
||||
"url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/12",
|
||||
"html_url": "https://github.com/grafana/git-ui-sync-demo/pull/12",
|
||||
"comments_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/12/comments",
|
||||
"events_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/12/events",
|
||||
"labels_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/12/labels{/name}",
|
||||
"repository_url": "https://api.github.com/repos/grafana/git-ui-sync-demo",
|
||||
"pull_request": {
|
||||
"url": "https://api.github.com/repos/grafana/git-ui-sync-demo/pulls/12",
|
||||
"html_url": "https://github.com/grafana/git-ui-sync-demo/pull/12",
|
||||
"diff_url": "https://github.com/grafana/git-ui-sync-demo/pull/12.diff",
|
||||
"patch_url": "https://github.com/grafana/git-ui-sync-demo/pull/12.patch"
|
||||
},
|
||||
"reactions": {
|
||||
"total_count": 0,
|
||||
"+1": 0,
|
||||
"-1": 0,
|
||||
"laugh": 0,
|
||||
"confused": 0,
|
||||
"heart": 0,
|
||||
"hooray": 0,
|
||||
"rocket": 0,
|
||||
"eyes": 0,
|
||||
"url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/12/reactions"
|
||||
},
|
||||
"node_id": "PR_kwDONO4cS86EfDVR",
|
||||
"draft": false
|
||||
},
|
||||
"comment": {
|
||||
"id": 2527008082,
|
||||
"node_id": "IC_kwDONO4cS86WnxVS",
|
||||
"body": "comment in PR",
|
||||
"user": {
|
||||
"login": "ryantxu",
|
||||
"id": 705951,
|
||||
"node_id": "MDQ6VXNlcjcwNTk1MQ==",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/705951?v=4",
|
||||
"html_url": "https://github.com/ryantxu",
|
||||
"gravatar_id": "",
|
||||
"type": "User",
|
||||
"site_admin": false,
|
||||
"url": "https://api.github.com/users/ryantxu",
|
||||
"events_url": "https://api.github.com/users/ryantxu/events{/privacy}",
|
||||
"following_url": "https://api.github.com/users/ryantxu/following{/other_user}",
|
||||
"followers_url": "https://api.github.com/users/ryantxu/followers",
|
||||
"gists_url": "https://api.github.com/users/ryantxu/gists{/gist_id}",
|
||||
"organizations_url": "https://api.github.com/users/ryantxu/orgs",
|
||||
"received_events_url": "https://api.github.com/users/ryantxu/received_events",
|
||||
"repos_url": "https://api.github.com/users/ryantxu/repos",
|
||||
"starred_url": "https://api.github.com/users/ryantxu/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ryantxu/subscriptions"
|
||||
},
|
||||
"reactions": {
|
||||
"total_count": 0,
|
||||
"+1": 0,
|
||||
"-1": 0,
|
||||
"laugh": 0,
|
||||
"confused": 0,
|
||||
"heart": 0,
|
||||
"hooray": 0,
|
||||
"rocket": 0,
|
||||
"eyes": 0,
|
||||
"url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/comments/2527008082/reactions"
|
||||
},
|
||||
"created_at": "2024-12-09T06:03:19Z",
|
||||
"updated_at": "2024-12-09T06:03:19Z",
|
||||
"author_association": "MEMBER",
|
||||
"url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/comments/2527008082",
|
||||
"html_url": "https://github.com/grafana/git-ui-sync-demo/pull/12#issuecomment-2527008082",
|
||||
"issue_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/12"
|
||||
},
|
||||
"repository": {
|
||||
"id": 888020043,
|
||||
"node_id": "R_kgDONO4cSw",
|
||||
"owner": {
|
||||
"login": "grafana",
|
||||
"id": 7195757,
|
||||
"node_id": "MDEyOk9yZ2FuaXphdGlvbjcxOTU3NTc=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7195757?v=4",
|
||||
"html_url": "https://github.com/grafana",
|
||||
"gravatar_id": "",
|
||||
"type": "Organization",
|
||||
"site_admin": false,
|
||||
"url": "https://api.github.com/users/grafana",
|
||||
"events_url": "https://api.github.com/users/grafana/events{/privacy}",
|
||||
"following_url": "https://api.github.com/users/grafana/following{/other_user}",
|
||||
"followers_url": "https://api.github.com/users/grafana/followers",
|
||||
"gists_url": "https://api.github.com/users/grafana/gists{/gist_id}",
|
||||
"organizations_url": "https://api.github.com/users/grafana/orgs",
|
||||
"received_events_url": "https://api.github.com/users/grafana/received_events",
|
||||
"repos_url": "https://api.github.com/users/grafana/repos",
|
||||
"starred_url": "https://api.github.com/users/grafana/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/grafana/subscriptions"
|
||||
},
|
||||
"name": "git-ui-sync-demo",
|
||||
"full_name": "grafana/git-ui-sync-demo",
|
||||
"description": "A repository containing Grafana dashboards to demo the Github Sync feature in Grafana.",
|
||||
"default_branch": "main",
|
||||
"created_at": "2024-11-13T17:13:33Z",
|
||||
"pushed_at": "2024-12-09T05:58:00Z",
|
||||
"updated_at": "2024-12-09T05:58:03Z",
|
||||
"html_url": "https://github.com/grafana/git-ui-sync-demo",
|
||||
"clone_url": "https://github.com/grafana/git-ui-sync-demo.git",
|
||||
"git_url": "git://github.com/grafana/git-ui-sync-demo.git",
|
||||
"ssh_url": "git@github.com:grafana/git-ui-sync-demo.git",
|
||||
"svn_url": "https://github.com/grafana/git-ui-sync-demo",
|
||||
"fork": false,
|
||||
"forks_count": 0,
|
||||
"open_issues_count": 9,
|
||||
"open_issues": 9,
|
||||
"stargazers_count": 0,
|
||||
"watchers_count": 0,
|
||||
"watchers": 0,
|
||||
"size": 141,
|
||||
"allow_forking": false,
|
||||
"web_commit_signoff_required": false,
|
||||
"archived": false,
|
||||
"disabled": false,
|
||||
"private": true,
|
||||
"has_issues": true,
|
||||
"has_wiki": true,
|
||||
"has_pages": false,
|
||||
"has_projects": true,
|
||||
"has_downloads": true,
|
||||
"has_discussions": false,
|
||||
"is_template": false,
|
||||
"url": "https://api.github.com/repos/grafana/git-ui-sync-demo",
|
||||
"archive_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/{archive_format}{/ref}",
|
||||
"assignees_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/assignees{/user}",
|
||||
"blobs_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/blobs{/sha}",
|
||||
"branches_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/branches{/branch}",
|
||||
"collaborators_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/collaborators{/collaborator}",
|
||||
"comments_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/comments{/number}",
|
||||
"commits_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/commits{/sha}",
|
||||
"compare_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/compare/{base}...{head}",
|
||||
"contents_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/contents/{+path}",
|
||||
"contributors_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/contributors",
|
||||
"deployments_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/deployments",
|
||||
"downloads_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/downloads",
|
||||
"events_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/events",
|
||||
"forks_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/forks",
|
||||
"git_commits_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/commits{/sha}",
|
||||
"git_refs_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/refs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/tags{/sha}",
|
||||
"hooks_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/hooks",
|
||||
"issue_comment_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/comments{/number}",
|
||||
"issue_events_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/events{/number}",
|
||||
"issues_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues{/number}",
|
||||
"keys_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/keys{/key_id}",
|
||||
"labels_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/labels{/name}",
|
||||
"languages_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/languages",
|
||||
"merges_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/merges",
|
||||
"milestones_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/milestones{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/notifications{?since,all,participating}",
|
||||
"pulls_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/pulls{/number}",
|
||||
"releases_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/releases{/id}",
|
||||
"stargazers_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/stargazers",
|
||||
"statuses_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/statuses/{sha}",
|
||||
"subscribers_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/subscribers",
|
||||
"subscription_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/subscription",
|
||||
"tags_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/tags",
|
||||
"trees_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/trees{/sha}",
|
||||
"teams_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/teams",
|
||||
"visibility": "internal"
|
||||
},
|
||||
"sender": {
|
||||
"login": "ryantxu",
|
||||
"id": 705951,
|
||||
"node_id": "MDQ6VXNlcjcwNTk1MQ==",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/705951?v=4",
|
||||
"html_url": "https://github.com/ryantxu",
|
||||
"gravatar_id": "",
|
||||
"type": "User",
|
||||
"site_admin": false,
|
||||
"url": "https://api.github.com/users/ryantxu",
|
||||
"events_url": "https://api.github.com/users/ryantxu/events{/privacy}",
|
||||
"following_url": "https://api.github.com/users/ryantxu/following{/other_user}",
|
||||
"followers_url": "https://api.github.com/users/ryantxu/followers",
|
||||
"gists_url": "https://api.github.com/users/ryantxu/gists{/gist_id}",
|
||||
"organizations_url": "https://api.github.com/users/ryantxu/orgs",
|
||||
"received_events_url": "https://api.github.com/users/ryantxu/received_events",
|
||||
"repos_url": "https://api.github.com/users/ryantxu/repos",
|
||||
"starred_url": "https://api.github.com/users/ryantxu/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ryantxu/subscriptions"
|
||||
},
|
||||
"organization": {
|
||||
"login": "grafana",
|
||||
"id": 7195757,
|
||||
"node_id": "MDEyOk9yZ2FuaXphdGlvbjcxOTU3NTc=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7195757?v=4",
|
||||
"description": "Grafana Labs is behind leading open source projects Grafana and Loki, and the creator of the first open \u0026 composable observability platform.",
|
||||
"url": "https://api.github.com/orgs/grafana",
|
||||
"events_url": "https://api.github.com/orgs/grafana/events",
|
||||
"hooks_url": "https://api.github.com/orgs/grafana/hooks",
|
||||
"issues_url": "https://api.github.com/orgs/grafana/issues",
|
||||
"members_url": "https://api.github.com/orgs/grafana/members{/member}",
|
||||
"public_members_url": "https://api.github.com/orgs/grafana/public_members{/member}",
|
||||
"repos_url": "https://api.github.com/orgs/grafana/repos"
|
||||
}
|
||||
}
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
{
|
||||
"zen": "Keep it logically awesome.",
|
||||
"hook_id": 517704995,
|
||||
"hook": {
|
||||
"created_at": "2024-12-09T05:44:20Z",
|
||||
"updated_at": "2024-12-09T05:44:20Z",
|
||||
"url": "https://api.github.com/repos/grafana/git-ui-sync-demo/hooks/517704995",
|
||||
"id": 517704995,
|
||||
"type": "Repository",
|
||||
"name": "web",
|
||||
"test_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/hooks/517704995/test",
|
||||
"ping_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/hooks/517704995/pings",
|
||||
"last_response": {
|
||||
"code": null,
|
||||
"message": null,
|
||||
"status": "unused"
|
||||
},
|
||||
"config": {
|
||||
"content_type": "form",
|
||||
"insecure_ssl": "0",
|
||||
"url": "https://0b71-216-128-0-90.ngrok-free.app/apis/provisioning.grafana.app/v0alpha1/namespaces/default/repositories/github-example-ryan/webhook",
|
||||
"secret": "********"
|
||||
},
|
||||
"events": [
|
||||
"*"
|
||||
],
|
||||
"active": true
|
||||
},
|
||||
"repository": {
|
||||
"id": 888020043,
|
||||
"node_id": "R_kgDONO4cSw",
|
||||
"owner": {
|
||||
"login": "grafana",
|
||||
"id": 7195757,
|
||||
"node_id": "MDEyOk9yZ2FuaXphdGlvbjcxOTU3NTc=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7195757?v=4",
|
||||
"html_url": "https://github.com/grafana",
|
||||
"gravatar_id": "",
|
||||
"type": "Organization",
|
||||
"site_admin": false,
|
||||
"url": "https://api.github.com/users/grafana",
|
||||
"events_url": "https://api.github.com/users/grafana/events{/privacy}",
|
||||
"following_url": "https://api.github.com/users/grafana/following{/other_user}",
|
||||
"followers_url": "https://api.github.com/users/grafana/followers",
|
||||
"gists_url": "https://api.github.com/users/grafana/gists{/gist_id}",
|
||||
"organizations_url": "https://api.github.com/users/grafana/orgs",
|
||||
"received_events_url": "https://api.github.com/users/grafana/received_events",
|
||||
"repos_url": "https://api.github.com/users/grafana/repos",
|
||||
"starred_url": "https://api.github.com/users/grafana/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/grafana/subscriptions"
|
||||
},
|
||||
"name": "git-ui-sync-demo",
|
||||
"full_name": "grafana/git-ui-sync-demo",
|
||||
"description": "A repository containing Grafana dashboards to demo the Github Sync feature in Grafana.",
|
||||
"default_branch": "main",
|
||||
"created_at": "2024-11-13T17:13:33Z",
|
||||
"pushed_at": "2024-12-08T10:51:24Z",
|
||||
"updated_at": "2024-11-28T12:53:26Z",
|
||||
"html_url": "https://github.com/grafana/git-ui-sync-demo",
|
||||
"clone_url": "https://github.com/grafana/git-ui-sync-demo.git",
|
||||
"git_url": "git://github.com/grafana/git-ui-sync-demo.git",
|
||||
"ssh_url": "git@github.com:grafana/git-ui-sync-demo.git",
|
||||
"svn_url": "https://github.com/grafana/git-ui-sync-demo",
|
||||
"fork": false,
|
||||
"forks_count": 0,
|
||||
"open_issues_count": 8,
|
||||
"open_issues": 8,
|
||||
"stargazers_count": 0,
|
||||
"watchers_count": 0,
|
||||
"watchers": 0,
|
||||
"size": 141,
|
||||
"allow_forking": false,
|
||||
"web_commit_signoff_required": false,
|
||||
"archived": false,
|
||||
"disabled": false,
|
||||
"private": true,
|
||||
"has_issues": true,
|
||||
"has_wiki": true,
|
||||
"has_pages": false,
|
||||
"has_projects": true,
|
||||
"has_downloads": true,
|
||||
"has_discussions": false,
|
||||
"is_template": false,
|
||||
"url": "https://api.github.com/repos/grafana/git-ui-sync-demo",
|
||||
"archive_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/{archive_format}{/ref}",
|
||||
"assignees_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/assignees{/user}",
|
||||
"blobs_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/blobs{/sha}",
|
||||
"branches_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/branches{/branch}",
|
||||
"collaborators_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/collaborators{/collaborator}",
|
||||
"comments_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/comments{/number}",
|
||||
"commits_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/commits{/sha}",
|
||||
"compare_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/compare/{base}...{head}",
|
||||
"contents_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/contents/{+path}",
|
||||
"contributors_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/contributors",
|
||||
"deployments_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/deployments",
|
||||
"downloads_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/downloads",
|
||||
"events_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/events",
|
||||
"forks_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/forks",
|
||||
"git_commits_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/commits{/sha}",
|
||||
"git_refs_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/refs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/tags{/sha}",
|
||||
"hooks_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/hooks",
|
||||
"issue_comment_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/comments{/number}",
|
||||
"issue_events_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/events{/number}",
|
||||
"issues_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues{/number}",
|
||||
"keys_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/keys{/key_id}",
|
||||
"labels_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/labels{/name}",
|
||||
"languages_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/languages",
|
||||
"merges_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/merges",
|
||||
"milestones_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/milestones{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/notifications{?since,all,participating}",
|
||||
"pulls_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/pulls{/number}",
|
||||
"releases_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/releases{/id}",
|
||||
"stargazers_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/stargazers",
|
||||
"statuses_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/statuses/{sha}",
|
||||
"subscribers_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/subscribers",
|
||||
"subscription_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/subscription",
|
||||
"tags_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/tags",
|
||||
"trees_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/trees{/sha}",
|
||||
"teams_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/teams",
|
||||
"visibility": "internal"
|
||||
},
|
||||
"sender": {
|
||||
"login": "ryantxu",
|
||||
"id": 705951,
|
||||
"node_id": "MDQ6VXNlcjcwNTk1MQ==",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/705951?v=4",
|
||||
"html_url": "https://github.com/ryantxu",
|
||||
"gravatar_id": "",
|
||||
"type": "User",
|
||||
"site_admin": false,
|
||||
"url": "https://api.github.com/users/ryantxu",
|
||||
"events_url": "https://api.github.com/users/ryantxu/events{/privacy}",
|
||||
"following_url": "https://api.github.com/users/ryantxu/following{/other_user}",
|
||||
"followers_url": "https://api.github.com/users/ryantxu/followers",
|
||||
"gists_url": "https://api.github.com/users/ryantxu/gists{/gist_id}",
|
||||
"organizations_url": "https://api.github.com/users/ryantxu/orgs",
|
||||
"received_events_url": "https://api.github.com/users/ryantxu/received_events",
|
||||
"repos_url": "https://api.github.com/users/ryantxu/repos",
|
||||
"starred_url": "https://api.github.com/users/ryantxu/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ryantxu/subscriptions"
|
||||
}
|
||||
}
|
||||
+470
@@ -0,0 +1,470 @@
|
||||
|
||||
{
|
||||
"action": "opened",
|
||||
"number": 12,
|
||||
"pull_request": {
|
||||
"id": 2222732625,
|
||||
"number": 12,
|
||||
"state": "open",
|
||||
"locked": false,
|
||||
"title": "Webhook test PR",
|
||||
"created_at": "2024-12-09T05:53:14Z",
|
||||
"updated_at": "2024-12-09T05:53:14Z",
|
||||
"user": {
|
||||
"login": "ryantxu",
|
||||
"id": 705951,
|
||||
"node_id": "MDQ6VXNlcjcwNTk1MQ==",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/705951?v=4",
|
||||
"html_url": "https://github.com/ryantxu",
|
||||
"gravatar_id": "",
|
||||
"type": "User",
|
||||
"site_admin": false,
|
||||
"url": "https://api.github.com/users/ryantxu",
|
||||
"events_url": "https://api.github.com/users/ryantxu/events{/privacy}",
|
||||
"following_url": "https://api.github.com/users/ryantxu/following{/other_user}",
|
||||
"followers_url": "https://api.github.com/users/ryantxu/followers",
|
||||
"gists_url": "https://api.github.com/users/ryantxu/gists{/gist_id}",
|
||||
"organizations_url": "https://api.github.com/users/ryantxu/orgs",
|
||||
"received_events_url": "https://api.github.com/users/ryantxu/received_events",
|
||||
"repos_url": "https://api.github.com/users/ryantxu/repos",
|
||||
"starred_url": "https://api.github.com/users/ryantxu/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ryantxu/subscriptions"
|
||||
},
|
||||
"draft": false,
|
||||
"merged": false,
|
||||
"mergeable_state": "unknown",
|
||||
"comments": 0,
|
||||
"commits": 1,
|
||||
"additions": 1,
|
||||
"deletions": 0,
|
||||
"changed_files": 1,
|
||||
"url": "https://api.github.com/repos/grafana/git-ui-sync-demo/pulls/12",
|
||||
"html_url": "https://github.com/grafana/git-ui-sync-demo/pull/12",
|
||||
"issue_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/12",
|
||||
"statuses_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/statuses/ab5446a53df9e5f8bdeed52250f51fad08e822bc",
|
||||
"diff_url": "https://github.com/grafana/git-ui-sync-demo/pull/12.diff",
|
||||
"patch_url": "https://github.com/grafana/git-ui-sync-demo/pull/12.patch",
|
||||
"commits_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/pulls/12/commits",
|
||||
"comments_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/12/comments",
|
||||
"review_comments_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/pulls/12/comments",
|
||||
"review_comment_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/pulls/comments{/number}",
|
||||
"review_comments": 0,
|
||||
"maintainer_can_modify": false,
|
||||
"author_association": "MEMBER",
|
||||
"node_id": "PR_kwDONO4cS86EfDVR",
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "https://api.github.com/repos/grafana/git-ui-sync-demo/pulls/12"
|
||||
},
|
||||
"html": {
|
||||
"href": "https://github.com/grafana/git-ui-sync-demo/pull/12"
|
||||
},
|
||||
"issue": {
|
||||
"href": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/12"
|
||||
},
|
||||
"comments": {
|
||||
"href": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/12/comments"
|
||||
},
|
||||
"review_comments": {
|
||||
"href": "https://api.github.com/repos/grafana/git-ui-sync-demo/pulls/12/comments"
|
||||
},
|
||||
"review_comment": {
|
||||
"href": "https://api.github.com/repos/grafana/git-ui-sync-demo/pulls/comments{/number}"
|
||||
},
|
||||
"commits": {
|
||||
"href": "https://api.github.com/repos/grafana/git-ui-sync-demo/pulls/12/commits"
|
||||
},
|
||||
"statuses": {
|
||||
"href": "https://api.github.com/repos/grafana/git-ui-sync-demo/statuses/ab5446a53df9e5f8bdeed52250f51fad08e822bc"
|
||||
}
|
||||
},
|
||||
"head": {
|
||||
"label": "grafana:dashboard/1733653266690",
|
||||
"ref": "dashboard/1733653266690",
|
||||
"sha": "ab5446a53df9e5f8bdeed52250f51fad08e822bc",
|
||||
"repo": {
|
||||
"id": 888020043,
|
||||
"node_id": "R_kgDONO4cSw",
|
||||
"owner": {
|
||||
"login": "grafana",
|
||||
"id": 7195757,
|
||||
"node_id": "MDEyOk9yZ2FuaXphdGlvbjcxOTU3NTc=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7195757?v=4",
|
||||
"html_url": "https://github.com/grafana",
|
||||
"gravatar_id": "",
|
||||
"type": "Organization",
|
||||
"site_admin": false,
|
||||
"url": "https://api.github.com/users/grafana",
|
||||
"events_url": "https://api.github.com/users/grafana/events{/privacy}",
|
||||
"following_url": "https://api.github.com/users/grafana/following{/other_user}",
|
||||
"followers_url": "https://api.github.com/users/grafana/followers",
|
||||
"gists_url": "https://api.github.com/users/grafana/gists{/gist_id}",
|
||||
"organizations_url": "https://api.github.com/users/grafana/orgs",
|
||||
"received_events_url": "https://api.github.com/users/grafana/received_events",
|
||||
"repos_url": "https://api.github.com/users/grafana/repos",
|
||||
"starred_url": "https://api.github.com/users/grafana/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/grafana/subscriptions"
|
||||
},
|
||||
"name": "git-ui-sync-demo",
|
||||
"full_name": "grafana/git-ui-sync-demo",
|
||||
"description": "A repository containing Grafana dashboards to demo the Github Sync feature in Grafana.",
|
||||
"default_branch": "main",
|
||||
"created_at": "2024-11-13T17:13:33Z",
|
||||
"pushed_at": "2024-12-08T10:51:24Z",
|
||||
"updated_at": "2024-11-28T12:53:26Z",
|
||||
"html_url": "https://github.com/grafana/git-ui-sync-demo",
|
||||
"clone_url": "https://github.com/grafana/git-ui-sync-demo.git",
|
||||
"git_url": "git://github.com/grafana/git-ui-sync-demo.git",
|
||||
"ssh_url": "git@github.com:grafana/git-ui-sync-demo.git",
|
||||
"svn_url": "https://github.com/grafana/git-ui-sync-demo",
|
||||
"fork": false,
|
||||
"forks_count": 0,
|
||||
"open_issues_count": 9,
|
||||
"open_issues": 9,
|
||||
"stargazers_count": 0,
|
||||
"watchers_count": 0,
|
||||
"watchers": 0,
|
||||
"size": 141,
|
||||
"allow_rebase_merge": true,
|
||||
"allow_update_branch": false,
|
||||
"allow_squash_merge": true,
|
||||
"allow_merge_commit": true,
|
||||
"allow_auto_merge": false,
|
||||
"allow_forking": false,
|
||||
"web_commit_signoff_required": false,
|
||||
"delete_branch_on_merge": false,
|
||||
"use_squash_pr_title_as_default": false,
|
||||
"squash_merge_commit_title": "COMMIT_OR_PR_TITLE",
|
||||
"squash_merge_commit_message": "COMMIT_MESSAGES",
|
||||
"merge_commit_title": "MERGE_MESSAGE",
|
||||
"merge_commit_message": "PR_TITLE",
|
||||
"archived": false,
|
||||
"disabled": false,
|
||||
"private": true,
|
||||
"has_issues": true,
|
||||
"has_wiki": true,
|
||||
"has_pages": false,
|
||||
"has_projects": true,
|
||||
"has_downloads": true,
|
||||
"has_discussions": false,
|
||||
"is_template": false,
|
||||
"url": "https://api.github.com/repos/grafana/git-ui-sync-demo",
|
||||
"archive_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/{archive_format}{/ref}",
|
||||
"assignees_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/assignees{/user}",
|
||||
"blobs_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/blobs{/sha}",
|
||||
"branches_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/branches{/branch}",
|
||||
"collaborators_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/collaborators{/collaborator}",
|
||||
"comments_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/comments{/number}",
|
||||
"commits_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/commits{/sha}",
|
||||
"compare_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/compare/{base}...{head}",
|
||||
"contents_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/contents/{+path}",
|
||||
"contributors_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/contributors",
|
||||
"deployments_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/deployments",
|
||||
"downloads_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/downloads",
|
||||
"events_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/events",
|
||||
"forks_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/forks",
|
||||
"git_commits_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/commits{/sha}",
|
||||
"git_refs_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/refs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/tags{/sha}",
|
||||
"hooks_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/hooks",
|
||||
"issue_comment_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/comments{/number}",
|
||||
"issue_events_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/events{/number}",
|
||||
"issues_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues{/number}",
|
||||
"keys_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/keys{/key_id}",
|
||||
"labels_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/labels{/name}",
|
||||
"languages_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/languages",
|
||||
"merges_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/merges",
|
||||
"milestones_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/milestones{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/notifications{?since,all,participating}",
|
||||
"pulls_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/pulls{/number}",
|
||||
"releases_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/releases{/id}",
|
||||
"stargazers_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/stargazers",
|
||||
"statuses_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/statuses/{sha}",
|
||||
"subscribers_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/subscribers",
|
||||
"subscription_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/subscription",
|
||||
"tags_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/tags",
|
||||
"trees_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/trees{/sha}",
|
||||
"teams_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/teams",
|
||||
"visibility": "internal"
|
||||
},
|
||||
"user": {
|
||||
"login": "grafana",
|
||||
"id": 7195757,
|
||||
"node_id": "MDEyOk9yZ2FuaXphdGlvbjcxOTU3NTc=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7195757?v=4",
|
||||
"html_url": "https://github.com/grafana",
|
||||
"gravatar_id": "",
|
||||
"type": "Organization",
|
||||
"site_admin": false,
|
||||
"url": "https://api.github.com/users/grafana",
|
||||
"events_url": "https://api.github.com/users/grafana/events{/privacy}",
|
||||
"following_url": "https://api.github.com/users/grafana/following{/other_user}",
|
||||
"followers_url": "https://api.github.com/users/grafana/followers",
|
||||
"gists_url": "https://api.github.com/users/grafana/gists{/gist_id}",
|
||||
"organizations_url": "https://api.github.com/users/grafana/orgs",
|
||||
"received_events_url": "https://api.github.com/users/grafana/received_events",
|
||||
"repos_url": "https://api.github.com/users/grafana/repos",
|
||||
"starred_url": "https://api.github.com/users/grafana/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/grafana/subscriptions"
|
||||
}
|
||||
},
|
||||
"base": {
|
||||
"label": "grafana:main",
|
||||
"ref": "main",
|
||||
"sha": "6c86a0cdfd220c2fe3518cfaa4a4babf030d9a7a",
|
||||
"repo": {
|
||||
"id": 888020043,
|
||||
"node_id": "R_kgDONO4cSw",
|
||||
"owner": {
|
||||
"login": "grafana",
|
||||
"id": 7195757,
|
||||
"node_id": "MDEyOk9yZ2FuaXphdGlvbjcxOTU3NTc=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7195757?v=4",
|
||||
"html_url": "https://github.com/grafana",
|
||||
"gravatar_id": "",
|
||||
"type": "Organization",
|
||||
"site_admin": false,
|
||||
"url": "https://api.github.com/users/grafana",
|
||||
"events_url": "https://api.github.com/users/grafana/events{/privacy}",
|
||||
"following_url": "https://api.github.com/users/grafana/following{/other_user}",
|
||||
"followers_url": "https://api.github.com/users/grafana/followers",
|
||||
"gists_url": "https://api.github.com/users/grafana/gists{/gist_id}",
|
||||
"organizations_url": "https://api.github.com/users/grafana/orgs",
|
||||
"received_events_url": "https://api.github.com/users/grafana/received_events",
|
||||
"repos_url": "https://api.github.com/users/grafana/repos",
|
||||
"starred_url": "https://api.github.com/users/grafana/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/grafana/subscriptions"
|
||||
},
|
||||
"name": "git-ui-sync-demo",
|
||||
"full_name": "grafana/git-ui-sync-demo",
|
||||
"description": "A repository containing Grafana dashboards to demo the Github Sync feature in Grafana.",
|
||||
"default_branch": "main",
|
||||
"created_at": "2024-11-13T17:13:33Z",
|
||||
"pushed_at": "2024-12-08T10:51:24Z",
|
||||
"updated_at": "2024-11-28T12:53:26Z",
|
||||
"html_url": "https://github.com/grafana/git-ui-sync-demo",
|
||||
"clone_url": "https://github.com/grafana/git-ui-sync-demo.git",
|
||||
"git_url": "git://github.com/grafana/git-ui-sync-demo.git",
|
||||
"ssh_url": "git@github.com:grafana/git-ui-sync-demo.git",
|
||||
"svn_url": "https://github.com/grafana/git-ui-sync-demo",
|
||||
"fork": false,
|
||||
"forks_count": 0,
|
||||
"open_issues_count": 9,
|
||||
"open_issues": 9,
|
||||
"stargazers_count": 0,
|
||||
"watchers_count": 0,
|
||||
"watchers": 0,
|
||||
"size": 141,
|
||||
"allow_rebase_merge": true,
|
||||
"allow_update_branch": false,
|
||||
"allow_squash_merge": true,
|
||||
"allow_merge_commit": true,
|
||||
"allow_auto_merge": false,
|
||||
"allow_forking": false,
|
||||
"web_commit_signoff_required": false,
|
||||
"delete_branch_on_merge": false,
|
||||
"use_squash_pr_title_as_default": false,
|
||||
"squash_merge_commit_title": "COMMIT_OR_PR_TITLE",
|
||||
"squash_merge_commit_message": "COMMIT_MESSAGES",
|
||||
"merge_commit_title": "MERGE_MESSAGE",
|
||||
"merge_commit_message": "PR_TITLE",
|
||||
"archived": false,
|
||||
"disabled": false,
|
||||
"private": true,
|
||||
"has_issues": true,
|
||||
"has_wiki": true,
|
||||
"has_pages": false,
|
||||
"has_projects": true,
|
||||
"has_downloads": true,
|
||||
"has_discussions": false,
|
||||
"is_template": false,
|
||||
"url": "https://api.github.com/repos/grafana/git-ui-sync-demo",
|
||||
"archive_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/{archive_format}{/ref}",
|
||||
"assignees_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/assignees{/user}",
|
||||
"blobs_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/blobs{/sha}",
|
||||
"branches_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/branches{/branch}",
|
||||
"collaborators_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/collaborators{/collaborator}",
|
||||
"comments_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/comments{/number}",
|
||||
"commits_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/commits{/sha}",
|
||||
"compare_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/compare/{base}...{head}",
|
||||
"contents_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/contents/{+path}",
|
||||
"contributors_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/contributors",
|
||||
"deployments_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/deployments",
|
||||
"downloads_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/downloads",
|
||||
"events_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/events",
|
||||
"forks_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/forks",
|
||||
"git_commits_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/commits{/sha}",
|
||||
"git_refs_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/refs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/tags{/sha}",
|
||||
"hooks_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/hooks",
|
||||
"issue_comment_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/comments{/number}",
|
||||
"issue_events_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/events{/number}",
|
||||
"issues_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues{/number}",
|
||||
"keys_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/keys{/key_id}",
|
||||
"labels_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/labels{/name}",
|
||||
"languages_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/languages",
|
||||
"merges_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/merges",
|
||||
"milestones_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/milestones{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/notifications{?since,all,participating}",
|
||||
"pulls_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/pulls{/number}",
|
||||
"releases_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/releases{/id}",
|
||||
"stargazers_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/stargazers",
|
||||
"statuses_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/statuses/{sha}",
|
||||
"subscribers_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/subscribers",
|
||||
"subscription_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/subscription",
|
||||
"tags_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/tags",
|
||||
"trees_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/trees{/sha}",
|
||||
"teams_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/teams",
|
||||
"visibility": "internal"
|
||||
},
|
||||
"user": {
|
||||
"login": "grafana",
|
||||
"id": 7195757,
|
||||
"node_id": "MDEyOk9yZ2FuaXphdGlvbjcxOTU3NTc=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7195757?v=4",
|
||||
"html_url": "https://github.com/grafana",
|
||||
"gravatar_id": "",
|
||||
"type": "Organization",
|
||||
"site_admin": false,
|
||||
"url": "https://api.github.com/users/grafana",
|
||||
"events_url": "https://api.github.com/users/grafana/events{/privacy}",
|
||||
"following_url": "https://api.github.com/users/grafana/following{/other_user}",
|
||||
"followers_url": "https://api.github.com/users/grafana/followers",
|
||||
"gists_url": "https://api.github.com/users/grafana/gists{/gist_id}",
|
||||
"organizations_url": "https://api.github.com/users/grafana/orgs",
|
||||
"received_events_url": "https://api.github.com/users/grafana/received_events",
|
||||
"repos_url": "https://api.github.com/users/grafana/repos",
|
||||
"starred_url": "https://api.github.com/users/grafana/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/grafana/subscriptions"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"id": 888020043,
|
||||
"node_id": "R_kgDONO4cSw",
|
||||
"owner": {
|
||||
"login": "grafana",
|
||||
"id": 7195757,
|
||||
"node_id": "MDEyOk9yZ2FuaXphdGlvbjcxOTU3NTc=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7195757?v=4",
|
||||
"html_url": "https://github.com/grafana",
|
||||
"gravatar_id": "",
|
||||
"type": "Organization",
|
||||
"site_admin": false,
|
||||
"url": "https://api.github.com/users/grafana",
|
||||
"events_url": "https://api.github.com/users/grafana/events{/privacy}",
|
||||
"following_url": "https://api.github.com/users/grafana/following{/other_user}",
|
||||
"followers_url": "https://api.github.com/users/grafana/followers",
|
||||
"gists_url": "https://api.github.com/users/grafana/gists{/gist_id}",
|
||||
"organizations_url": "https://api.github.com/users/grafana/orgs",
|
||||
"received_events_url": "https://api.github.com/users/grafana/received_events",
|
||||
"repos_url": "https://api.github.com/users/grafana/repos",
|
||||
"starred_url": "https://api.github.com/users/grafana/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/grafana/subscriptions"
|
||||
},
|
||||
"name": "git-ui-sync-demo",
|
||||
"full_name": "grafana/git-ui-sync-demo",
|
||||
"description": "A repository containing Grafana dashboards to demo the Github Sync feature in Grafana.",
|
||||
"default_branch": "main",
|
||||
"created_at": "2024-11-13T17:13:33Z",
|
||||
"pushed_at": "2024-12-08T10:51:24Z",
|
||||
"updated_at": "2024-11-28T12:53:26Z",
|
||||
"html_url": "https://github.com/grafana/git-ui-sync-demo",
|
||||
"clone_url": "https://github.com/grafana/git-ui-sync-demo.git",
|
||||
"git_url": "git://github.com/grafana/git-ui-sync-demo.git",
|
||||
"ssh_url": "git@github.com:grafana/git-ui-sync-demo.git",
|
||||
"svn_url": "https://github.com/grafana/git-ui-sync-demo",
|
||||
"fork": false,
|
||||
"forks_count": 0,
|
||||
"open_issues_count": 9,
|
||||
"open_issues": 9,
|
||||
"stargazers_count": 0,
|
||||
"watchers_count": 0,
|
||||
"watchers": 0,
|
||||
"size": 141,
|
||||
"allow_forking": false,
|
||||
"web_commit_signoff_required": false,
|
||||
"archived": false,
|
||||
"disabled": false,
|
||||
"private": true,
|
||||
"has_issues": true,
|
||||
"has_wiki": true,
|
||||
"has_pages": false,
|
||||
"has_projects": true,
|
||||
"has_downloads": true,
|
||||
"has_discussions": false,
|
||||
"is_template": false,
|
||||
"url": "https://api.github.com/repos/grafana/git-ui-sync-demo",
|
||||
"archive_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/{archive_format}{/ref}",
|
||||
"assignees_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/assignees{/user}",
|
||||
"blobs_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/blobs{/sha}",
|
||||
"branches_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/branches{/branch}",
|
||||
"collaborators_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/collaborators{/collaborator}",
|
||||
"comments_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/comments{/number}",
|
||||
"commits_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/commits{/sha}",
|
||||
"compare_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/compare/{base}...{head}",
|
||||
"contents_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/contents/{+path}",
|
||||
"contributors_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/contributors",
|
||||
"deployments_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/deployments",
|
||||
"downloads_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/downloads",
|
||||
"events_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/events",
|
||||
"forks_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/forks",
|
||||
"git_commits_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/commits{/sha}",
|
||||
"git_refs_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/refs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/tags{/sha}",
|
||||
"hooks_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/hooks",
|
||||
"issue_comment_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/comments{/number}",
|
||||
"issue_events_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/events{/number}",
|
||||
"issues_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues{/number}",
|
||||
"keys_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/keys{/key_id}",
|
||||
"labels_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/labels{/name}",
|
||||
"languages_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/languages",
|
||||
"merges_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/merges",
|
||||
"milestones_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/milestones{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/notifications{?since,all,participating}",
|
||||
"pulls_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/pulls{/number}",
|
||||
"releases_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/releases{/id}",
|
||||
"stargazers_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/stargazers",
|
||||
"statuses_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/statuses/{sha}",
|
||||
"subscribers_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/subscribers",
|
||||
"subscription_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/subscription",
|
||||
"tags_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/tags",
|
||||
"trees_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/trees{/sha}",
|
||||
"teams_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/teams",
|
||||
"visibility": "internal"
|
||||
},
|
||||
"sender": {
|
||||
"login": "ryantxu",
|
||||
"id": 705951,
|
||||
"node_id": "MDQ6VXNlcjcwNTk1MQ==",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/705951?v=4",
|
||||
"html_url": "https://github.com/ryantxu",
|
||||
"gravatar_id": "",
|
||||
"type": "User",
|
||||
"site_admin": false,
|
||||
"url": "https://api.github.com/users/ryantxu",
|
||||
"events_url": "https://api.github.com/users/ryantxu/events{/privacy}",
|
||||
"following_url": "https://api.github.com/users/ryantxu/following{/other_user}",
|
||||
"followers_url": "https://api.github.com/users/ryantxu/followers",
|
||||
"gists_url": "https://api.github.com/users/ryantxu/gists{/gist_id}",
|
||||
"organizations_url": "https://api.github.com/users/ryantxu/orgs",
|
||||
"received_events_url": "https://api.github.com/users/ryantxu/received_events",
|
||||
"repos_url": "https://api.github.com/users/ryantxu/repos",
|
||||
"starred_url": "https://api.github.com/users/ryantxu/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ryantxu/subscriptions"
|
||||
},
|
||||
"organization": {
|
||||
"login": "grafana",
|
||||
"id": 7195757,
|
||||
"node_id": "MDEyOk9yZ2FuaXphdGlvbjcxOTU3NTc=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7195757?v=4",
|
||||
"description": "Grafana Labs is behind leading open source projects Grafana and Loki, and the creator of the first open \u0026 composable observability platform.",
|
||||
"url": "https://api.github.com/orgs/grafana",
|
||||
"events_url": "https://api.github.com/orgs/grafana/events",
|
||||
"hooks_url": "https://api.github.com/orgs/grafana/hooks",
|
||||
"issues_url": "https://api.github.com/orgs/grafana/issues",
|
||||
"members_url": "https://api.github.com/orgs/grafana/members{/member}",
|
||||
"public_members_url": "https://api.github.com/orgs/grafana/public_members{/member}",
|
||||
"repos_url": "https://api.github.com/orgs/grafana/repos"
|
||||
}
|
||||
}
|
||||
Vendored
+148
@@ -0,0 +1,148 @@
|
||||
{
|
||||
"ref": "refs/heads/not-main",
|
||||
"commits": [
|
||||
{
|
||||
"message": "Update README.md\n\ntest message",
|
||||
"author": {
|
||||
"name": "Ryan McKinley",
|
||||
"email": "ryantxu@gmail.com",
|
||||
"username": "ryantxu"
|
||||
},
|
||||
"url": "https://github.com/grafana/git-ui-sync-demo/commit/72096e3adc646c5a5b8a91744f962b12bac06045",
|
||||
"distinct": true,
|
||||
"id": "72096e3adc646c5a5b8a91744f962b12bac06045",
|
||||
"tree_id": "03ff034c54bcefae2f96041f3fb8172f2fe93df3",
|
||||
"timestamp": "2024-12-09T08:58:00+03:00",
|
||||
"committer": {
|
||||
"name": "GitHub",
|
||||
"email": "noreply@github.com",
|
||||
"username": "web-flow"
|
||||
},
|
||||
"modified": [
|
||||
"README.md"
|
||||
]
|
||||
}
|
||||
],
|
||||
"before": "6c86a0cdfd220c2fe3518cfaa4a4babf030d9a7a",
|
||||
"after": "72096e3adc646c5a5b8a91744f962b12bac06045",
|
||||
"created": false,
|
||||
"deleted": false,
|
||||
"forced": false,
|
||||
"compare": "https://github.com/grafana/git-ui-sync-demo/compare/6c86a0cdfd22...72096e3adc64",
|
||||
"repository": {
|
||||
"id": 888020043,
|
||||
"node_id": "R_kgDONO4cSw",
|
||||
"name": "git-ui-sync-demo",
|
||||
"full_name": "grafana/git-ui-sync-demo",
|
||||
"owner": {
|
||||
"login": "grafana",
|
||||
"id": 7195757,
|
||||
"node_id": "MDEyOk9yZ2FuaXphdGlvbjcxOTU3NTc=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7195757?v=4",
|
||||
"html_url": "https://github.com/grafana",
|
||||
"gravatar_id": "",
|
||||
"name": "grafana",
|
||||
"email": "hello@grafana.com",
|
||||
"type": "Organization",
|
||||
"site_admin": false,
|
||||
"url": "https://api.github.com/users/grafana",
|
||||
"events_url": "https://api.github.com/users/grafana/events{/privacy}",
|
||||
"following_url": "https://api.github.com/users/grafana/following{/other_user}",
|
||||
"followers_url": "https://api.github.com/users/grafana/followers",
|
||||
"gists_url": "https://api.github.com/users/grafana/gists{/gist_id}",
|
||||
"organizations_url": "https://api.github.com/users/grafana/orgs",
|
||||
"received_events_url": "https://api.github.com/users/grafana/received_events",
|
||||
"repos_url": "https://api.github.com/users/grafana/repos",
|
||||
"starred_url": "https://api.github.com/users/grafana/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/grafana/subscriptions"
|
||||
},
|
||||
"private": true,
|
||||
"description": "A repository containing Grafana dashboards to demo the Github Sync feature in Grafana.",
|
||||
"fork": false,
|
||||
"created_at": "2024-11-13T20:13:33+03:00",
|
||||
"pushed_at": "2024-12-09T08:58:00+03:00",
|
||||
"updated_at": "2024-11-28T12:53:26Z",
|
||||
"pulls_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/pulls{/number}",
|
||||
"size": 141,
|
||||
"stargazers_count": 0,
|
||||
"watchers_count": 0,
|
||||
"has_issues": true,
|
||||
"has_downloads": true,
|
||||
"has_wiki": true,
|
||||
"has_pages": false,
|
||||
"forks_count": 0,
|
||||
"archived": false,
|
||||
"disabled": false,
|
||||
"open_issues_count": 9,
|
||||
"default_branch": "main",
|
||||
"master_branch": "main",
|
||||
"organization": "grafana",
|
||||
"url": "https://github.com/grafana/git-ui-sync-demo",
|
||||
"archive_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/{archive_format}{/ref}",
|
||||
"html_url": "https://github.com/grafana/git-ui-sync-demo",
|
||||
"statuses_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/statuses/{sha}",
|
||||
"git_url": "git://github.com/grafana/git-ui-sync-demo.git",
|
||||
"ssh_url": "git@github.com:grafana/git-ui-sync-demo.git",
|
||||
"clone_url": "https://github.com/grafana/git-ui-sync-demo.git",
|
||||
"svn_url": "https://github.com/grafana/git-ui-sync-demo"
|
||||
},
|
||||
"head_commit": {
|
||||
"message": "Update README.md\n\ntest message",
|
||||
"author": {
|
||||
"name": "Ryan McKinley",
|
||||
"email": "ryantxu@gmail.com",
|
||||
"username": "ryantxu"
|
||||
},
|
||||
"url": "https://github.com/grafana/git-ui-sync-demo/commit/72096e3adc646c5a5b8a91744f962b12bac06045",
|
||||
"distinct": true,
|
||||
"id": "72096e3adc646c5a5b8a91744f962b12bac06045",
|
||||
"tree_id": "03ff034c54bcefae2f96041f3fb8172f2fe93df3",
|
||||
"timestamp": "2024-12-09T08:58:00+03:00",
|
||||
"committer": {
|
||||
"name": "GitHub",
|
||||
"email": "noreply@github.com",
|
||||
"username": "web-flow"
|
||||
},
|
||||
"modified": [
|
||||
"README.md"
|
||||
]
|
||||
},
|
||||
"pusher": {
|
||||
"name": "ryantxu",
|
||||
"email": "ryantxu@gmail.com"
|
||||
},
|
||||
"sender": {
|
||||
"login": "ryantxu",
|
||||
"id": 705951,
|
||||
"node_id": "MDQ6VXNlcjcwNTk1MQ==",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/705951?v=4",
|
||||
"html_url": "https://github.com/ryantxu",
|
||||
"gravatar_id": "",
|
||||
"type": "User",
|
||||
"site_admin": false,
|
||||
"url": "https://api.github.com/users/ryantxu",
|
||||
"events_url": "https://api.github.com/users/ryantxu/events{/privacy}",
|
||||
"following_url": "https://api.github.com/users/ryantxu/following{/other_user}",
|
||||
"followers_url": "https://api.github.com/users/ryantxu/followers",
|
||||
"gists_url": "https://api.github.com/users/ryantxu/gists{/gist_id}",
|
||||
"organizations_url": "https://api.github.com/users/ryantxu/orgs",
|
||||
"received_events_url": "https://api.github.com/users/ryantxu/received_events",
|
||||
"repos_url": "https://api.github.com/users/ryantxu/repos",
|
||||
"starred_url": "https://api.github.com/users/ryantxu/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ryantxu/subscriptions"
|
||||
},
|
||||
"organization": {
|
||||
"login": "grafana",
|
||||
"id": 7195757,
|
||||
"node_id": "MDEyOk9yZ2FuaXphdGlvbjcxOTU3NTc=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7195757?v=4",
|
||||
"description": "Grafana Labs is behind leading open source projects Grafana and Loki, and the creator of the first open \u0026 composable observability platform.",
|
||||
"url": "https://api.github.com/orgs/grafana",
|
||||
"events_url": "https://api.github.com/orgs/grafana/events",
|
||||
"hooks_url": "https://api.github.com/orgs/grafana/hooks",
|
||||
"issues_url": "https://api.github.com/orgs/grafana/issues",
|
||||
"members_url": "https://api.github.com/orgs/grafana/members{/member}",
|
||||
"public_members_url": "https://api.github.com/orgs/grafana/public_members{/member}",
|
||||
"repos_url": "https://api.github.com/orgs/grafana/repos"
|
||||
}
|
||||
}
|
||||
+234
@@ -0,0 +1,234 @@
|
||||
{
|
||||
"ref": "refs/heads/main",
|
||||
"before": "72096e3adc646c5a5b8a91744f962b12bac06045",
|
||||
"after": "5c816f9812e391c62b0c5555d0b473b296d9179c",
|
||||
"repository": {
|
||||
"id": 888020043,
|
||||
"node_id": "R_kgDONO4cSw",
|
||||
"name": "git-ui-sync-demo",
|
||||
"full_name": "grafana/git-ui-sync-demo",
|
||||
"private": true,
|
||||
"owner": {
|
||||
"name": "grafana",
|
||||
"email": "hello@grafana.com",
|
||||
"login": "grafana",
|
||||
"id": 7195757,
|
||||
"node_id": "MDEyOk9yZ2FuaXphdGlvbjcxOTU3NTc=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7195757?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/grafana",
|
||||
"html_url": "https://github.com/grafana",
|
||||
"followers_url": "https://api.github.com/users/grafana/followers",
|
||||
"following_url": "https://api.github.com/users/grafana/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/grafana/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/grafana/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/grafana/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/grafana/orgs",
|
||||
"repos_url": "https://api.github.com/users/grafana/repos",
|
||||
"events_url": "https://api.github.com/users/grafana/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/grafana/received_events",
|
||||
"type": "Organization",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"html_url": "https://github.com/grafana/git-ui-sync-demo",
|
||||
"description": "A repository containing Grafana dashboards to demo the Github Sync feature in Grafana.",
|
||||
"fork": false,
|
||||
"url": "https://github.com/grafana/git-ui-sync-demo",
|
||||
"forks_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/forks",
|
||||
"keys_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/keys{/key_id}",
|
||||
"collaborators_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/collaborators{/collaborator}",
|
||||
"teams_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/teams",
|
||||
"hooks_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/hooks",
|
||||
"issue_events_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/events{/number}",
|
||||
"events_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/events",
|
||||
"assignees_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/assignees{/user}",
|
||||
"branches_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/branches{/branch}",
|
||||
"tags_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/tags",
|
||||
"blobs_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/blobs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/tags{/sha}",
|
||||
"git_refs_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/refs{/sha}",
|
||||
"trees_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/trees{/sha}",
|
||||
"statuses_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/statuses/{sha}",
|
||||
"languages_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/languages",
|
||||
"stargazers_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/stargazers",
|
||||
"contributors_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/contributors",
|
||||
"subscribers_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/subscribers",
|
||||
"subscription_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/subscription",
|
||||
"commits_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/commits{/sha}",
|
||||
"git_commits_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/git/commits{/sha}",
|
||||
"comments_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/comments{/number}",
|
||||
"issue_comment_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues/comments{/number}",
|
||||
"contents_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/contents/{+path}",
|
||||
"compare_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/compare/{base}...{head}",
|
||||
"merges_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/merges",
|
||||
"archive_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/{archive_format}{/ref}",
|
||||
"downloads_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/downloads",
|
||||
"issues_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/issues{/number}",
|
||||
"pulls_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/pulls{/number}",
|
||||
"milestones_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/milestones{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/notifications{?since,all,participating}",
|
||||
"labels_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/labels{/name}",
|
||||
"releases_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/releases{/id}",
|
||||
"deployments_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/deployments",
|
||||
"created_at": 1731518013,
|
||||
"updated_at": "2024-12-09T05:58:03Z",
|
||||
"pushed_at": 1733731254,
|
||||
"git_url": "git://github.com/grafana/git-ui-sync-demo.git",
|
||||
"ssh_url": "git@github.com:grafana/git-ui-sync-demo.git",
|
||||
"clone_url": "https://github.com/grafana/git-ui-sync-demo.git",
|
||||
"svn_url": "https://github.com/grafana/git-ui-sync-demo",
|
||||
"homepage": null,
|
||||
"size": 142,
|
||||
"stargazers_count": 0,
|
||||
"watchers_count": 0,
|
||||
"language": null,
|
||||
"has_issues": true,
|
||||
"has_projects": true,
|
||||
"has_downloads": true,
|
||||
"has_wiki": true,
|
||||
"has_pages": false,
|
||||
"has_discussions": false,
|
||||
"forks_count": 0,
|
||||
"mirror_url": null,
|
||||
"archived": false,
|
||||
"disabled": false,
|
||||
"open_issues_count": 9,
|
||||
"license": null,
|
||||
"allow_forking": false,
|
||||
"is_template": false,
|
||||
"web_commit_signoff_required": false,
|
||||
"topics": [
|
||||
|
||||
],
|
||||
"visibility": "internal",
|
||||
"forks": 0,
|
||||
"open_issues": 9,
|
||||
"watchers": 0,
|
||||
"default_branch": "main",
|
||||
"stargazers": 0,
|
||||
"master_branch": "main",
|
||||
"organization": "grafana",
|
||||
"custom_properties": {
|
||||
|
||||
}
|
||||
},
|
||||
"pusher": {
|
||||
"name": "ryantxu",
|
||||
"email": "ryantxu@gmail.com"
|
||||
},
|
||||
"organization": {
|
||||
"login": "grafana",
|
||||
"id": 7195757,
|
||||
"node_id": "MDEyOk9yZ2FuaXphdGlvbjcxOTU3NTc=",
|
||||
"url": "https://api.github.com/orgs/grafana",
|
||||
"repos_url": "https://api.github.com/orgs/grafana/repos",
|
||||
"events_url": "https://api.github.com/orgs/grafana/events",
|
||||
"hooks_url": "https://api.github.com/orgs/grafana/hooks",
|
||||
"issues_url": "https://api.github.com/orgs/grafana/issues",
|
||||
"members_url": "https://api.github.com/orgs/grafana/members{/member}",
|
||||
"public_members_url": "https://api.github.com/orgs/grafana/public_members{/member}",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7195757?v=4",
|
||||
"description": "Grafana Labs is behind leading open source projects Grafana and Loki, and the creator of the first open & composable observability platform."
|
||||
},
|
||||
"enterprise": {
|
||||
"id": 129980,
|
||||
"slug": "grafana",
|
||||
"name": "Grafana Labs Enterprise",
|
||||
"node_id": "E_kgDOAAH7vA",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/b/129980?v=4",
|
||||
"description": "Grafana Labs is behind leading open source projects Grafana and Loki, and the creator of the first open & composable observability platform.",
|
||||
"website_url": "https://grafana.com",
|
||||
"html_url": "https://github.com/enterprises/grafana",
|
||||
"created_at": "2024-02-29T23:01:47Z",
|
||||
"updated_at": "2024-10-21T08:45:28Z"
|
||||
},
|
||||
"sender": {
|
||||
"login": "ryantxu",
|
||||
"id": 705951,
|
||||
"node_id": "MDQ6VXNlcjcwNTk1MQ==",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/705951?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/ryantxu",
|
||||
"html_url": "https://github.com/ryantxu",
|
||||
"followers_url": "https://api.github.com/users/ryantxu/followers",
|
||||
"following_url": "https://api.github.com/users/ryantxu/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/ryantxu/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/ryantxu/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ryantxu/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/ryantxu/orgs",
|
||||
"repos_url": "https://api.github.com/users/ryantxu/repos",
|
||||
"events_url": "https://api.github.com/users/ryantxu/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/ryantxu/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"created": false,
|
||||
"deleted": false,
|
||||
"forced": false,
|
||||
"base_ref": null,
|
||||
"compare": "https://github.com/grafana/git-ui-sync-demo/compare/72096e3adc64...5c816f9812e3",
|
||||
"commits": [
|
||||
{
|
||||
"id": "5c816f9812e391c62b0c5555d0b473b296d9179c",
|
||||
"tree_id": "97c7ba756b07b6a2b7fd130e59f75deed53fe027",
|
||||
"distinct": true,
|
||||
"message": "nested folders",
|
||||
"timestamp": "2024-12-09T11:00:48+03:00",
|
||||
"url": "https://github.com/grafana/git-ui-sync-demo/commit/5c816f9812e391c62b0c5555d0b473b296d9179c",
|
||||
"author": {
|
||||
"name": "Ryan McKinley",
|
||||
"email": "ryantxu@gmail.com",
|
||||
"username": "ryantxu"
|
||||
},
|
||||
"committer": {
|
||||
"name": "Ryan McKinley",
|
||||
"email": "ryantxu@gmail.com",
|
||||
"username": "ryantxu"
|
||||
},
|
||||
"added": [
|
||||
"nested-1/README.md",
|
||||
"nested-1/dash-1.json",
|
||||
"nested-1/nested-2/README.md",
|
||||
"nested-1/nested-2/dash-2.json"
|
||||
],
|
||||
"removed": [
|
||||
|
||||
],
|
||||
"modified": [
|
||||
"first-dashboard.json"
|
||||
]
|
||||
}
|
||||
],
|
||||
"head_commit": {
|
||||
"id": "5c816f9812e391c62b0c5555d0b473b296d9179c",
|
||||
"tree_id": "97c7ba756b07b6a2b7fd130e59f75deed53fe027",
|
||||
"distinct": true,
|
||||
"message": "nested folders",
|
||||
"timestamp": "2024-12-09T11:00:48+03:00",
|
||||
"url": "https://github.com/grafana/git-ui-sync-demo/commit/5c816f9812e391c62b0c5555d0b473b296d9179c",
|
||||
"author": {
|
||||
"name": "Ryan McKinley",
|
||||
"email": "ryantxu@gmail.com",
|
||||
"username": "ryantxu"
|
||||
},
|
||||
"committer": {
|
||||
"name": "Ryan McKinley",
|
||||
"email": "ryantxu@gmail.com",
|
||||
"username": "ryantxu"
|
||||
},
|
||||
"added": [
|
||||
"nested-1/README.md",
|
||||
"nested-1/dash-1.json",
|
||||
"nested-1/nested-2/README.md",
|
||||
"nested-1/nested-2/dash-2.json"
|
||||
],
|
||||
"removed": [
|
||||
|
||||
],
|
||||
"modified": [
|
||||
"first-dashboard.json"
|
||||
]
|
||||
}
|
||||
}
|
||||
Vendored
+148
@@ -0,0 +1,148 @@
|
||||
{
|
||||
"ref": "refs/heads/main",
|
||||
"commits": [
|
||||
{
|
||||
"message": "Update README.md\n\ntest message",
|
||||
"author": {
|
||||
"name": "Ryan McKinley",
|
||||
"email": "ryantxu@gmail.com",
|
||||
"username": "ryantxu"
|
||||
},
|
||||
"url": "https://github.com/grafana/git-ui-sync-demo/commit/72096e3adc646c5a5b8a91744f962b12bac06045",
|
||||
"distinct": true,
|
||||
"id": "72096e3adc646c5a5b8a91744f962b12bac06045",
|
||||
"tree_id": "03ff034c54bcefae2f96041f3fb8172f2fe93df3",
|
||||
"timestamp": "2024-12-09T08:58:00+03:00",
|
||||
"committer": {
|
||||
"name": "GitHub",
|
||||
"email": "noreply@github.com",
|
||||
"username": "web-flow"
|
||||
},
|
||||
"modified": [
|
||||
"README.md"
|
||||
]
|
||||
}
|
||||
],
|
||||
"before": "6c86a0cdfd220c2fe3518cfaa4a4babf030d9a7a",
|
||||
"after": "72096e3adc646c5a5b8a91744f962b12bac06045",
|
||||
"created": false,
|
||||
"deleted": false,
|
||||
"forced": false,
|
||||
"compare": "https://github.com/grafana/git-ui-sync-demo/compare/6c86a0cdfd22...72096e3adc64",
|
||||
"repository": {
|
||||
"id": 888020043,
|
||||
"node_id": "R_kgDONO4cSw",
|
||||
"name": "git-ui-sync-demo",
|
||||
"full_name": "grafana/git-ui-sync-demo",
|
||||
"owner": {
|
||||
"login": "grafana",
|
||||
"id": 7195757,
|
||||
"node_id": "MDEyOk9yZ2FuaXphdGlvbjcxOTU3NTc=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7195757?v=4",
|
||||
"html_url": "https://github.com/grafana",
|
||||
"gravatar_id": "",
|
||||
"name": "grafana",
|
||||
"email": "hello@grafana.com",
|
||||
"type": "Organization",
|
||||
"site_admin": false,
|
||||
"url": "https://api.github.com/users/grafana",
|
||||
"events_url": "https://api.github.com/users/grafana/events{/privacy}",
|
||||
"following_url": "https://api.github.com/users/grafana/following{/other_user}",
|
||||
"followers_url": "https://api.github.com/users/grafana/followers",
|
||||
"gists_url": "https://api.github.com/users/grafana/gists{/gist_id}",
|
||||
"organizations_url": "https://api.github.com/users/grafana/orgs",
|
||||
"received_events_url": "https://api.github.com/users/grafana/received_events",
|
||||
"repos_url": "https://api.github.com/users/grafana/repos",
|
||||
"starred_url": "https://api.github.com/users/grafana/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/grafana/subscriptions"
|
||||
},
|
||||
"private": true,
|
||||
"description": "A repository containing Grafana dashboards to demo the Github Sync feature in Grafana.",
|
||||
"fork": false,
|
||||
"created_at": "2024-11-13T20:13:33+03:00",
|
||||
"pushed_at": "2024-12-09T08:58:00+03:00",
|
||||
"updated_at": "2024-11-28T12:53:26Z",
|
||||
"pulls_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/pulls{/number}",
|
||||
"size": 141,
|
||||
"stargazers_count": 0,
|
||||
"watchers_count": 0,
|
||||
"has_issues": true,
|
||||
"has_downloads": true,
|
||||
"has_wiki": true,
|
||||
"has_pages": false,
|
||||
"forks_count": 0,
|
||||
"archived": false,
|
||||
"disabled": false,
|
||||
"open_issues_count": 9,
|
||||
"default_branch": "main",
|
||||
"master_branch": "main",
|
||||
"organization": "grafana",
|
||||
"url": "https://github.com/grafana/git-ui-sync-demo",
|
||||
"archive_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/{archive_format}{/ref}",
|
||||
"html_url": "https://github.com/grafana/git-ui-sync-demo",
|
||||
"statuses_url": "https://api.github.com/repos/grafana/git-ui-sync-demo/statuses/{sha}",
|
||||
"git_url": "git://github.com/grafana/git-ui-sync-demo.git",
|
||||
"ssh_url": "git@github.com:grafana/git-ui-sync-demo.git",
|
||||
"clone_url": "https://github.com/grafana/git-ui-sync-demo.git",
|
||||
"svn_url": "https://github.com/grafana/git-ui-sync-demo"
|
||||
},
|
||||
"head_commit": {
|
||||
"message": "Update README.md\n\ntest message",
|
||||
"author": {
|
||||
"name": "Ryan McKinley",
|
||||
"email": "ryantxu@gmail.com",
|
||||
"username": "ryantxu"
|
||||
},
|
||||
"url": "https://github.com/grafana/git-ui-sync-demo/commit/72096e3adc646c5a5b8a91744f962b12bac06045",
|
||||
"distinct": true,
|
||||
"id": "72096e3adc646c5a5b8a91744f962b12bac06045",
|
||||
"tree_id": "03ff034c54bcefae2f96041f3fb8172f2fe93df3",
|
||||
"timestamp": "2024-12-09T08:58:00+03:00",
|
||||
"committer": {
|
||||
"name": "GitHub",
|
||||
"email": "noreply@github.com",
|
||||
"username": "web-flow"
|
||||
},
|
||||
"modified": [
|
||||
"README.md"
|
||||
]
|
||||
},
|
||||
"pusher": {
|
||||
"name": "ryantxu",
|
||||
"email": "ryantxu@gmail.com"
|
||||
},
|
||||
"sender": {
|
||||
"login": "ryantxu",
|
||||
"id": 705951,
|
||||
"node_id": "MDQ6VXNlcjcwNTk1MQ==",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/705951?v=4",
|
||||
"html_url": "https://github.com/ryantxu",
|
||||
"gravatar_id": "",
|
||||
"type": "User",
|
||||
"site_admin": false,
|
||||
"url": "https://api.github.com/users/ryantxu",
|
||||
"events_url": "https://api.github.com/users/ryantxu/events{/privacy}",
|
||||
"following_url": "https://api.github.com/users/ryantxu/following{/other_user}",
|
||||
"followers_url": "https://api.github.com/users/ryantxu/followers",
|
||||
"gists_url": "https://api.github.com/users/ryantxu/gists{/gist_id}",
|
||||
"organizations_url": "https://api.github.com/users/ryantxu/orgs",
|
||||
"received_events_url": "https://api.github.com/users/ryantxu/received_events",
|
||||
"repos_url": "https://api.github.com/users/ryantxu/repos",
|
||||
"starred_url": "https://api.github.com/users/ryantxu/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ryantxu/subscriptions"
|
||||
},
|
||||
"organization": {
|
||||
"login": "grafana",
|
||||
"id": 7195757,
|
||||
"node_id": "MDEyOk9yZ2FuaXphdGlvbjcxOTU3NTc=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7195757?v=4",
|
||||
"description": "Grafana Labs is behind leading open source projects Grafana and Loki, and the creator of the first open \u0026 composable observability platform.",
|
||||
"url": "https://api.github.com/orgs/grafana",
|
||||
"events_url": "https://api.github.com/orgs/grafana/events",
|
||||
"hooks_url": "https://api.github.com/orgs/grafana/hooks",
|
||||
"issues_url": "https://api.github.com/orgs/grafana/issues",
|
||||
"members_url": "https://api.github.com/orgs/grafana/members{/member}",
|
||||
"public_members_url": "https://api.github.com/orgs/grafana/public_members{/member}",
|
||||
"repos_url": "https://api.github.com/orgs/grafana/repos"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,368 @@
|
||||
package github
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"slices"
|
||||
|
||||
"github.com/google/go-github/v70/github"
|
||||
"github.com/google/uuid"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/logging"
|
||||
provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
|
||||
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/repository"
|
||||
)
|
||||
|
||||
var subscribedEvents = []string{"pull_request", "push"} // same order as slices.Sort()
|
||||
|
||||
type WebhookRepository interface {
|
||||
Webhook(ctx context.Context, req *http.Request) (*provisioning.WebhookResponse, error)
|
||||
}
|
||||
|
||||
type GithubWebhookRepository interface {
|
||||
GithubRepository
|
||||
repository.Hooks
|
||||
|
||||
WebhookRepository
|
||||
}
|
||||
|
||||
type githubWebhookRepository struct {
|
||||
GithubRepository
|
||||
config *provisioning.Repository
|
||||
owner string
|
||||
repo string
|
||||
secret common.RawSecureValue
|
||||
gh Client
|
||||
webhookURL string
|
||||
}
|
||||
|
||||
func NewGithubWebhookRepository(
|
||||
basic GithubRepository,
|
||||
webhookURL string,
|
||||
secret common.RawSecureValue,
|
||||
) GithubWebhookRepository {
|
||||
return &githubWebhookRepository{
|
||||
GithubRepository: basic,
|
||||
config: basic.Config(),
|
||||
owner: basic.Owner(),
|
||||
repo: basic.Repo(),
|
||||
gh: basic.Client(),
|
||||
webhookURL: webhookURL,
|
||||
secret: secret,
|
||||
}
|
||||
}
|
||||
|
||||
// Webhook implements Repository.
|
||||
func (r *githubWebhookRepository) Webhook(ctx context.Context, req *http.Request) (*provisioning.WebhookResponse, error) {
|
||||
if r.config.Status.Webhook == nil {
|
||||
return nil, fmt.Errorf("unexpected webhook request")
|
||||
}
|
||||
|
||||
if r.secret.IsZero() {
|
||||
return nil, fmt.Errorf("missing webhook secret")
|
||||
}
|
||||
|
||||
payload, err := github.ValidatePayload(req, []byte(r.secret))
|
||||
if err != nil {
|
||||
return nil, apierrors.NewUnauthorized("invalid signature")
|
||||
}
|
||||
|
||||
return r.parseWebhook(github.WebHookType(req), payload)
|
||||
}
|
||||
|
||||
// This method does not include context because it does delegate any more requests
|
||||
func (r *githubWebhookRepository) parseWebhook(messageType string, payload []byte) (*provisioning.WebhookResponse, error) {
|
||||
event, err := github.ParseWebHook(messageType, payload)
|
||||
if err != nil {
|
||||
return nil, apierrors.NewBadRequest("invalid payload")
|
||||
}
|
||||
|
||||
switch event := event.(type) {
|
||||
case *github.PushEvent:
|
||||
return r.parsePushEvent(event)
|
||||
case *github.PullRequestEvent:
|
||||
return r.parsePullRequestEvent(event)
|
||||
case *github.PingEvent:
|
||||
return &provisioning.WebhookResponse{
|
||||
Code: http.StatusOK,
|
||||
Message: "ping received",
|
||||
}, nil
|
||||
default:
|
||||
return &provisioning.WebhookResponse{
|
||||
Code: http.StatusNotImplemented,
|
||||
Message: fmt.Sprintf("unsupported messageType: %s", messageType),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (r *githubWebhookRepository) parsePushEvent(event *github.PushEvent) (*provisioning.WebhookResponse, error) {
|
||||
if event.GetRepo() == nil {
|
||||
return nil, fmt.Errorf("missing repository in push event")
|
||||
}
|
||||
if event.GetRepo().GetFullName() != fmt.Sprintf("%s/%s", r.owner, r.repo) {
|
||||
return nil, fmt.Errorf("repository mismatch")
|
||||
}
|
||||
|
||||
// No need to sync if not enabled
|
||||
if !r.config.Spec.Sync.Enabled {
|
||||
return &provisioning.WebhookResponse{Code: http.StatusOK}, nil
|
||||
}
|
||||
|
||||
// Skip silently if the event is not for the main/master branch
|
||||
// as we cannot configure the webhook to only publish events for the main branch
|
||||
if event.GetRef() != fmt.Sprintf("refs/heads/%s", r.config.Spec.GitHub.Branch) {
|
||||
return &provisioning.WebhookResponse{Code: http.StatusOK}, nil
|
||||
}
|
||||
|
||||
return &provisioning.WebhookResponse{
|
||||
Code: http.StatusAccepted,
|
||||
Job: &provisioning.JobSpec{
|
||||
Repository: r.config.GetName(),
|
||||
Action: provisioning.JobActionPull,
|
||||
Pull: &provisioning.SyncJobOptions{
|
||||
Incremental: true,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *githubWebhookRepository) parsePullRequestEvent(event *github.PullRequestEvent) (*provisioning.WebhookResponse, error) {
|
||||
if event.GetRepo() == nil {
|
||||
return nil, fmt.Errorf("missing repository in pull request event")
|
||||
}
|
||||
cfg := r.config.Spec.GitHub
|
||||
if cfg == nil {
|
||||
return nil, fmt.Errorf("missing GitHub config")
|
||||
}
|
||||
|
||||
if event.GetRepo().GetFullName() != fmt.Sprintf("%s/%s", r.owner, r.repo) {
|
||||
return nil, fmt.Errorf("repository mismatch")
|
||||
}
|
||||
pr := event.GetPullRequest()
|
||||
if pr == nil {
|
||||
return nil, fmt.Errorf("expected PR in event")
|
||||
}
|
||||
|
||||
if pr.GetBase().GetRef() != r.config.Spec.GitHub.Branch {
|
||||
return &provisioning.WebhookResponse{
|
||||
Code: http.StatusOK,
|
||||
Message: fmt.Sprintf("ignoring pull request event as %s is not the configured branch", pr.GetBase().GetRef()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
action := event.GetAction()
|
||||
if action != "opened" && action != "reopened" && action != "synchronize" {
|
||||
return &provisioning.WebhookResponse{
|
||||
Code: http.StatusOK, // Nothing needed
|
||||
Message: fmt.Sprintf("ignore pull request event: %s", action),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Queue an async job that will parse files
|
||||
return &provisioning.WebhookResponse{
|
||||
Code: http.StatusAccepted, // Nothing needed
|
||||
Message: fmt.Sprintf("pull request: %s", action),
|
||||
Job: &provisioning.JobSpec{
|
||||
Repository: r.config.GetName(),
|
||||
Action: provisioning.JobActionPullRequest,
|
||||
PullRequest: &provisioning.PullRequestJobOptions{
|
||||
URL: pr.GetHTMLURL(),
|
||||
PR: pr.GetNumber(),
|
||||
Ref: pr.GetHead().GetRef(),
|
||||
Hash: pr.GetHead().GetSHA(),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CommentPullRequest adds a comment to a pull request.
|
||||
func (r *githubWebhookRepository) CommentPullRequest(ctx context.Context, prNumber int, comment string) error {
|
||||
ctx, _ = r.logger(ctx, "")
|
||||
return r.gh.CreatePullRequestComment(ctx, r.owner, r.repo, prNumber, comment)
|
||||
}
|
||||
|
||||
func (r *githubWebhookRepository) createWebhook(ctx context.Context) (WebhookConfig, error) {
|
||||
secret, err := uuid.NewRandom()
|
||||
if err != nil {
|
||||
return WebhookConfig{}, fmt.Errorf("could not generate secret: %w", err)
|
||||
}
|
||||
|
||||
cfg := WebhookConfig{
|
||||
URL: r.webhookURL,
|
||||
Secret: secret.String(),
|
||||
ContentType: "json",
|
||||
Events: subscribedEvents,
|
||||
Active: true,
|
||||
}
|
||||
|
||||
hook, err := r.gh.CreateWebhook(ctx, r.owner, r.repo, cfg)
|
||||
if err != nil {
|
||||
return WebhookConfig{}, err
|
||||
}
|
||||
|
||||
// HACK: GitHub does not return the secret, so we need to update it manually
|
||||
hook.Secret = cfg.Secret
|
||||
|
||||
logging.FromContext(ctx).Info("webhook created", "url", cfg.URL, "id", hook.ID)
|
||||
return hook, nil
|
||||
}
|
||||
|
||||
// updateWebhook checks if the webhook needs to be updated and updates it if necessary.
|
||||
// if the webhook does not exist, it will create it.
|
||||
func (r *githubWebhookRepository) updateWebhook(ctx context.Context) (WebhookConfig, bool, error) {
|
||||
if r.config.Status.Webhook == nil || r.config.Status.Webhook.ID == 0 {
|
||||
hook, err := r.createWebhook(ctx)
|
||||
if err != nil {
|
||||
return WebhookConfig{}, false, err
|
||||
}
|
||||
return hook, true, nil
|
||||
}
|
||||
|
||||
hook, err := r.gh.GetWebhook(ctx, r.owner, r.repo, r.config.Status.Webhook.ID)
|
||||
switch {
|
||||
case errors.Is(err, ErrResourceNotFound):
|
||||
hook, err := r.createWebhook(ctx)
|
||||
if err != nil {
|
||||
return WebhookConfig{}, false, err
|
||||
}
|
||||
return hook, true, nil
|
||||
case err != nil:
|
||||
return WebhookConfig{}, false, fmt.Errorf("get webhook: %w", err)
|
||||
}
|
||||
|
||||
var mustUpdate bool
|
||||
|
||||
if hook.URL != r.webhookURL {
|
||||
mustUpdate = true
|
||||
hook.URL = r.webhookURL
|
||||
}
|
||||
|
||||
slices.Sort(hook.Events) // consistent order for comparison
|
||||
if !slices.Equal(hook.Events, subscribedEvents) {
|
||||
mustUpdate = true
|
||||
hook.Events = subscribedEvents
|
||||
}
|
||||
|
||||
if !mustUpdate {
|
||||
return hook, false, nil
|
||||
}
|
||||
|
||||
// Something has changed in the webhook. Let's rotate the secret as well, so as to ensure we end up with a 100% correct webhook.
|
||||
secret, err := uuid.NewRandom()
|
||||
if err != nil {
|
||||
return WebhookConfig{}, false, fmt.Errorf("could not generate secret: %w", err)
|
||||
}
|
||||
hook.Secret = secret.String()
|
||||
if err := r.gh.EditWebhook(ctx, r.owner, r.repo, hook); err != nil {
|
||||
return WebhookConfig{}, false, fmt.Errorf("edit webhook: %w", err)
|
||||
}
|
||||
|
||||
return hook, true, nil
|
||||
}
|
||||
|
||||
func (r *githubWebhookRepository) deleteWebhook(ctx context.Context) error {
|
||||
logger := logging.FromContext(ctx)
|
||||
if r.config.Status.Webhook == nil {
|
||||
return fmt.Errorf("webhook not found")
|
||||
}
|
||||
|
||||
id := r.config.Status.Webhook.ID
|
||||
|
||||
if err := r.gh.DeleteWebhook(ctx, r.owner, r.repo, id); err != nil {
|
||||
return fmt.Errorf("delete webhook: %w", err)
|
||||
}
|
||||
|
||||
logger.Info("webhook deleted", "url", r.config.Status.Webhook.URL, "id", id)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *githubWebhookRepository) OnCreate(ctx context.Context) ([]map[string]interface{}, error) {
|
||||
if len(r.webhookURL) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
ctx, _ = r.logger(ctx, "")
|
||||
hook, err := r.createWebhook(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []map[string]interface{}{
|
||||
{
|
||||
"op": "replace",
|
||||
"path": "/status/webhook",
|
||||
"value": &provisioning.WebhookStatus{
|
||||
ID: hook.ID,
|
||||
URL: hook.URL,
|
||||
SubscribedEvents: hook.Events,
|
||||
},
|
||||
},
|
||||
{
|
||||
"op": "replace",
|
||||
"path": "/secure/webhookSecret",
|
||||
"value": map[string]string{
|
||||
"create": hook.Secret,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *githubWebhookRepository) OnUpdate(ctx context.Context) ([]map[string]interface{}, error) {
|
||||
if len(r.webhookURL) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
ctx, _ = r.logger(ctx, "")
|
||||
hook, changed, err := r.updateWebhook(ctx)
|
||||
if err != nil || !changed {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// update the webhook and secret
|
||||
return []map[string]any{{
|
||||
"op": "replace",
|
||||
"path": "/status/webhook",
|
||||
"value": &provisioning.WebhookStatus{
|
||||
ID: hook.ID,
|
||||
URL: hook.URL,
|
||||
SubscribedEvents: hook.Events,
|
||||
},
|
||||
}, {
|
||||
"op": "replace",
|
||||
"path": "/secure/webhookSecret",
|
||||
"value": map[string]string{
|
||||
"create": hook.Secret,
|
||||
},
|
||||
}}, nil
|
||||
}
|
||||
|
||||
func (r *githubWebhookRepository) OnDelete(ctx context.Context) error {
|
||||
if r.config.Status.Webhook == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return r.deleteWebhook(ctx)
|
||||
}
|
||||
|
||||
func (r *githubWebhookRepository) logger(ctx context.Context, ref string) (context.Context, logging.Logger) {
|
||||
logger := logging.FromContext(ctx)
|
||||
|
||||
type containsGh int
|
||||
var containsGhKey containsGh
|
||||
if ctx.Value(containsGhKey) != nil {
|
||||
return ctx, logging.FromContext(ctx)
|
||||
}
|
||||
|
||||
if ref == "" {
|
||||
ref = r.config.Spec.GitHub.Branch
|
||||
}
|
||||
|
||||
logger = logger.With(slog.Group("github_repository", "owner", r.owner, "name", r.repo, "ref", ref))
|
||||
ctx = logging.Context(ctx, logger)
|
||||
// We want to ensure we don't add multiple github_repository keys. With doesn't deduplicate the keys...
|
||||
ctx = context.WithValue(ctx, containsGhKey, true)
|
||||
return ctx, logger
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user