1// Copyright 2013 The go-github AUTHORS. All rights reserved. 2// 3// Use of this source code is governed by a BSD-style 4// license that can be found in the LICENSE file. 5 6package github 7 8import ( 9 "bytes" 10 "context" 11 "fmt" 12 "time" 13) 14 15// RepositoryCommit represents a commit in a repo. 16// Note that it's wrapping a Commit, so author/committer information is in two places, 17// but contain different details about them: in RepositoryCommit "github details", in Commit - "git details". 18type RepositoryCommit struct { 19 SHA *string `json:"sha,omitempty"` 20 Commit *Commit `json:"commit,omitempty"` 21 Author *User `json:"author,omitempty"` 22 Committer *User `json:"committer,omitempty"` 23 Parents []Commit `json:"parents,omitempty"` 24 HTMLURL *string `json:"html_url,omitempty"` 25 URL *string `json:"url,omitempty"` 26 CommentsURL *string `json:"comments_url,omitempty"` 27 28 // Details about how many changes were made in this commit. Only filled in during GetCommit! 29 Stats *CommitStats `json:"stats,omitempty"` 30 // Details about which files, and how this commit touched. Only filled in during GetCommit! 31 Files []CommitFile `json:"files,omitempty"` 32} 33 34func (r RepositoryCommit) String() string { 35 return Stringify(r) 36} 37 38// CommitStats represents the number of additions / deletions from a file in a given RepositoryCommit or GistCommit. 39type CommitStats struct { 40 Additions *int `json:"additions,omitempty"` 41 Deletions *int `json:"deletions,omitempty"` 42 Total *int `json:"total,omitempty"` 43} 44 45func (c CommitStats) String() string { 46 return Stringify(c) 47} 48 49// CommitFile represents a file modified in a commit. 50type CommitFile struct { 51 SHA *string `json:"sha,omitempty"` 52 Filename *string `json:"filename,omitempty"` 53 Additions *int `json:"additions,omitempty"` 54 Deletions *int `json:"deletions,omitempty"` 55 Changes *int `json:"changes,omitempty"` 56 Status *string `json:"status,omitempty"` 57 Patch *string `json:"patch,omitempty"` 58 BlobURL *string `json:"blob_url,omitempty"` 59 RawURL *string `json:"raw_url,omitempty"` 60 ContentsURL *string `json:"contents_url,omitempty"` 61} 62 63func (c CommitFile) String() string { 64 return Stringify(c) 65} 66 67// CommitsComparison is the result of comparing two commits. 68// See CompareCommits() for details. 69type CommitsComparison struct { 70 BaseCommit *RepositoryCommit `json:"base_commit,omitempty"` 71 MergeBaseCommit *RepositoryCommit `json:"merge_base_commit,omitempty"` 72 73 // Head can be 'behind' or 'ahead' 74 Status *string `json:"status,omitempty"` 75 AheadBy *int `json:"ahead_by,omitempty"` 76 BehindBy *int `json:"behind_by,omitempty"` 77 TotalCommits *int `json:"total_commits,omitempty"` 78 79 Commits []RepositoryCommit `json:"commits,omitempty"` 80 81 Files []CommitFile `json:"files,omitempty"` 82 83 HTMLURL *string `json:"html_url,omitempty"` 84 PermalinkURL *string `json:"permalink_url,omitempty"` 85 DiffURL *string `json:"diff_url,omitempty"` 86 PatchURL *string `json:"patch_url,omitempty"` 87 URL *string `json:"url,omitempty"` // API URL. 88} 89 90func (c CommitsComparison) String() string { 91 return Stringify(c) 92} 93 94// CommitsListOptions specifies the optional parameters to the 95// RepositoriesService.ListCommits method. 96type CommitsListOptions struct { 97 // SHA or branch to start listing Commits from. 98 SHA string `url:"sha,omitempty"` 99 100 // Path that should be touched by the returned Commits. 101 Path string `url:"path,omitempty"` 102 103 // Author of by which to filter Commits. 104 Author string `url:"author,omitempty"` 105 106 // Since when should Commits be included in the response. 107 Since time.Time `url:"since,omitempty"` 108 109 // Until when should Commits be included in the response. 110 Until time.Time `url:"until,omitempty"` 111 112 ListOptions 113} 114 115// ListCommits lists the commits of a repository. 116// 117// GitHub API docs: https://developer.github.com/v3/repos/commits/#list 118func (s *RepositoriesService) ListCommits(ctx context.Context, owner, repo string, opt *CommitsListOptions) ([]*RepositoryCommit, *Response, error) { 119 u := fmt.Sprintf("repos/%v/%v/commits", owner, repo) 120 u, err := addOptions(u, opt) 121 if err != nil { 122 return nil, nil, err 123 } 124 125 req, err := s.client.NewRequest("GET", u, nil) 126 if err != nil { 127 return nil, nil, err 128 } 129 130 // TODO: remove custom Accept header when this API fully launches. 131 req.Header.Set("Accept", mediaTypeGitSigningPreview) 132 133 var commits []*RepositoryCommit 134 resp, err := s.client.Do(ctx, req, &commits) 135 if err != nil { 136 return nil, resp, err 137 } 138 139 return commits, resp, nil 140} 141 142// GetCommit fetches the specified commit, including all details about it. 143// 144// GitHub API docs: https://developer.github.com/v3/repos/commits/#get-a-single-commit 145// See also: https://developer.github.com/v3/git/commits/#get-a-single-commit provides the same functionality 146func (s *RepositoriesService) GetCommit(ctx context.Context, owner, repo, sha string) (*RepositoryCommit, *Response, error) { 147 u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, sha) 148 149 req, err := s.client.NewRequest("GET", u, nil) 150 if err != nil { 151 return nil, nil, err 152 } 153 154 // TODO: remove custom Accept header when this API fully launches. 155 req.Header.Set("Accept", mediaTypeGitSigningPreview) 156 157 commit := new(RepositoryCommit) 158 resp, err := s.client.Do(ctx, req, commit) 159 if err != nil { 160 return nil, resp, err 161 } 162 163 return commit, resp, nil 164} 165 166// GetCommitRaw fetches the specified commit in raw (diff or patch) format. 167func (s *RepositoriesService) GetCommitRaw(ctx context.Context, owner string, repo string, sha string, opt RawOptions) (string, *Response, error) { 168 u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, sha) 169 req, err := s.client.NewRequest("GET", u, nil) 170 if err != nil { 171 return "", nil, err 172 } 173 174 switch opt.Type { 175 case Diff: 176 req.Header.Set("Accept", mediaTypeV3Diff) 177 case Patch: 178 req.Header.Set("Accept", mediaTypeV3Patch) 179 default: 180 return "", nil, fmt.Errorf("unsupported raw type %d", opt.Type) 181 } 182 183 var buf bytes.Buffer 184 resp, err := s.client.Do(ctx, req, &buf) 185 if err != nil { 186 return "", resp, err 187 } 188 189 return buf.String(), resp, nil 190} 191 192// GetCommitSHA1 gets the SHA-1 of a commit reference. If a last-known SHA1 is 193// supplied and no new commits have occurred, a 304 Unmodified response is returned. 194// 195// GitHub API docs: https://developer.github.com/v3/repos/commits/#get-the-sha-1-of-a-commit-reference 196func (s *RepositoriesService) GetCommitSHA1(ctx context.Context, owner, repo, ref, lastSHA string) (string, *Response, error) { 197 u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, ref) 198 199 req, err := s.client.NewRequest("GET", u, nil) 200 if err != nil { 201 return "", nil, err 202 } 203 if lastSHA != "" { 204 req.Header.Set("If-None-Match", `"`+lastSHA+`"`) 205 } 206 207 req.Header.Set("Accept", mediaTypeV3SHA) 208 209 var buf bytes.Buffer 210 resp, err := s.client.Do(ctx, req, &buf) 211 if err != nil { 212 return "", resp, err 213 } 214 215 return buf.String(), resp, nil 216} 217 218// CompareCommits compares a range of commits with each other. 219// todo: support media formats - https://github.com/google/go-github/issues/6 220// 221// GitHub API docs: https://developer.github.com/v3/repos/commits/#compare-two-commits 222func (s *RepositoriesService) CompareCommits(ctx context.Context, owner, repo string, base, head string) (*CommitsComparison, *Response, error) { 223 u := fmt.Sprintf("repos/%v/%v/compare/%v...%v", owner, repo, base, head) 224 225 req, err := s.client.NewRequest("GET", u, nil) 226 if err != nil { 227 return nil, nil, err 228 } 229 230 comp := new(CommitsComparison) 231 resp, err := s.client.Do(ctx, req, comp) 232 if err != nil { 233 return nil, resp, err 234 } 235 236 return comp, resp, nil 237} 238