1
2
3
4
5
6 package github
7
8 import (
9 "context"
10 "fmt"
11 "strconv"
12
13 qs "github.com/google/go-querystring/query"
14 )
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 type SearchService service
34
35
36 type SearchOptions struct {
37
38
39
40
41
42
43
44
45 Sort string `url:"sort,omitempty"`
46
47
48
49 Order string `url:"order,omitempty"`
50
51
52 TextMatch bool `url:"-"`
53
54 ListOptions
55 }
56
57
58 type searchParameters struct {
59 Query string
60 RepositoryID *int64
61 }
62
63
64 type RepositoriesSearchResult struct {
65 Total *int `json:"total_count,omitempty"`
66 IncompleteResults *bool `json:"incomplete_results,omitempty"`
67 Repositories []*Repository `json:"items,omitempty"`
68 }
69
70
71
72
73 func (s *SearchService) Repositories(ctx context.Context, query string, opts *SearchOptions) (*RepositoriesSearchResult, *Response, error) {
74 result := new(RepositoriesSearchResult)
75 resp, err := s.search(ctx, "repositories", &searchParameters{Query: query}, opts, result)
76 if err != nil {
77 return nil, resp, err
78 }
79
80 return result, resp, nil
81 }
82
83
84 type TopicsSearchResult struct {
85 Total *int `json:"total_count,omitempty"`
86 IncompleteResults *bool `json:"incomplete_results,omitempty"`
87 Topics []*TopicResult `json:"items,omitempty"`
88 }
89
90 type TopicResult struct {
91 Name *string `json:"name,omitempty"`
92 DisplayName *string `json:"display_name,omitempty"`
93 ShortDescription *string `json:"short_description,omitempty"`
94 Description *string `json:"description,omitempty"`
95 CreatedBy *string `json:"created_by,omitempty"`
96 CreatedAt *Timestamp `json:"created_at,omitempty"`
97 UpdatedAt *string `json:"updated_at,omitempty"`
98 Featured *bool `json:"featured,omitempty"`
99 Curated *bool `json:"curated,omitempty"`
100 Score *float64 `json:"score,omitempty"`
101 }
102
103
104
105
106
107
108 func (s *SearchService) Topics(ctx context.Context, query string, opts *SearchOptions) (*TopicsSearchResult, *Response, error) {
109 result := new(TopicsSearchResult)
110 resp, err := s.search(ctx, "topics", &searchParameters{Query: query}, opts, result)
111 if err != nil {
112 return nil, resp, err
113 }
114
115 return result, resp, nil
116 }
117
118
119 type CommitsSearchResult struct {
120 Total *int `json:"total_count,omitempty"`
121 IncompleteResults *bool `json:"incomplete_results,omitempty"`
122 Commits []*CommitResult `json:"items,omitempty"`
123 }
124
125
126 type CommitResult struct {
127 SHA *string `json:"sha,omitempty"`
128 Commit *Commit `json:"commit,omitempty"`
129 Author *User `json:"author,omitempty"`
130 Committer *User `json:"committer,omitempty"`
131 Parents []*Commit `json:"parents,omitempty"`
132 HTMLURL *string `json:"html_url,omitempty"`
133 URL *string `json:"url,omitempty"`
134 CommentsURL *string `json:"comments_url,omitempty"`
135
136 Repository *Repository `json:"repository,omitempty"`
137 Score *float64 `json:"score,omitempty"`
138 }
139
140
141
142
143 func (s *SearchService) Commits(ctx context.Context, query string, opts *SearchOptions) (*CommitsSearchResult, *Response, error) {
144 result := new(CommitsSearchResult)
145 resp, err := s.search(ctx, "commits", &searchParameters{Query: query}, opts, result)
146 if err != nil {
147 return nil, resp, err
148 }
149
150 return result, resp, nil
151 }
152
153
154 type IssuesSearchResult struct {
155 Total *int `json:"total_count,omitempty"`
156 IncompleteResults *bool `json:"incomplete_results,omitempty"`
157 Issues []*Issue `json:"items,omitempty"`
158 }
159
160
161
162
163 func (s *SearchService) Issues(ctx context.Context, query string, opts *SearchOptions) (*IssuesSearchResult, *Response, error) {
164 result := new(IssuesSearchResult)
165 resp, err := s.search(ctx, "issues", &searchParameters{Query: query}, opts, result)
166 if err != nil {
167 return nil, resp, err
168 }
169
170 return result, resp, nil
171 }
172
173
174 type UsersSearchResult struct {
175 Total *int `json:"total_count,omitempty"`
176 IncompleteResults *bool `json:"incomplete_results,omitempty"`
177 Users []*User `json:"items,omitempty"`
178 }
179
180
181
182
183 func (s *SearchService) Users(ctx context.Context, query string, opts *SearchOptions) (*UsersSearchResult, *Response, error) {
184 result := new(UsersSearchResult)
185 resp, err := s.search(ctx, "users", &searchParameters{Query: query}, opts, result)
186 if err != nil {
187 return nil, resp, err
188 }
189
190 return result, resp, nil
191 }
192
193
194 type Match struct {
195 Text *string `json:"text,omitempty"`
196 Indices []int `json:"indices,omitempty"`
197 }
198
199
200 type TextMatch struct {
201 ObjectURL *string `json:"object_url,omitempty"`
202 ObjectType *string `json:"object_type,omitempty"`
203 Property *string `json:"property,omitempty"`
204 Fragment *string `json:"fragment,omitempty"`
205 Matches []*Match `json:"matches,omitempty"`
206 }
207
208 func (tm TextMatch) String() string {
209 return Stringify(tm)
210 }
211
212
213 type CodeSearchResult struct {
214 Total *int `json:"total_count,omitempty"`
215 IncompleteResults *bool `json:"incomplete_results,omitempty"`
216 CodeResults []*CodeResult `json:"items,omitempty"`
217 }
218
219
220 type CodeResult struct {
221 Name *string `json:"name,omitempty"`
222 Path *string `json:"path,omitempty"`
223 SHA *string `json:"sha,omitempty"`
224 HTMLURL *string `json:"html_url,omitempty"`
225 Repository *Repository `json:"repository,omitempty"`
226 TextMatches []*TextMatch `json:"text_matches,omitempty"`
227 }
228
229 func (c CodeResult) String() string {
230 return Stringify(c)
231 }
232
233
234
235
236 func (s *SearchService) Code(ctx context.Context, query string, opts *SearchOptions) (*CodeSearchResult, *Response, error) {
237 result := new(CodeSearchResult)
238 resp, err := s.search(ctx, "code", &searchParameters{Query: query}, opts, result)
239 if err != nil {
240 return nil, resp, err
241 }
242
243 return result, resp, nil
244 }
245
246
247 type LabelsSearchResult struct {
248 Total *int `json:"total_count,omitempty"`
249 IncompleteResults *bool `json:"incomplete_results,omitempty"`
250 Labels []*LabelResult `json:"items,omitempty"`
251 }
252
253
254 type LabelResult struct {
255 ID *int64 `json:"id,omitempty"`
256 URL *string `json:"url,omitempty"`
257 Name *string `json:"name,omitempty"`
258 Color *string `json:"color,omitempty"`
259 Default *bool `json:"default,omitempty"`
260 Description *string `json:"description,omitempty"`
261 Score *float64 `json:"score,omitempty"`
262 }
263
264 func (l LabelResult) String() string {
265 return Stringify(l)
266 }
267
268
269
270
271 func (s *SearchService) Labels(ctx context.Context, repoID int64, query string, opts *SearchOptions) (*LabelsSearchResult, *Response, error) {
272 result := new(LabelsSearchResult)
273 resp, err := s.search(ctx, "labels", &searchParameters{RepositoryID: &repoID, Query: query}, opts, result)
274 if err != nil {
275 return nil, resp, err
276 }
277
278 return result, resp, nil
279 }
280
281
282
283
284
285
286 func (s *SearchService) search(ctx context.Context, searchType string, parameters *searchParameters, opts *SearchOptions, result interface{}) (*Response, error) {
287 params, err := qs.Values(opts)
288 if err != nil {
289 return nil, err
290 }
291
292 if parameters.RepositoryID != nil {
293 params.Set("repository_id", strconv.FormatInt(*parameters.RepositoryID, 10))
294 }
295 params.Set("q", parameters.Query)
296 u := fmt.Sprintf("search/%s?%s", searchType, params.Encode())
297
298 req, err := s.client.NewRequest("GET", u, nil)
299 if err != nil {
300 return nil, err
301 }
302
303 switch {
304 case searchType == "commits":
305
306
307 req.Header.Set("Accept", mediaTypeCommitSearchPreview)
308 case searchType == "topics":
309
310
311 req.Header.Set("Accept", mediaTypeTopicsPreview)
312 case searchType == "repositories":
313
314
315 req.Header.Set("Accept", mediaTypeTopicsPreview)
316 case searchType == "issues":
317
318
319 req.Header.Set("Accept", mediaTypeReactionsPreview)
320 case opts != nil && opts.TextMatch:
321
322
323 req.Header.Set("Accept", "application/vnd.github.v3.text-match+json")
324 }
325
326 return s.client.Do(ctx, req, result)
327 }
328
View as plain text