github.com/google/go-github/v66@v66.0.0/github/repos_commits.go (about)

     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  
     6  package github
     7  
     8  import (
     9  	"bytes"
    10  	"context"
    11  	"fmt"
    12  	"net/url"
    13  	"time"
    14  )
    15  
    16  // RepositoryCommit represents a commit in a repo.
    17  // Note that it's wrapping a Commit, so author/committer information is in two places,
    18  // but contain different details about them: in RepositoryCommit "github details", in Commit - "git details".
    19  type RepositoryCommit struct {
    20  	NodeID      *string   `json:"node_id,omitempty"`
    21  	SHA         *string   `json:"sha,omitempty"`
    22  	Commit      *Commit   `json:"commit,omitempty"`
    23  	Author      *User     `json:"author,omitempty"`
    24  	Committer   *User     `json:"committer,omitempty"`
    25  	Parents     []*Commit `json:"parents,omitempty"`
    26  	HTMLURL     *string   `json:"html_url,omitempty"`
    27  	URL         *string   `json:"url,omitempty"`
    28  	CommentsURL *string   `json:"comments_url,omitempty"`
    29  
    30  	// Details about how many changes were made in this commit. Only filled in during GetCommit!
    31  	Stats *CommitStats `json:"stats,omitempty"`
    32  	// Details about which files, and how this commit touched. Only filled in during GetCommit!
    33  	Files []*CommitFile `json:"files,omitempty"`
    34  }
    35  
    36  func (r RepositoryCommit) String() string {
    37  	return Stringify(r)
    38  }
    39  
    40  // CommitStats represents the number of additions / deletions from a file in a given RepositoryCommit or GistCommit.
    41  type CommitStats struct {
    42  	Additions *int `json:"additions,omitempty"`
    43  	Deletions *int `json:"deletions,omitempty"`
    44  	Total     *int `json:"total,omitempty"`
    45  }
    46  
    47  func (c CommitStats) String() string {
    48  	return Stringify(c)
    49  }
    50  
    51  // CommitFile represents a file modified in a commit.
    52  type CommitFile struct {
    53  	SHA              *string `json:"sha,omitempty"`
    54  	Filename         *string `json:"filename,omitempty"`
    55  	Additions        *int    `json:"additions,omitempty"`
    56  	Deletions        *int    `json:"deletions,omitempty"`
    57  	Changes          *int    `json:"changes,omitempty"`
    58  	Status           *string `json:"status,omitempty"`
    59  	Patch            *string `json:"patch,omitempty"`
    60  	BlobURL          *string `json:"blob_url,omitempty"`
    61  	RawURL           *string `json:"raw_url,omitempty"`
    62  	ContentsURL      *string `json:"contents_url,omitempty"`
    63  	PreviousFilename *string `json:"previous_filename,omitempty"`
    64  }
    65  
    66  func (c CommitFile) String() string {
    67  	return Stringify(c)
    68  }
    69  
    70  // CommitsComparison is the result of comparing two commits.
    71  // See CompareCommits() for details.
    72  type CommitsComparison struct {
    73  	BaseCommit      *RepositoryCommit `json:"base_commit,omitempty"`
    74  	MergeBaseCommit *RepositoryCommit `json:"merge_base_commit,omitempty"`
    75  
    76  	// Head can be 'behind' or 'ahead'
    77  	Status       *string `json:"status,omitempty"`
    78  	AheadBy      *int    `json:"ahead_by,omitempty"`
    79  	BehindBy     *int    `json:"behind_by,omitempty"`
    80  	TotalCommits *int    `json:"total_commits,omitempty"`
    81  
    82  	Commits []*RepositoryCommit `json:"commits,omitempty"`
    83  
    84  	Files []*CommitFile `json:"files,omitempty"`
    85  
    86  	HTMLURL      *string `json:"html_url,omitempty"`
    87  	PermalinkURL *string `json:"permalink_url,omitempty"`
    88  	DiffURL      *string `json:"diff_url,omitempty"`
    89  	PatchURL     *string `json:"patch_url,omitempty"`
    90  	URL          *string `json:"url,omitempty"` // API URL.
    91  }
    92  
    93  func (c CommitsComparison) String() string {
    94  	return Stringify(c)
    95  }
    96  
    97  // CommitsListOptions specifies the optional parameters to the
    98  // RepositoriesService.ListCommits method.
    99  type CommitsListOptions struct {
   100  	// SHA or branch to start listing Commits from.
   101  	SHA string `url:"sha,omitempty"`
   102  
   103  	// Path that should be touched by the returned Commits.
   104  	Path string `url:"path,omitempty"`
   105  
   106  	// Author of by which to filter Commits.
   107  	Author string `url:"author,omitempty"`
   108  
   109  	// Since when should Commits be included in the response.
   110  	Since time.Time `url:"since,omitempty"`
   111  
   112  	// Until when should Commits be included in the response.
   113  	Until time.Time `url:"until,omitempty"`
   114  
   115  	ListOptions
   116  }
   117  
   118  // BranchCommit is the result of listing branches with commit SHA.
   119  type BranchCommit struct {
   120  	Name      *string `json:"name,omitempty"`
   121  	Commit    *Commit `json:"commit,omitempty"`
   122  	Protected *bool   `json:"protected,omitempty"`
   123  }
   124  
   125  // ListCommits lists the commits of a repository.
   126  //
   127  // GitHub API docs: https://docs.github.com/rest/commits/commits#list-commits
   128  //
   129  //meta:operation GET /repos/{owner}/{repo}/commits
   130  func (s *RepositoriesService) ListCommits(ctx context.Context, owner, repo string, opts *CommitsListOptions) ([]*RepositoryCommit, *Response, error) {
   131  	u := fmt.Sprintf("repos/%v/%v/commits", owner, repo)
   132  	u, err := addOptions(u, opts)
   133  	if err != nil {
   134  		return nil, nil, err
   135  	}
   136  
   137  	req, err := s.client.NewRequest("GET", u, nil)
   138  	if err != nil {
   139  		return nil, nil, err
   140  	}
   141  
   142  	var commits []*RepositoryCommit
   143  	resp, err := s.client.Do(ctx, req, &commits)
   144  	if err != nil {
   145  		return nil, resp, err
   146  	}
   147  
   148  	return commits, resp, nil
   149  }
   150  
   151  // GetCommit fetches the specified commit, including all details about it.
   152  //
   153  // GitHub API docs: https://docs.github.com/rest/commits/commits#get-a-commit
   154  //
   155  //meta:operation GET /repos/{owner}/{repo}/commits/{ref}
   156  func (s *RepositoriesService) GetCommit(ctx context.Context, owner, repo, sha string, opts *ListOptions) (*RepositoryCommit, *Response, error) {
   157  	u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, sha)
   158  	u, err := addOptions(u, opts)
   159  	if err != nil {
   160  		return nil, nil, err
   161  	}
   162  
   163  	req, err := s.client.NewRequest("GET", u, nil)
   164  	if err != nil {
   165  		return nil, nil, err
   166  	}
   167  
   168  	commit := new(RepositoryCommit)
   169  	resp, err := s.client.Do(ctx, req, commit)
   170  	if err != nil {
   171  		return nil, resp, err
   172  	}
   173  
   174  	return commit, resp, nil
   175  }
   176  
   177  // GetCommitRaw fetches the specified commit in raw (diff or patch) format.
   178  //
   179  // GitHub API docs: https://docs.github.com/rest/commits/commits#get-a-commit
   180  //
   181  //meta:operation GET /repos/{owner}/{repo}/commits/{ref}
   182  func (s *RepositoriesService) GetCommitRaw(ctx context.Context, owner string, repo string, sha string, opts RawOptions) (string, *Response, error) {
   183  	u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, sha)
   184  	req, err := s.client.NewRequest("GET", u, nil)
   185  	if err != nil {
   186  		return "", nil, err
   187  	}
   188  
   189  	switch opts.Type {
   190  	case Diff:
   191  		req.Header.Set("Accept", mediaTypeV3Diff)
   192  	case Patch:
   193  		req.Header.Set("Accept", mediaTypeV3Patch)
   194  	default:
   195  		return "", nil, fmt.Errorf("unsupported raw type %d", opts.Type)
   196  	}
   197  
   198  	var buf bytes.Buffer
   199  	resp, err := s.client.Do(ctx, req, &buf)
   200  	if err != nil {
   201  		return "", resp, err
   202  	}
   203  
   204  	return buf.String(), resp, nil
   205  }
   206  
   207  // GetCommitSHA1 gets the SHA-1 of a commit reference. If a last-known SHA1 is
   208  // supplied and no new commits have occurred, a 304 Unmodified response is returned.
   209  //
   210  // GitHub API docs: https://docs.github.com/rest/commits/commits#get-a-commit
   211  //
   212  //meta:operation GET /repos/{owner}/{repo}/commits/{ref}
   213  func (s *RepositoriesService) GetCommitSHA1(ctx context.Context, owner, repo, ref, lastSHA string) (string, *Response, error) {
   214  	u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, refURLEscape(ref))
   215  
   216  	req, err := s.client.NewRequest("GET", u, nil)
   217  	if err != nil {
   218  		return "", nil, err
   219  	}
   220  	if lastSHA != "" {
   221  		req.Header.Set("If-None-Match", `"`+lastSHA+`"`)
   222  	}
   223  
   224  	req.Header.Set("Accept", mediaTypeV3SHA)
   225  
   226  	var buf bytes.Buffer
   227  	resp, err := s.client.Do(ctx, req, &buf)
   228  	if err != nil {
   229  		return "", resp, err
   230  	}
   231  
   232  	return buf.String(), resp, nil
   233  }
   234  
   235  // CompareCommits compares a range of commits with each other.
   236  //
   237  // GitHub API docs: https://docs.github.com/rest/commits/commits#compare-two-commits
   238  //
   239  //meta:operation GET /repos/{owner}/{repo}/compare/{basehead}
   240  func (s *RepositoriesService) CompareCommits(ctx context.Context, owner, repo string, base, head string, opts *ListOptions) (*CommitsComparison, *Response, error) {
   241  	escapedBase := url.QueryEscape(base)
   242  	escapedHead := url.QueryEscape(head)
   243  
   244  	u := fmt.Sprintf("repos/%v/%v/compare/%v...%v", owner, repo, escapedBase, escapedHead)
   245  	u, err := addOptions(u, opts)
   246  	if err != nil {
   247  		return nil, nil, err
   248  	}
   249  
   250  	req, err := s.client.NewRequest("GET", u, nil)
   251  	if err != nil {
   252  		return nil, nil, err
   253  	}
   254  
   255  	comp := new(CommitsComparison)
   256  	resp, err := s.client.Do(ctx, req, comp)
   257  	if err != nil {
   258  		return nil, resp, err
   259  	}
   260  
   261  	return comp, resp, nil
   262  }
   263  
   264  // CompareCommitsRaw compares a range of commits with each other in raw (diff or patch) format.
   265  //
   266  // Both "base" and "head" must be branch names in "repo".
   267  // To compare branches across other repositories in the same network as "repo",
   268  // use the format "<USERNAME>:branch".
   269  //
   270  // GitHub API docs: https://docs.github.com/rest/commits/commits#compare-two-commits
   271  //
   272  //meta:operation GET /repos/{owner}/{repo}/compare/{basehead}
   273  func (s *RepositoriesService) CompareCommitsRaw(ctx context.Context, owner, repo, base, head string, opts RawOptions) (string, *Response, error) {
   274  	escapedBase := url.QueryEscape(base)
   275  	escapedHead := url.QueryEscape(head)
   276  
   277  	u := fmt.Sprintf("repos/%v/%v/compare/%v...%v", owner, repo, escapedBase, escapedHead)
   278  
   279  	req, err := s.client.NewRequest("GET", u, nil)
   280  	if err != nil {
   281  		return "", nil, err
   282  	}
   283  
   284  	switch opts.Type {
   285  	case Diff:
   286  		req.Header.Set("Accept", mediaTypeV3Diff)
   287  	case Patch:
   288  		req.Header.Set("Accept", mediaTypeV3Patch)
   289  	default:
   290  		return "", nil, fmt.Errorf("unsupported raw type %d", opts.Type)
   291  	}
   292  
   293  	var buf bytes.Buffer
   294  	resp, err := s.client.Do(ctx, req, &buf)
   295  	if err != nil {
   296  		return "", resp, err
   297  	}
   298  
   299  	return buf.String(), resp, nil
   300  }
   301  
   302  // ListBranchesHeadCommit gets all branches where the given commit SHA is the HEAD,
   303  // or latest commit for the branch.
   304  //
   305  // GitHub API docs: https://docs.github.com/rest/commits/commits#list-branches-for-head-commit
   306  //
   307  //meta:operation GET /repos/{owner}/{repo}/commits/{commit_sha}/branches-where-head
   308  func (s *RepositoriesService) ListBranchesHeadCommit(ctx context.Context, owner, repo, sha string) ([]*BranchCommit, *Response, error) {
   309  	u := fmt.Sprintf("repos/%v/%v/commits/%v/branches-where-head", owner, repo, sha)
   310  
   311  	req, err := s.client.NewRequest("GET", u, nil)
   312  	if err != nil {
   313  		return nil, nil, err
   314  	}
   315  
   316  	// TODO: remove custom Accept header when this API fully launches.
   317  	req.Header.Set("Accept", mediaTypeListPullsOrBranchesForCommitPreview)
   318  	var branchCommits []*BranchCommit
   319  	resp, err := s.client.Do(ctx, req, &branchCommits)
   320  	if err != nil {
   321  		return nil, resp, err
   322  	}
   323  
   324  	return branchCommits, resp, nil
   325  }