From 7b8330850694013e0194a054ff2a2dd1a5ccac2e Mon Sep 17 00:00:00 2001 From: wuhuizuo Date: Tue, 31 Dec 2024 18:18:24 +0800 Subject: [PATCH] feat(tibuild): support commit to build (#219) Usage: /devbuild trigger --engine tekton -e enterprise tidb v8.5.0-dev commit/ Signed-off-by: wuhuizuo --------- Signed-off-by: wuhuizuo --- tibuild/go.mod | 2 +- tibuild/pkg/rest/service/dev_build_service.go | 23 ++++++ tibuild/pkg/rest/service/gh_client.go | 79 +++++++++++++++++++ tibuild/pkg/rest/service/gh_client_test.go | 39 +++++++++ tibuild/pkg/rest/service/interface.go | 1 + 5 files changed, 143 insertions(+), 1 deletion(-) diff --git a/tibuild/go.mod b/tibuild/go.mod index 50c5d6fb..f8e822d0 100644 --- a/tibuild/go.mod +++ b/tibuild/go.mod @@ -1,6 +1,6 @@ module github.com/PingCAP-QE/ee-apps/tibuild -go 1.23 +go 1.23.4 require ( github.com/DATA-DOG/go-sqlmock v1.5.2 diff --git a/tibuild/pkg/rest/service/dev_build_service.go b/tibuild/pkg/rest/service/dev_build_service.go index 9a51a2af..64dafacc 100644 --- a/tibuild/pkg/rest/service/dev_build_service.go +++ b/tibuild/pkg/rest/service/dev_build_service.go @@ -142,12 +142,35 @@ func fillDetailInfoForTekton(ctx context.Context, client GHClient, req *DevBuild } req.Spec.GitHash = commit + return nil + case strings.HasPrefix(req.Spec.GitRef, "commit/"): + commit := strings.Replace(req.Spec.GitRef, "commit/", "", 1) + req.Spec.GitHash = commit + branch, err := getBranchForCommit(ctx, client, repo.Owner, repo.Repo, commit) + if err != nil { + return err + } + + req.Spec.GitRef = "branch/" + branch return nil default: return nil } } +// get the branch name for the commit in github / repo. +func getBranchForCommit(ctx context.Context, client GHClient, owner, repo, commit string) (string, error) { + branches, err := client.GetBranchesForCommit(ctx, owner, repo, commit) + if err != nil { + return "", err + } + if len(branches) == 0 { + return "", fmt.Errorf("no branch found for commit %s", commit) + } + + return branches[0], nil +} + func fillWithDefaults(req *DevBuild) { spec := &req.Spec guessEnterprisePluginRef(spec) diff --git a/tibuild/pkg/rest/service/gh_client.go b/tibuild/pkg/rest/service/gh_client.go index cfb70511..49f1865e 100644 --- a/tibuild/pkg/rest/service/gh_client.go +++ b/tibuild/pkg/rest/service/gh_client.go @@ -2,8 +2,10 @@ package service import ( "context" + "encoding/json" "fmt" "net/http" + "net/url" "regexp" "strings" @@ -15,6 +17,83 @@ var sha1regex *regexp.Regexp = regexp.MustCompile(`^[0-9a-fA-F]{40}$`) type GitHubClient struct{ *github.Client } +// define a struct for the json data: +/* +{ + "branches": [ + { + "branch": "master", + "prs": [ + { + "number": 57522, + "showPrefix": false, + "repo": { + "name": "tidb", + "ownerLogin": "pingcap" + }, + "globalRelayId": "PR_kwDOAoCpQc6CbBGf" + } + ] + } + ], + "tags": [ + "v9.0.0-alpha" + ] +} +*/ +type branchesForCommitResponse struct { + Branches []struct { + Branch string `json:"branch"` + } + Tags []string `json:"tags"` +} + +// GetBranchesForCommit implements GHClient. +func (c GitHubClient) GetBranchesForCommit(ctx context.Context, owner string, repo string, commit string) ([]string, error) { + // check for github owner format with regexp, only support [a-zA-Z0-9_-] + if !regexp.MustCompile(`^[a-zA-Z0-9_-]+$`).MatchString(owner) { + return nil, fmt.Errorf("owner %s is not a valid github owner", owner) + } + // check for github repo name format with regexp, only support [a-zA-Z0-9_-] + if !regexp.MustCompile(`^[a-zA-Z0-9_-]+$`).MatchString(repo) { + return nil, fmt.Errorf("repo %s is not a valid github repo name", repo) + } + // check for commit format + if !sha1regex.MatchString(commit) { + return nil, fmt.Errorf("commit %s is not a valid sha1", commit) + } + + rawURL, err := url.JoinPath("https://github.com", owner, repo, "branch_commits", commit) + if err != nil { + return nil, err + } + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, rawURL, nil) + if err != nil { + return nil, err + } + + req.Header.Add("Accept", "application/json") + res, err := c.Client.Client().Do(req) + if err != nil { + return nil, err + } + defer res.Body.Close() + + // parse the res body + var data branchesForCommitResponse + // read the response body and unmarshal to `data` + if err := json.NewDecoder(res.Body).Decode(&data); err != nil { + return nil, err + } + + var branches []string + for _, branch := range data.Branches { + branches = append(branches, branch.Branch) + } + return branches, nil +} + func (c GitHubClient) GetHash(ctx context.Context, owner, repo, ref string) (string, error) { if sha1regex.MatchString(ref) { return ref, nil diff --git a/tibuild/pkg/rest/service/gh_client_test.go b/tibuild/pkg/rest/service/gh_client_test.go index 3dff257c..ed3aa81c 100644 --- a/tibuild/pkg/rest/service/gh_client_test.go +++ b/tibuild/pkg/rest/service/gh_client_test.go @@ -3,6 +3,7 @@ package service import ( "context" "os" + "reflect" "testing" "github.com/stretchr/testify/require" @@ -24,3 +25,41 @@ func TestGetHashSha1(t *testing.T) { require.NoError(t, err) require.Equal(t, s, hash) } + +func TestGitHubClient_GetBranchesForCommit(t *testing.T) { + type args struct { + owner string + repo string + commit string + } + tests := []struct { + name string + args args + want []string + wantErr bool + }{ + { + name: "test", + args: args{ + owner: "pingcap", + repo: "tidb", + commit: "0ccee0e011054ebfc86a6d5faa59a689a0793c05", + }, + want: []string{"master"}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := NewGHClient("") + got, err := c.GetBranchesForCommit(context.TODO(), tt.args.owner, tt.args.repo, tt.args.commit) + if (err != nil) != tt.wantErr { + t.Errorf("GitHubClient.GetBranchesForCommit() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("GitHubClient.GetBranchesForCommit() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/tibuild/pkg/rest/service/interface.go b/tibuild/pkg/rest/service/interface.go index 670d2ed5..39911ecf 100644 --- a/tibuild/pkg/rest/service/interface.go +++ b/tibuild/pkg/rest/service/interface.go @@ -27,4 +27,5 @@ type ArtifactHelperService interface { type GHClient interface { GetHash(ctx context.Context, owner, repo, ref string) (string, error) GetPullRequestInfo(ctx context.Context, owner, repo string, prNum int) (*github.PullRequest, error) + GetBranchesForCommit(ctx context.Context, owner, repo, commit string) ([]string, error) }