Repository navigation
Expand file tree
/
Copy pathclient.go
More file actions
165 lines (144 loc) · 5.59 KB
/
Copy pathclient.go
File metadata and controls
165 lines (144 loc) · 5.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// Package client is the REST API client for issue artifacts. Commands reach
// the API through the ArtifactClient interface, so their tests can use the
// generated mock instead of HTTP stubs.
package client
import (
"bytes"
"encoding/json"
"net/http"
"strconv"
"github.com/cli/cli/v2/api"
"github.com/cli/cli/v2/internal/ghrepo"
"github.com/cli/cli/v2/internal/safeurl"
issueShared "github.com/cli/cli/v2/pkg/cmd/issue/shared"
)
//go:generate moq -rm -out client_mock.go . ArtifactClient
// ArtifactClient is how the artifact commands reach the API. Every request
// goes to the host of the repository it is given.
type ArtifactClient interface {
// IsPullRequest reports whether number in repo is a pull request rather
// than an issue, with one lookup.
IsPullRequest(repo ghrepo.Interface, number int) (bool, error)
// UploadTarget is IsPullRequest for a command that uploads files with
// --attach. Its one lookup also returns what an upload needs to know
// about repo.
UploadTarget(repo ghrepo.Interface, number int) (*UploadTarget, error)
// List returns the artifacts on an issue in the order the API returns
// them, which is number order. An empty artifactType lists every type,
// and a limit of 0 lists every artifact.
List(repo ghrepo.Interface, issueNumber int, artifactType string, limit int) ([]Artifact, error)
// Get returns one artifact on an issue, with its edit history.
Get(repo ghrepo.Interface, issueNumber int, number int) (*ArtifactWithVersions, error)
// Delete deletes one artifact from an issue. The API can't restore a
// deleted artifact.
Delete(repo ghrepo.Interface, issueNumber int, number int) error
// Create creates one artifact on an issue and returns it. The API doesn't
// return a new artifact's description.
Create(repo ghrepo.Interface, issueNumber int, artifactType, name, body string) (*Artifact, error)
}
// maxPageSize is the most artifacts one request asks for.
const maxPageSize = 100
type artifactClient struct {
httpClient *http.Client
apiClient *api.Client
}
// NewArtifactClient returns an ArtifactClient that sends its requests through
// httpClient.
func NewArtifactClient(httpClient *http.Client) ArtifactClient {
return &artifactClient{
httpClient: httpClient,
apiClient: api.NewClientFromHTTP(httpClient),
}
}
func (c *artifactClient) IsPullRequest(repo ghrepo.Interface, number int) (bool, error) {
issue, err := issueShared.FindIssueOrPR(c.httpClient, repo, number, []string{"number"})
if err != nil {
return false, err
}
return issue.IsPullRequest(), nil
}
func (c *artifactClient) UploadTarget(repo ghrepo.Interface, number int) (*UploadTarget, error) {
issue, err := issueShared.FindIssueOrPR(c.httpClient, repo, number, []string{"number", "repository"})
if err != nil {
return nil, err
}
return &UploadTarget{
IsPullRequest: issue.IsPullRequest(),
RepositoryID: issue.RepositoryDatabaseID(),
ViewerPermission: issue.RepositoryViewerPermission(),
}, nil
}
// List requests pages until one comes back short or the limit is reached.
// Every request asks for the same page size, so the page numbers line up.
func (c *artifactClient) List(repo ghrepo.Interface, issueNumber int, artifactType string, limit int) ([]Artifact, error) {
u, err := safeurl.JoinPath("repos", repo.RepoOwner(), repo.RepoName(), "issues", strconv.Itoa(issueNumber), "artifacts")
if err != nil {
return nil, err
}
perPage := maxPageSize
if limit > 0 && limit < maxPageSize {
perPage = limit
}
u.SetQuery("per_page", strconv.Itoa(perPage))
if artifactType != "" {
u.SetQuery("type", artifactType)
}
artifacts := []Artifact{}
for page := 1; ; page++ {
if page > 1 {
u.SetQuery("page", strconv.Itoa(page))
}
var pageArtifacts []Artifact
if err := c.apiClient.REST(repo.RepoHost(), "GET", u.String(), nil, &pageArtifacts); err != nil {
return nil, err
}
artifacts = append(artifacts, pageArtifacts...)
if len(pageArtifacts) < perPage || (limit > 0 && len(artifacts) >= limit) {
break
}
}
if limit > 0 && len(artifacts) > limit {
artifacts = artifacts[:limit]
}
return artifacts, nil
}
func (c *artifactClient) Get(repo ghrepo.Interface, issueNumber int, number int) (*ArtifactWithVersions, error) {
u, err := safeurl.JoinPath("repos", repo.RepoOwner(), repo.RepoName(), "issues", strconv.Itoa(issueNumber), "artifacts", strconv.Itoa(number))
if err != nil {
return nil, err
}
var response struct {
Artifact Artifact `json:"artifact"`
Versions []Version `json:"versions"`
}
if err := c.apiClient.REST(repo.RepoHost(), "GET", u.String(), nil, &response); err != nil {
return nil, err
}
return &ArtifactWithVersions{Artifact: response.Artifact, Versions: response.Versions}, nil
}
func (c *artifactClient) Delete(repo ghrepo.Interface, issueNumber int, number int) error {
u, err := safeurl.JoinPath("repos", repo.RepoOwner(), repo.RepoName(), "issues", strconv.Itoa(issueNumber), "artifacts", strconv.Itoa(number))
if err != nil {
return err
}
return c.apiClient.REST(repo.RepoHost(), "DELETE", u.String(), nil, nil)
}
func (c *artifactClient) Create(repo ghrepo.Interface, issueNumber int, artifactType, name, body string) (*Artifact, error) {
u, err := safeurl.JoinPath("repos", repo.RepoOwner(), repo.RepoName(), "issues", strconv.Itoa(issueNumber), "artifacts")
if err != nil {
return nil, err
}
payload, err := json.Marshal(map[string]string{
"type": artifactType,
"name": name,
"body": body,
})
if err != nil {
return nil, err
}
var artifact Artifact
if err := c.apiClient.REST(repo.RepoHost(), "POST", u.String(), bytes.NewReader(payload), &artifact); err != nil {
return nil, err
}
return &artifact, nil
}