Provisioning: Use Nanogit for basic git operations in Github repository type (#107889)
This commit is contained in:
@@ -2,10 +2,7 @@ package provisioning
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
@@ -13,7 +10,6 @@ import (
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
gh "github.com/google/go-github/v70/github"
|
||||
ghmock "github.com/migueleliasweb/go-github-mock/src/mock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -224,20 +220,8 @@ func runGrafana(t *testing.T, options ...grafanaOption) *provisioningTestHelper
|
||||
}
|
||||
helper := apis.NewK8sTestHelper(t, opts)
|
||||
|
||||
helper.GetEnv().GitHubFactory.Client = ghmock.NewMockedHTTPClient(
|
||||
ghmock.WithRequestMatchHandler(ghmock.GetUser, ghAlwaysWrite(t, &gh.User{})),
|
||||
ghmock.WithRequestMatchHandler(ghmock.GetReposHooksByOwnerByRepo, ghAlwaysWrite(t, []*gh.Hook{})),
|
||||
ghmock.WithRequestMatchHandler(ghmock.PostReposHooksByOwnerByRepo, ghAlwaysWrite(t, &gh.Hook{})),
|
||||
ghmock.WithRequestMatchHandler(ghmock.GetReposByOwnerByRepo, ghAlwaysWrite(t, &gh.Repository{})),
|
||||
ghmock.WithRequestMatchHandler(ghmock.GetReposBranchesByOwnerByRepoByBranch, ghAlwaysWrite(t, &gh.Branch{})),
|
||||
ghmock.WithRequestMatchHandler(ghmock.GetReposGitTreesByOwnerByRepoByTreeSha, ghAlwaysWrite(t, &gh.Tree{})),
|
||||
ghmock.WithRequestMatchHandler(
|
||||
ghmock.DeleteReposHooksByOwnerByRepoByHookId,
|
||||
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}),
|
||||
),
|
||||
)
|
||||
// FIXME: keeping this line here to keep the dependency around until we have tests which use this again.
|
||||
helper.GetEnv().GitHubFactory.Client = ghmock.NewMockedHTTPClient()
|
||||
|
||||
repositories := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
User: helper.Org1.Admin,
|
||||
@@ -310,33 +294,6 @@ func runGrafana(t *testing.T, options ...grafanaOption) *provisioningTestHelper
|
||||
}
|
||||
}
|
||||
|
||||
func ghAlwaysWrite(t *testing.T, body any) http.HandlerFunc {
|
||||
marshalled := ghmock.MustMarshal(body)
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
_, err := w.Write(marshalled)
|
||||
require.NoError(t, err, "failed to write body in mock")
|
||||
})
|
||||
}
|
||||
|
||||
func ghHandleTree(t *testing.T, refs map[string][]*gh.TreeEntry) http.HandlerFunc {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
sha := r.URL.Path[strings.LastIndex(r.URL.Path, "/")+1:]
|
||||
require.NotEmpty(t, sha, "sha path parameter was missing?")
|
||||
|
||||
entries := refs[sha]
|
||||
require.NotNil(t, entries, "no entries for sha %s", sha)
|
||||
|
||||
tree := &gh.Tree{
|
||||
SHA: gh.Ptr(sha),
|
||||
Truncated: gh.Ptr(false),
|
||||
Entries: entries,
|
||||
}
|
||||
|
||||
_, err := w.Write(ghmock.MustMarshal(tree))
|
||||
require.NoError(t, err, "failed to write body in mock")
|
||||
})
|
||||
}
|
||||
|
||||
func mustNestedString(obj map[string]interface{}, fields ...string) string {
|
||||
v, _, err := unstructured.NestedString(obj, fields...)
|
||||
if err != nil {
|
||||
@@ -350,15 +307,6 @@ func asJSON(obj any) []byte {
|
||||
return jj
|
||||
}
|
||||
|
||||
func treeEntryDir(dirName string, sha string) *gh.TreeEntry {
|
||||
return &gh.TreeEntry{
|
||||
SHA: gh.Ptr(sha),
|
||||
Path: gh.Ptr(dirName),
|
||||
Type: gh.Ptr("tree"),
|
||||
Mode: gh.Ptr("040000"),
|
||||
}
|
||||
}
|
||||
|
||||
func unstructuredToRepository(t *testing.T, obj *unstructured.Unstructured) *provisioning.Repository {
|
||||
bytes, err := obj.MarshalJSON()
|
||||
require.NoError(t, err)
|
||||
@@ -369,33 +317,3 @@ func unstructuredToRepository(t *testing.T, obj *unstructured.Unstructured) *pro
|
||||
|
||||
return repo
|
||||
}
|
||||
|
||||
func treeEntry(fpath string, content []byte) *gh.TreeEntry {
|
||||
sha := sha256.Sum256(content)
|
||||
|
||||
return &gh.TreeEntry{
|
||||
SHA: gh.Ptr(hex.EncodeToString(sha[:])),
|
||||
Path: gh.Ptr(fpath),
|
||||
Size: gh.Ptr(len(content)),
|
||||
Type: gh.Ptr("blob"),
|
||||
Mode: gh.Ptr("100644"),
|
||||
Content: gh.Ptr(string(content)),
|
||||
}
|
||||
}
|
||||
|
||||
func repoContent(fpath string, content []byte) *gh.RepositoryContent {
|
||||
sha := sha256.Sum256(content)
|
||||
typ := "blob"
|
||||
if strings.HasSuffix(fpath, "/") {
|
||||
typ = "tree"
|
||||
}
|
||||
|
||||
return &gh.RepositoryContent{
|
||||
SHA: gh.Ptr(hex.EncodeToString(sha[:])),
|
||||
Name: gh.Ptr(path.Base(fpath)),
|
||||
Path: &fpath,
|
||||
Size: gh.Ptr(len(content)),
|
||||
Type: &typ,
|
||||
Content: gh.Ptr(string(content)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,13 +7,10 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
gh "github.com/google/go-github/v70/github"
|
||||
ghmock "github.com/migueleliasweb/go-github-mock/src/mock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
@@ -174,7 +171,7 @@ func TestIntegrationProvisioning_FailInvalidSchema(t *testing.T) {
|
||||
}, time.Second*10, time.Millisecond*10, "Expected to be able to start a sync job")
|
||||
|
||||
require.EventuallyWithT(t, func(collect *assert.CollectT) {
|
||||
//helper.TriggerJobProcessing(t)
|
||||
// helper.TriggerJobProcessing(t)
|
||||
result, err := helper.Repositories.Resource.Get(ctx, repo, metav1.GetOptions{},
|
||||
"jobs", string(jobObj.GetUID()))
|
||||
|
||||
@@ -212,50 +209,25 @@ func TestIntegrationProvisioning_CreatingGitHubRepository(t *testing.T) {
|
||||
helper := runGrafana(t)
|
||||
ctx := context.Background()
|
||||
|
||||
helper.GetEnv().GitHubFactory.Client = ghmock.NewMockedHTTPClient(
|
||||
ghmock.WithRequestMatchHandler(ghmock.GetUser, ghAlwaysWrite(t, &gh.User{Name: gh.Ptr("github-user")})),
|
||||
ghmock.WithRequestMatchHandler(ghmock.GetReposHooksByOwnerByRepo, ghAlwaysWrite(t, []*gh.Hook{})),
|
||||
ghmock.WithRequestMatchHandler(ghmock.PostReposHooksByOwnerByRepo, ghAlwaysWrite(t, &gh.Hook{ID: gh.Ptr(int64(123))})),
|
||||
ghmock.WithRequestMatchHandler(ghmock.GetReposByOwnerByRepo, ghAlwaysWrite(t, &gh.Repository{ID: gh.Ptr(int64(234))})),
|
||||
ghmock.WithRequestMatchHandler(
|
||||
ghmock.GetReposBranchesByOwnerByRepoByBranch,
|
||||
ghAlwaysWrite(t, &gh.Branch{
|
||||
Name: gh.Ptr("main"),
|
||||
Commit: &gh.RepositoryCommit{SHA: gh.Ptr("deadbeef")},
|
||||
}),
|
||||
),
|
||||
ghmock.WithRequestMatchHandler(ghmock.GetReposGitTreesByOwnerByRepoByTreeSha,
|
||||
ghHandleTree(t, map[string][]*gh.TreeEntry{
|
||||
"deadbeef": {
|
||||
treeEntryDir("grafana", "subtree"),
|
||||
},
|
||||
"subtree": {
|
||||
treeEntry("dashboard.json", helper.LoadFile("testdata/all-panels.json")),
|
||||
treeEntryDir("subdir", "subtree2"),
|
||||
treeEntry("subdir/dashboard2.yaml", helper.LoadFile("testdata/text-options.json")),
|
||||
},
|
||||
})),
|
||||
ghmock.WithRequestMatchHandler(
|
||||
ghmock.GetReposContentsByOwnerByRepoByPath,
|
||||
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
pathRegex := regexp.MustCompile(`/repos/[^/]+/[^/]+/contents/(.*)`)
|
||||
matches := pathRegex.FindStringSubmatch(r.URL.Path)
|
||||
require.NotNil(t, matches, "no match for contents?")
|
||||
path := matches[1]
|
||||
// FIXME: instead of using an existing GitHub repository, we should create a new one for the tests and a branch
|
||||
// This was the previous structure
|
||||
// ghmock.WithRequestMatchHandler(ghmock.GetReposGitTreesByOwnerByRepoByTreeSha,
|
||||
// ghHandleTree(t, map[string][]*gh.TreeEntry{
|
||||
// "deadbeef": {
|
||||
// treeEntryDir("grafana", "subtree"),
|
||||
// },
|
||||
// "subtree": {
|
||||
// treeEntry("dashboard.json", helper.LoadFile("testdata/all-panels.json")),
|
||||
// treeEntryDir("subdir", "subtree2"),
|
||||
// treeEntry("subdir/dashboard2.yaml", helper.LoadFile("testdata/text-options.json")),
|
||||
// },
|
||||
// })),
|
||||
|
||||
var err error
|
||||
switch path {
|
||||
case "grafana/dashboard.json":
|
||||
_, err = w.Write(ghmock.MustMarshal(repoContent(path, helper.LoadFile("testdata/all-panels.json"))))
|
||||
case "grafana/subdir/dashboard2.yaml":
|
||||
_, err = w.Write(ghmock.MustMarshal(repoContent(path, helper.LoadFile("testdata/text-options.json"))))
|
||||
default:
|
||||
t.Fatalf("got unexpected path: %s", path)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
}),
|
||||
),
|
||||
)
|
||||
// FIXME: uncomment these to implement webhook integration tests.
|
||||
// helper.GetEnv().GitHubFactory.Client = ghmock.NewMockedHTTPClient(
|
||||
// ghmock.WithRequestMatchHandler(ghmock.GetReposHooksByOwnerByRepo, ghAlwaysWrite(t, []*gh.Hook{})),
|
||||
// ghmock.WithRequestMatchHandler(ghmock.PostReposHooksByOwnerByRepo, ghAlwaysWrite(t, &gh.Hook{ID: gh.Ptr(int64(123))})),
|
||||
// )
|
||||
|
||||
const repo = "github-create-test"
|
||||
_, err := helper.Repositories.Resource.Create(ctx,
|
||||
@@ -280,8 +252,10 @@ func TestIntegrationProvisioning_CreatingGitHubRepository(t *testing.T) {
|
||||
for _, v := range found.Items {
|
||||
names = append(names, v.GetName())
|
||||
}
|
||||
assert.Contains(t, names, "n1jR8vnnz", "should contain dashboard.json's contents")
|
||||
assert.Contains(t, names, "WZ7AhQiVz", "should contain dashboard2.yaml's contents")
|
||||
require.Len(t, names, 3, "should have three dashboards")
|
||||
assert.Contains(t, names, "adg5vbj", "should contain dashboard.json's contents")
|
||||
assert.Contains(t, names, "admfz74", "should contain dashboard2.yaml's contents")
|
||||
assert.Contains(t, names, "adn5mxb", "should contain dashboard2.yaml's contents")
|
||||
|
||||
err = helper.Repositories.Resource.Delete(ctx, repo, metav1.DeleteOptions{})
|
||||
require.NoError(t, err, "should delete values")
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
"description": "{{ or .Description .Name "Load grafana dashboard from fake repository" }}",
|
||||
"type": "github",
|
||||
"github": {
|
||||
"url": "{{ or .URL "https://github.com/grafana/git-ui-sync-demo" }}",
|
||||
"branch": "{{ or .Branch "dummy" }}",
|
||||
"url": "{{ or .URL "https://github.com/grafana/grafana-git-sync-demo" }}",
|
||||
"branch": "{{ or .Branch "integration-test" }}",
|
||||
"generateDashboardPreviews": {{ if .GenerateDashboardPreviews }} true {{ else }} false {{ end }},
|
||||
"token": "{{ or .Token "github_pat_dummy" }}",
|
||||
"token": "{{ or .Token "" }}",
|
||||
"path": "{{ or .Path "grafana/" }}"
|
||||
},
|
||||
"sync": {
|
||||
|
||||
Reference in New Issue
Block a user