Browse Source

initial search service and repository search

Beyang Liu 13 years ago
committed by Will Norris
parent
commit
4e62bb73d5
4 changed files with 285 additions and 0 deletions
  1. +4
    -0
      github/github.go
  2. +6
    -0
      github/github_test.go
  3. +134
    -0
      github/search.go
  4. +141
    -0
      github/search_test.go

+ 4
- 0
github/github.go View File

@ -65,6 +65,8 @@ const (
headerRateLimit = "X-RateLimit-Limit"
headerRateRemaining = "X-RateLimit-Remaining"
headerRateReset = "X-RateLimit-Reset"
mimePreview = "application/vnd.github.preview"
)
// A Client manages communication with the GitHub API.
@ -96,6 +98,7 @@ type Client struct {
Users *UsersService
Gists *GistsService
Activity *ActivityService
Search *SearchService
}
// ListOptions specifies the optional parameters to various List methods that
@ -124,6 +127,7 @@ func NewClient(httpClient *http.Client) *Client {
c.Users = &UsersService{client: c}
c.Gists = &GistsService{client: c}
c.Activity = &ActivityService{client: c}
c.Search = &SearchService{client: c}
return c
}


+ 6
- 0
github/github_test.go View File

@ -63,6 +63,12 @@ func testFormValues(t *testing.T, r *http.Request, values values) {
}
}
func testHeader(t *testing.T, r *http.Request, header string, want string) {
if value := r.Header.Get(header); want != value {
t.Errorf("Header %s = %s, want: %s", header, value, want)
}
}
func testURLParseError(t *testing.T, err error) {
if err == nil {
t.Errorf("Expected error to be returned")


+ 134
- 0
github/search.go View File

@ -0,0 +1,134 @@
// Copyright 2013 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package github
import (
"fmt"
"net/url"
"strconv"
)
// SearchService provides access to the search related functions
// in the GitHub API.
//
// GitHub API docs: http://developer.github.com/v3/search/
type SearchService struct {
client *Client
}
// SearchOptions specifies optional parameters to the SearchService methods.
type SearchOptions struct {
// How to sort the search results. Possible values are:
// - for repositories: stars, fork, updated
// - for code: indexed
// - for issues: comments, created, updated
// - for users: followers, repositories, joined
//
// Default is to sort by best match.
Sort string
// Sort order if sort parameter is provided. Possible values are: asc,
// desc. Default is desc.
Order string
// Page of results to retrieve.
Page int
// Number of results to show per page. This can be up to 100
// according to GitHub.
PerPage int
}
// RepositoriesSearchResult represents the result of a repositories search.
type RepositoriesSearchResult struct {
Total int `json:"total_count,omitempty"`
Repositories []Repository `json:"items,omitempty"`
}
// Repositories searches repositories via various criteria.
//
// GitHub API docs: http://developer.github.com/v3/search/#search-repositories
func (s *SearchService) Repositories(query string, opt *SearchOptions) (*RepositoriesSearchResult, *Response, error) {
result := new(RepositoriesSearchResult)
resp, err := s.search("repositories", query, opt, result)
return result, resp, err
}
// IssuesSearchResult represents the result of an issues search.
type IssuesSearchResult struct {
Total int `json:"total_count,omitempty"`
Issues []Issue `json:"items,omitempty"`
}
// Issues searches issues via various criteria.
//
// GitHub API docs: http://developer.github.com/v3/search/#search-issues
func (s *SearchService) Issues(query string, opt *SearchOptions) (*IssuesSearchResult, *Response, error) {
result := new(IssuesSearchResult)
resp, err := s.search("issues", query, opt, result)
return result, resp, err
}
// UsersSearchResult represents the result of an issues search.
type UsersSearchResult struct {
Total int `json:"total_count,omitempty"`
Users []User `json:"items,omitempty"`
}
// Users searches users via various criteria.
//
// GitHub API docs: http://developer.github.com/v3/search/#search-users
func (s *SearchService) Users(query string, opt *SearchOptions) (*UsersSearchResult, *Response, error) {
result := new(UsersSearchResult)
resp, err := s.search("users", query, opt, result)
return result, resp, err
}
// CodeSearchResult represents the result of an code search.
type CodeSearchResult struct {
Total int `json:"total_count,omitempty"`
CodeResults []CodeResult `json:"items,omitempty"`
}
// CodeResult represents a single search result.
type CodeResult struct {
Name string `json:"name,omitempty"`
Path string `json:"path,omitempty"`
SHA string `json:"sha,omitempty"`
HTMLURL string `json:"html_url,omitempty"`
Repository *Repository `json:"repository,omitempty"`
}
// Code searches code via various criteria.
//
// GitHub API docs: http://developer.github.com/v3/search/#search-code
func (s *SearchService) Code(query string, opt *SearchOptions) (*CodeSearchResult, *Response, error) {
result := new(CodeSearchResult)
resp, err := s.search("code", query, opt, result)
return result, resp, err
}
// Helper function that executes search queries against different
// GitHub search types (repositories, code, issues, users)
func (s *SearchService) search(searchType string, query string, opt *SearchOptions, result interface{}) (*Response, error) {
params := url.Values{"q": []string{query}}
if opt != nil {
params.Add("sort", opt.Sort)
params.Add("order", opt.Order)
params.Add("page", strconv.Itoa(opt.Page))
params.Add("per_page", strconv.Itoa(opt.PerPage))
}
u := fmt.Sprintf("search/%s?%s", searchType, params.Encode())
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, err
}
req.Header.Add("Accept", mimePreview)
resp, err := s.client.Do(req, result)
return resp, err
}

+ 141
- 0
github/search_test.go View File

@ -0,0 +1,141 @@
package github
import (
"fmt"
"net/http"
"reflect"
"testing"
)
func TestSearchService_Repositories(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/search/repositories", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mimePreview)
testFormValues(t, r, values{
"q": "blah",
"sort": "forks",
"order": "desc",
"page": "2",
"per_page": "2",
})
fmt.Fprint(w, `{"total_count": 4, "items": [{"id":1},{"id":2}]}`)
})
opts := &SearchOptions{Sort: "forks", Order: "desc", Page: 2, PerPage: 2}
result, _, err := client.Search.Repositories("blah", opts)
if err != nil {
t.Errorf("Search.Repositories returned error: %v", err)
}
want := &RepositoriesSearchResult{
Total: 4,
Repositories: []Repository{{ID: 1}, {ID: 2}},
}
if !reflect.DeepEqual(result, want) {
t.Errorf("Search.Repositories returned %+v, want %+v", result, want)
}
}
func TestSearchService_Issues(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/search/issues", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mimePreview)
testFormValues(t, r, values{
"q": "blah",
"sort": "forks",
"order": "desc",
"page": "2",
"per_page": "2",
})
fmt.Fprint(w, `{"total_count": 4, "items": [{"number":1},{"number":2}]}`)
})
opts := &SearchOptions{Sort: "forks", Order: "desc", Page: 2, PerPage: 2}
result, _, err := client.Search.Issues("blah", opts)
if err != nil {
t.Errorf("Search.Issues returned error: %v", err)
}
want := &IssuesSearchResult{
Total: 4,
Issues: []Issue{{Number: 1}, {Number: 2}},
}
if !reflect.DeepEqual(result, want) {
t.Errorf("Search.Issues returned %+v, want %+v", result, want)
}
}
func TestSearchService_Users(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/search/users", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mimePreview)
testFormValues(t, r, values{
"q": "blah",
"sort": "forks",
"order": "desc",
"page": "2",
"per_page": "2",
})
fmt.Fprint(w, `{"total_count": 4, "items": [{"id":1},{"id":2}]}`)
})
opts := &SearchOptions{Sort: "forks", Order: "desc", Page: 2, PerPage: 2}
result, _, err := client.Search.Users("blah", opts)
if err != nil {
t.Errorf("Search.Issues returned error: %v", err)
}
want := &UsersSearchResult{
Total: 4,
Users: []User{{ID: 1}, {ID: 2}},
}
if !reflect.DeepEqual(result, want) {
t.Errorf("Search.Users returned %+v, want %+v", result, want)
}
}
func TestSearchService_Code(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/search/code", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mimePreview)
testFormValues(t, r, values{
"q": "blah",
"sort": "forks",
"order": "desc",
"page": "2",
"per_page": "2",
})
fmt.Fprint(w, `{"total_count": 4, "items": [{"name":"1"},{"name":"2"}]}`)
})
opts := &SearchOptions{Sort: "forks", Order: "desc", Page: 2, PerPage: 2}
result, _, err := client.Search.Code("blah", opts)
if err != nil {
t.Errorf("Search.Code returned error: %v", err)
}
want := &CodeSearchResult{
Total: 4,
CodeResults: []CodeResult{{Name: "1"}, {Name: "2"}},
}
if !reflect.DeepEqual(result, want) {
t.Errorf("Search.Code returned %+v, want %+v", result, want)
}
}

Loading…
Cancel
Save