github.com/covergates/covergates@v0.2.2-0.20201009050117-42ef8a19fb95/modules/scm/git.go (about) 1 package scm 2 3 import ( 4 "context" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "io/ioutil" 9 "net/http" 10 "net/url" 11 "time" 12 13 "github.com/covergates/covergates/core" 14 "github.com/drone/go-scm/scm" 15 "github.com/drone/go-scm/scm/driver/github" 16 log "github.com/sirupsen/logrus" 17 ) 18 19 type gitService struct { 20 git core.Git 21 scm core.SCMProvider 22 scmClient *scm.Client 23 } 24 25 type giteaCommit struct { 26 Sha string `json:"sha"` 27 Commit *giteaRepoCommit `json:"commit"` 28 Committer *giteaUser `json:"committer"` 29 } 30 31 type githubCommit struct { 32 SHA string `json:"sha"` 33 Commit struct { 34 Committer struct { 35 Name string `json:"name"` 36 Email string `json:"email"` 37 Date time.Time `json:"date"` 38 } `json:"committer"` 39 Message string `json:"message"` 40 } `json:"commit"` 41 Committer struct { 42 AvatarURL string `json:"avatar_url"` 43 Login string `json:"login"` 44 } `json:"committer"` 45 } 46 47 type giteaRepoCommit struct { 48 Message string `json:"message"` 49 Committer *giteaCommitUser `json:"committer"` 50 } 51 52 type giteaCommitUser struct { 53 Name string `json:"name"` 54 } 55 56 type giteaUser struct { 57 UserName string `json:"username"` 58 Avatar string `json:"avatar_url"` 59 } 60 61 func (service *gitService) FindCommit(ctx context.Context, user *core.User, repo *core.Repo) string { 62 client := service.scmClient 63 ctx = withUser(ctx, service.scm, user) 64 ref, _, err := client.Git.FindBranch( 65 ctx, 66 fmt.Sprintf("%s/%s", repo.NameSpace, repo.Name), 67 repo.Branch, 68 ) 69 if err != nil { 70 return "" 71 } 72 return ref.Sha 73 } 74 75 func (service *gitService) ListCommits(ctx context.Context, user *core.User, repo string) ([]*core.Commit, error) { 76 ctx = withUser(ctx, service.scm, user) 77 if service.scm == core.Gitea { 78 return service.listGiteaCommits(ctx, repo, "") 79 } 80 return service.listCommits(ctx, repo, "") 81 } 82 83 func (service *gitService) ListCommitsByRef(ctx context.Context, user *core.User, repo, ref string) ([]*core.Commit, error) { 84 ctx = withUser(ctx, service.scm, user) 85 switch service.scm { 86 case core.Gitea: 87 return service.listGiteaCommits(ctx, repo, ref) 88 case core.Github: 89 return service.listGithubCommits(ctx, repo, ref) 90 default: 91 return service.listCommits(ctx, repo, ref) 92 } 93 } 94 95 func (service *gitService) listCommits(ctx context.Context, repo, ref string) ([]*core.Commit, error) { 96 client := service.scmClient 97 options := scm.CommitListOptions{Size: 20} 98 if ref != "" { 99 options.Ref = ref 100 } 101 commits, _, err := client.Git.ListCommits(ctx, repo, options) 102 if err != nil { 103 return nil, err 104 } 105 results := make([]*core.Commit, len(commits)) 106 for i, commit := range commits { 107 results[i] = &core.Commit{ 108 Sha: commit.Sha, 109 Message: commit.Message, 110 Committer: commit.Committer.Name, 111 CommitterAvater: commit.Committer.Avatar, 112 } 113 } 114 return results, nil 115 } 116 117 func mustGetGiteaCommitsQuery(repo, ref string) string { 118 u, err := url.Parse(fmt.Sprintf("api/v1/repos/%s/commits", repo)) 119 if err != nil { 120 log.Fatal(err) 121 } 122 query := u.Query() 123 if ref != "" { 124 query.Set("sha", ref) 125 } 126 u.RawQuery = query.Encode() 127 return u.String() 128 } 129 130 func (service *gitService) listGiteaCommits(ctx context.Context, repo, ref string) ([]*core.Commit, error) { 131 client := service.scmClient 132 res, err := client.Do(ctx, &scm.Request{ 133 Header: map[string][]string{ 134 "Content-Type": {"application/json"}, 135 }, 136 Method: "GET", 137 Path: mustGetGiteaCommitsQuery(repo, ref), 138 }) 139 if err != nil { 140 return nil, err 141 } 142 defer res.Body.Close() 143 if res.Status > 300 { 144 return nil, errors.New(http.StatusText(res.Status)) 145 } 146 data, err := ioutil.ReadAll(res.Body) 147 if err != nil { 148 return nil, err 149 } 150 var commits []giteaCommit 151 if err := json.Unmarshal(data, &commits); err != nil { 152 return nil, err 153 } 154 results := make([]*core.Commit, len(commits)) 155 for i, commit := range commits { 156 results[i] = &core.Commit{ 157 Sha: commit.Sha, 158 Message: commit.Commit.Message, 159 } 160 if commit.Committer != nil { 161 results[i].Committer = commit.Committer.UserName 162 results[i].CommitterAvater = commit.Committer.Avatar 163 } else { 164 results[i].Committer = commit.Commit.Committer.Name 165 } 166 } 167 return results, nil 168 } 169 170 func (service *gitService) listGithubCommits(ctx context.Context, repo, ref string) ([]*core.Commit, error) { 171 params := url.Values{} 172 params.Add("sha", ref) 173 params.Add("per_page", "25") 174 175 res, err := service.scmClient.Do(ctx, &scm.Request{ 176 Method: "GET", 177 Path: fmt.Sprintf("repos/%s/commits?%s", repo, params.Encode()), 178 }) 179 if err != nil { 180 return nil, err 181 } 182 defer res.Body.Close() 183 if res.Status > 300 { 184 var err *github.Error 185 json.NewDecoder(res.Body).Decode(err) 186 return nil, err 187 } 188 var commits []*githubCommit 189 json.NewDecoder(res.Body).Decode(&commits) 190 result := make([]*core.Commit, len(commits)) 191 for i, commit := range commits { 192 result[i] = &core.Commit{ 193 Committer: commit.Commit.Committer.Name, 194 CommitterAvater: commit.Committer.AvatarURL, 195 Message: commit.Commit.Message, 196 Sha: commit.SHA, 197 } 198 } 199 return result, nil 200 } 201 202 func (service *gitService) ListBranches(ctx context.Context, user *core.User, repo string) ([]string, error) { 203 client := service.scmClient 204 ctx = withUser(ctx, service.scm, user) 205 references, _, err := client.Git.ListBranches(ctx, repo, scm.ListOptions{}) 206 if err != nil { 207 return []string{}, err 208 } 209 branches := make([]string, len(references)) 210 for i, ref := range references { 211 branches[i] = ref.Name 212 } 213 return branches, nil 214 } 215 216 // GitRepository clone 217 func (service *gitService) GitRepository(ctx context.Context, user *core.User, repo string) (core.GitRepository, error) { 218 client := service.scmClient 219 rs := &repoService{scm: service.scm, client: client} 220 token := userToken(service.scm, user) 221 ctx = withUser(ctx, service.scm, user) 222 url, err := rs.CloneURL(ctx, user, repo) 223 if err != nil { 224 return nil, err 225 } 226 return service.git.Clone(ctx, url, token.Token) 227 }