本站源代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

220 lines
6.5KB

  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. package github
  6. import (
  7. "context"
  8. "encoding/json"
  9. "errors"
  10. "fmt"
  11. "net/url"
  12. "strings"
  13. )
  14. // Reference represents a GitHub reference.
  15. type Reference struct {
  16. Ref *string `json:"ref"`
  17. URL *string `json:"url"`
  18. Object *GitObject `json:"object"`
  19. NodeID *string `json:"node_id,omitempty"`
  20. }
  21. func (r Reference) String() string {
  22. return Stringify(r)
  23. }
  24. // GitObject represents a Git object.
  25. type GitObject struct {
  26. Type *string `json:"type"`
  27. SHA *string `json:"sha"`
  28. URL *string `json:"url"`
  29. }
  30. func (o GitObject) String() string {
  31. return Stringify(o)
  32. }
  33. // createRefRequest represents the payload for creating a reference.
  34. type createRefRequest struct {
  35. Ref *string `json:"ref"`
  36. SHA *string `json:"sha"`
  37. }
  38. // updateRefRequest represents the payload for updating a reference.
  39. type updateRefRequest struct {
  40. SHA *string `json:"sha"`
  41. Force *bool `json:"force"`
  42. }
  43. // GetRef fetches a single Reference object for a given Git ref.
  44. // If there is no exact match, GetRef will return an error.
  45. //
  46. // Note: The GitHub API can return multiple matches.
  47. // If you wish to use this functionality please use the GetRefs() method.
  48. //
  49. // GitHub API docs: https://developer.github.com/v3/git/refs/#get-a-reference
  50. func (s *GitService) GetRef(ctx context.Context, owner string, repo string, ref string) (*Reference, *Response, error) {
  51. ref = strings.TrimPrefix(ref, "refs/")
  52. u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, url.QueryEscape(ref))
  53. req, err := s.client.NewRequest("GET", u, nil)
  54. if err != nil {
  55. return nil, nil, err
  56. }
  57. r := new(Reference)
  58. resp, err := s.client.Do(ctx, req, r)
  59. if _, ok := err.(*json.UnmarshalTypeError); ok {
  60. // Multiple refs, means there wasn't an exact match.
  61. return nil, resp, errors.New("no exact match found for this ref")
  62. } else if err != nil {
  63. return nil, resp, err
  64. }
  65. return r, resp, nil
  66. }
  67. // GetRefs fetches a slice of Reference objects for a given Git ref.
  68. // If there is an exact match, only that ref is returned.
  69. // If there is no exact match, GitHub returns all refs that start with ref.
  70. // If returned error is nil, there will be at least 1 ref returned.
  71. // For example:
  72. //
  73. // "heads/featureA" -> ["refs/heads/featureA"] // Exact match, single ref is returned.
  74. // "heads/feature" -> ["refs/heads/featureA", "refs/heads/featureB"] // All refs that start with ref.
  75. // "heads/notexist" -> [] // Returns an error.
  76. //
  77. // GitHub API docs: https://developer.github.com/v3/git/refs/#get-a-reference
  78. func (s *GitService) GetRefs(ctx context.Context, owner string, repo string, ref string) ([]*Reference, *Response, error) {
  79. ref = strings.TrimPrefix(ref, "refs/")
  80. u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, url.QueryEscape(ref))
  81. req, err := s.client.NewRequest("GET", u, nil)
  82. if err != nil {
  83. return nil, nil, err
  84. }
  85. var rawJSON json.RawMessage
  86. resp, err := s.client.Do(ctx, req, &rawJSON)
  87. if err != nil {
  88. return nil, resp, err
  89. }
  90. // Prioritize the most common case: a single returned ref.
  91. r := new(Reference)
  92. singleUnmarshalError := json.Unmarshal(rawJSON, r)
  93. if singleUnmarshalError == nil {
  94. return []*Reference{r}, resp, nil
  95. }
  96. // Attempt to unmarshal multiple refs.
  97. var rs []*Reference
  98. multipleUnmarshalError := json.Unmarshal(rawJSON, &rs)
  99. if multipleUnmarshalError == nil {
  100. if len(rs) == 0 {
  101. return nil, resp, fmt.Errorf("unexpected response from GitHub API: an array of refs with length 0")
  102. }
  103. return rs, resp, nil
  104. }
  105. return nil, resp, fmt.Errorf("unmarshalling failed for both single and multiple refs: %s and %s", singleUnmarshalError, multipleUnmarshalError)
  106. }
  107. // ReferenceListOptions specifies optional parameters to the
  108. // GitService.ListRefs method.
  109. type ReferenceListOptions struct {
  110. Type string `url:"-"`
  111. ListOptions
  112. }
  113. // ListRefs lists all refs in a repository.
  114. //
  115. // GitHub API docs: https://developer.github.com/v3/git/refs/#get-all-references
  116. func (s *GitService) ListRefs(ctx context.Context, owner, repo string, opt *ReferenceListOptions) ([]*Reference, *Response, error) {
  117. var u string
  118. if opt != nil && opt.Type != "" {
  119. u = fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, opt.Type)
  120. } else {
  121. u = fmt.Sprintf("repos/%v/%v/git/refs", owner, repo)
  122. }
  123. u, err := addOptions(u, opt)
  124. if err != nil {
  125. return nil, nil, err
  126. }
  127. req, err := s.client.NewRequest("GET", u, nil)
  128. if err != nil {
  129. return nil, nil, err
  130. }
  131. var rs []*Reference
  132. resp, err := s.client.Do(ctx, req, &rs)
  133. if err != nil {
  134. return nil, resp, err
  135. }
  136. return rs, resp, nil
  137. }
  138. // CreateRef creates a new ref in a repository.
  139. //
  140. // GitHub API docs: https://developer.github.com/v3/git/refs/#create-a-reference
  141. func (s *GitService) CreateRef(ctx context.Context, owner string, repo string, ref *Reference) (*Reference, *Response, error) {
  142. u := fmt.Sprintf("repos/%v/%v/git/refs", owner, repo)
  143. req, err := s.client.NewRequest("POST", u, &createRefRequest{
  144. // back-compat with previous behavior that didn't require 'refs/' prefix
  145. Ref: String("refs/" + strings.TrimPrefix(*ref.Ref, "refs/")),
  146. SHA: ref.Object.SHA,
  147. })
  148. if err != nil {
  149. return nil, nil, err
  150. }
  151. r := new(Reference)
  152. resp, err := s.client.Do(ctx, req, r)
  153. if err != nil {
  154. return nil, resp, err
  155. }
  156. return r, resp, nil
  157. }
  158. // UpdateRef updates an existing ref in a repository.
  159. //
  160. // GitHub API docs: https://developer.github.com/v3/git/refs/#update-a-reference
  161. func (s *GitService) UpdateRef(ctx context.Context, owner string, repo string, ref *Reference, force bool) (*Reference, *Response, error) {
  162. refPath := strings.TrimPrefix(*ref.Ref, "refs/")
  163. u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, refPath)
  164. req, err := s.client.NewRequest("PATCH", u, &updateRefRequest{
  165. SHA: ref.Object.SHA,
  166. Force: &force,
  167. })
  168. if err != nil {
  169. return nil, nil, err
  170. }
  171. r := new(Reference)
  172. resp, err := s.client.Do(ctx, req, r)
  173. if err != nil {
  174. return nil, resp, err
  175. }
  176. return r, resp, nil
  177. }
  178. // DeleteRef deletes a ref from a repository.
  179. //
  180. // GitHub API docs: https://developer.github.com/v3/git/refs/#delete-a-reference
  181. func (s *GitService) DeleteRef(ctx context.Context, owner string, repo string, ref string) (*Response, error) {
  182. ref = strings.TrimPrefix(ref, "refs/")
  183. u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, url.QueryEscape(ref))
  184. req, err := s.client.NewRequest("DELETE", u, nil)
  185. if err != nil {
  186. return nil, err
  187. }
  188. return s.client.Do(ctx, req, nil)
  189. }
上海开阖软件有限公司 沪ICP备12045867号-1