From fafcf3a623b25dca0eeec0e45a22425967d7c2d9 Mon Sep 17 00:00:00 2001 From: Simone Gotti Date: Tue, 11 Jun 2019 11:07:39 +0200 Subject: [PATCH] gitsource: add new methods to handle refs and commits Add new methods to handle refs and commits and related urls --- internal/gitsources/agolagit/agolagit.go | 40 +++++++++ internal/gitsources/gitea/gitea.go | 96 +++++++++++++++++++++ internal/gitsources/github/github.go | 96 +++++++++++++++++++++ internal/gitsources/gitlab/gitlab.go | 104 +++++++++++++++++++++++ internal/gitsources/gitsource.go | 31 +++++++ 5 files changed, 367 insertions(+) diff --git a/internal/gitsources/agolagit/agolagit.go b/internal/gitsources/agolagit/agolagit.go index a55f777..bc01e52 100644 --- a/internal/gitsources/agolagit/agolagit.go +++ b/internal/gitsources/agolagit/agolagit.go @@ -168,3 +168,43 @@ func (c *Client) CreateCommitStatus(repopath, commitSHA string, status gitsource func (c *Client) ListUserRepos() ([]*gitsource.RepoInfo, error) { return nil, nil } + +func (c *Client) GetRef(repopath, ref string) (*gitsource.Ref, error) { + return nil, nil +} + +func (c *Client) RefType(ref string) (gitsource.RefType, string, error) { + return -1, "", nil +} + +func (c *Client) GetCommit(repopath, commitSHA string) (*gitsource.Commit, error) { + return nil, nil +} + +func (c *Client) BranchRef(branch string) string { + return "" +} + +func (c *Client) TagRef(tag string) string { + return "" +} + +func (c *Client) PullRequestRef(prID string) string { + return "" +} + +func (c *Client) CommitLink(repoInfo *gitsource.RepoInfo, commitSHA string) string { + return "" +} + +func (c *Client) BranchLink(repoInfo *gitsource.RepoInfo, branch string) string { + return "" +} + +func (c *Client) TagLink(repoInfo *gitsource.RepoInfo, tag string) string { + return "" +} + +func (c *Client) PullRequestLink(repoInfo *gitsource.RepoInfo, prID string) string { + return "" +} diff --git a/internal/gitsources/gitea/gitea.go b/internal/gitsources/gitea/gitea.go index 9dd9d61..372c570 100644 --- a/internal/gitsources/gitea/gitea.go +++ b/internal/gitsources/gitea/gitea.go @@ -23,6 +23,7 @@ import ( "net" "net/http" "path" + "regexp" "strconv" "strings" "time" @@ -45,6 +46,11 @@ const ( var ( // gitea corrently doesn't have any auth scope GiteaOauth2Scopes = []string{""} + + branchRefPrefix = "refs/heads/" + tagRefPrefix = "refs/tags/" + pullRequestRefRegex = regexp.MustCompile("refs/pull/(.*)/head") + pullRequestRefFmt = "refs/pull/%s/head" ) type Opts struct { @@ -397,3 +403,93 @@ func fromGiteaRepo(rr *gitea.Repository) *gitsource.RepoInfo { HTTPCloneURL: rr.CloneURL, } } + +func (c *Client) GetRef(repopath, ref string) (*gitsource.Ref, error) { + owner, reponame, err := parseRepoPath(repopath) + if err != nil { + return nil, err + } + + remoteRef, err := c.client.GetRepoRef(owner, reponame, ref) + if err != nil { + return nil, err + } + + return fromGiteaRef(remoteRef) +} + +func fromGiteaRef(remoteRef *gitea.Reference) (*gitsource.Ref, error) { + t := remoteRef.Object.Type + switch t { + case "commit": + default: + return nil, fmt.Errorf("unsupported object type: %s", t) + } + + return &gitsource.Ref{ + Ref: remoteRef.Ref, + CommitSHA: remoteRef.Object.SHA, + }, nil +} + +func (c *Client) RefType(ref string) (gitsource.RefType, string, error) { + switch { + case strings.HasPrefix(ref, branchRefPrefix): + return gitsource.RefTypeBranch, strings.TrimPrefix(ref, branchRefPrefix), nil + + case strings.HasPrefix(ref, tagRefPrefix): + return gitsource.RefTypeTag, strings.TrimPrefix(ref, tagRefPrefix), nil + + case pullRequestRefRegex.MatchString(ref): + m := pullRequestRefRegex.FindStringSubmatch(ref) + return gitsource.RefTypePullRequest, m[0], nil + + default: + return -1, "", fmt.Errorf("unsupported ref: %s", ref) + } +} + +func (c *Client) GetCommit(repopath, commitSHA string) (*gitsource.Commit, error) { + owner, reponame, err := parseRepoPath(repopath) + if err != nil { + return nil, err + } + + commit, err := c.client.GetSingleCommit(owner, reponame, commitSHA) + if err != nil { + return nil, err + } + + return &gitsource.Commit{ + SHA: commit.SHA, + Message: commit.RepoCommit.Message, + }, nil +} + +func (c *Client) BranchRef(branch string) string { + return branchRefPrefix + branch +} + +func (c *Client) TagRef(tag string) string { + return tagRefPrefix + tag +} + +func (c *Client) PullRequestRef(prID string) string { + return fmt.Sprintf(pullRequestRefFmt, prID) +} + +func (c *Client) CommitLink(repoInfo *gitsource.RepoInfo, commitSHA string) string { + return fmt.Sprintf("%s/commit/%s", repoInfo.HTMLURL, commitSHA) +} + +func (c *Client) BranchLink(repoInfo *gitsource.RepoInfo, branch string) string { + return fmt.Sprintf("%s/src/branch/%s", repoInfo.HTMLURL, branch) +} + +func (c *Client) TagLink(repoInfo *gitsource.RepoInfo, tag string) string { + return fmt.Sprintf("%s/src/tag/%s", repoInfo.HTMLURL, tag) +} + +func (c *Client) PullRequestLink(repoInfo *gitsource.RepoInfo, prID string) string { + return fmt.Sprintf("%s/pulls/%s", repoInfo.HTMLURL, prID) +} diff --git a/internal/gitsources/github/github.go b/internal/gitsources/github/github.go index 7d4621a..fb1ca77 100644 --- a/internal/gitsources/github/github.go +++ b/internal/gitsources/github/github.go @@ -23,6 +23,7 @@ import ( "net/http" "net/url" "path" + "regexp" "strconv" "strings" "time" @@ -36,6 +37,11 @@ import ( var ( GitHubOauth2Scopes = []string{"repo"} + + branchRefPrefix = "refs/heads/" + tagRefPrefix = "refs/tags/" + pullRequestRefRegex = regexp.MustCompile("refs/pull/(.*)/head") + pullRequestRefFmt = "refs/pull/%s/head" ) const ( @@ -392,3 +398,93 @@ func fromGithubRepo(rr *github.Repository) *gitsource.RepoInfo { HTTPCloneURL: *rr.CloneURL, } } + +func (c *Client) GetRef(repopath, ref string) (*gitsource.Ref, error) { + owner, reponame, err := parseRepoPath(repopath) + if err != nil { + return nil, err + } + + remoteRef, _, err := c.client.Git.GetRef(context.TODO(), owner, reponame, ref) + if err != nil { + return nil, err + } + + return fromGithubRef(remoteRef) +} + +func fromGithubRef(remoteRef *github.Reference) (*gitsource.Ref, error) { + t := *(remoteRef.Object.Type) + switch t { + case "commit": + default: + return nil, fmt.Errorf("unsupported object type: %s", t) + } + + return &gitsource.Ref{ + Ref: *remoteRef.Ref, + CommitSHA: *remoteRef.Object.SHA, + }, nil +} + +func (c *Client) RefType(ref string) (gitsource.RefType, string, error) { + switch { + case strings.HasPrefix(ref, branchRefPrefix): + return gitsource.RefTypeBranch, strings.TrimPrefix(ref, branchRefPrefix), nil + + case strings.HasPrefix(ref, tagRefPrefix): + return gitsource.RefTypeTag, strings.TrimPrefix(ref, tagRefPrefix), nil + + case pullRequestRefRegex.MatchString(ref): + m := pullRequestRefRegex.FindStringSubmatch(ref) + return gitsource.RefTypePullRequest, m[0], nil + + default: + return -1, "", fmt.Errorf("unsupported ref: %s", ref) + } +} + +func (c *Client) GetCommit(repopath, commitSHA string) (*gitsource.Commit, error) { + owner, reponame, err := parseRepoPath(repopath) + if err != nil { + return nil, err + } + + commit, _, err := c.client.Git.GetCommit(context.TODO(), owner, reponame, commitSHA) + if err != nil { + return nil, err + } + + return &gitsource.Commit{ + SHA: *commit.SHA, + Message: *commit.Message, + }, nil +} + +func (c *Client) BranchRef(branch string) string { + return branchRefPrefix + branch +} + +func (c *Client) TagRef(tag string) string { + return tagRefPrefix + tag +} + +func (c *Client) PullRequestRef(prID string) string { + return fmt.Sprintf(pullRequestRefFmt, prID) +} + +func (c *Client) CommitLink(repoInfo *gitsource.RepoInfo, commitSHA string) string { + return fmt.Sprintf("%s/commit/%s", repoInfo.HTMLURL, commitSHA) +} + +func (c *Client) BranchLink(repoInfo *gitsource.RepoInfo, branch string) string { + return fmt.Sprintf("%s/src/branch/%s", repoInfo.HTMLURL, branch) +} + +func (c *Client) TagLink(repoInfo *gitsource.RepoInfo, tag string) string { + return fmt.Sprintf("%s/src/tag/%s", repoInfo.HTMLURL, tag) +} + +func (c *Client) PullRequestLink(repoInfo *gitsource.RepoInfo, prID string) string { + return fmt.Sprintf("%s/pull/%s", repoInfo.HTMLURL, prID) +} diff --git a/internal/gitsources/gitlab/gitlab.go b/internal/gitsources/gitlab/gitlab.go index a0198e8..1f39381 100644 --- a/internal/gitsources/gitlab/gitlab.go +++ b/internal/gitsources/gitlab/gitlab.go @@ -21,7 +21,9 @@ import ( "fmt" "net" "net/http" + "regexp" "strconv" + "strings" "time" gitsource "github.com/sorintlab/agola/internal/gitsources" @@ -33,6 +35,11 @@ import ( var ( GitlabOauth2Scopes = []string{"api"} + + branchRefPrefix = "refs/heads/" + tagRefPrefix = "refs/tags/" + pullRequestRefRegex = regexp.MustCompile("refs/merge-requests/(.*)/head") + pullRequestRefFmt = "refs/merge-requests/%s/head" ) type Opts struct { @@ -284,3 +291,100 @@ func fromGitlabRepo(rr *gitlab.Project) *gitsource.RepoInfo { HTTPCloneURL: rr.HTTPURLToRepo, } } + +// NOTE(sgotti) gitlab doesn't provide a get ref api +func (c *Client) GetRef(repopath, ref string) (*gitsource.Ref, error) { + switch { + case strings.HasPrefix(ref, "refs/heads/"): + + branch := strings.TrimPrefix(ref, "refs/heads/") + remoteBranch, _, err := c.client.Branches.GetBranch(repopath, branch) + if err != nil { + return nil, err + } + + if err != nil { + return nil, err + } + + return &gitsource.Ref{ + Ref: ref, + CommitSHA: remoteBranch.Commit.ID, + }, nil + + case strings.HasPrefix(ref, "refs/tags/"): + tag := strings.TrimPrefix(ref, "refs/heads/") + remoteTag, _, err := c.client.Tags.GetTag(repopath, tag) + if err != nil { + return nil, err + } + + if err != nil { + return nil, err + } + + return &gitsource.Ref{ + Ref: ref, + CommitSHA: remoteTag.Commit.ID, + }, nil + default: + return nil, fmt.Errorf("unsupported ref: %s", ref) + } +} + +func (c *Client) RefType(ref string) (gitsource.RefType, string, error) { + switch { + case strings.HasPrefix(ref, branchRefPrefix): + return gitsource.RefTypeBranch, strings.TrimPrefix(ref, branchRefPrefix), nil + + case strings.HasPrefix(ref, tagRefPrefix): + return gitsource.RefTypeTag, strings.TrimPrefix(ref, tagRefPrefix), nil + + case pullRequestRefRegex.MatchString(ref): + m := pullRequestRefRegex.FindStringSubmatch(ref) + return gitsource.RefTypePullRequest, m[0], nil + + default: + return -1, "", fmt.Errorf("unsupported ref: %s", ref) + } +} + +func (c *Client) GetCommit(repopath, commitSHA string) (*gitsource.Commit, error) { + commit, _, err := c.client.Commits.GetCommit(repopath, commitSHA, nil) + if err != nil { + return nil, err + } + + return &gitsource.Commit{ + SHA: commit.ID, + Message: commit.Message, + }, nil +} + +func (c *Client) BranchRef(branch string) string { + return branchRefPrefix + branch +} + +func (c *Client) TagRef(tag string) string { + return tagRefPrefix + tag +} + +func (c *Client) PullRequestRef(prID string) string { + return fmt.Sprintf(pullRequestRefFmt, prID) +} + +func (c *Client) CommitLink(repoInfo *gitsource.RepoInfo, commitSHA string) string { + return fmt.Sprintf("%s/commit/%s", repoInfo.HTMLURL, commitSHA) +} + +func (c *Client) BranchLink(repoInfo *gitsource.RepoInfo, branch string) string { + return fmt.Sprintf("%s/tree/%s", repoInfo.HTMLURL, branch) +} + +func (c *Client) TagLink(repoInfo *gitsource.RepoInfo, tag string) string { + return fmt.Sprintf("%s/tree/%s", repoInfo.HTMLURL, tag) +} + +func (c *Client) PullRequestLink(repoInfo *gitsource.RepoInfo, prID string) string { + return fmt.Sprintf("%s/merge_requests/%s", repoInfo.HTMLURL, prID) +} diff --git a/internal/gitsources/gitsource.go b/internal/gitsources/gitsource.go index 7e97b57..0b83b87 100644 --- a/internal/gitsources/gitsource.go +++ b/internal/gitsources/gitsource.go @@ -45,6 +45,19 @@ type GitSource interface { CreateCommitStatus(repopath, commitSHA string, status CommitStatus, targetURL, description, context string) error // ListUserRepos report repos where the user has the permission to create deploy keys and webhooks ListUserRepos() ([]*RepoInfo, error) + GetRef(repopath, ref string) (*Ref, error) + // RefType returns the ref type and the related name (branch, tag, pr id) + RefType(ref string) (RefType, string, error) + GetCommit(repopath, commitSHA string) (*Commit, error) + + BranchRef(branch string) string + TagRef(tag string) string + PullRequestRef(prID string) string + + CommitLink(repoInfo *RepoInfo, commitSHA string) string + BranchLink(repoInfo *RepoInfo, branch string) string + TagLink(repoInfo *RepoInfo, tag string) string + PullRequestLink(repoInfo *RepoInfo, prID string) string } type UserSource interface { @@ -80,3 +93,21 @@ type UserInfo struct { LoginName string Email string } + +type RefType int + +const ( + RefTypeBranch RefType = iota + RefTypeTag + RefTypePullRequest +) + +type Ref struct { + Ref string + CommitSHA string +} + +type Commit struct { + SHA string + Message string +}