Repository: google/go-github (go)

Issue:
Question about query with date that includes "+"
Hello!

I tried to use `Search.Repositories` function.
I see it almost works well, but I tried to use query string `created:` that includes "+" doesn't work well.
Could you please give me some advice to use query in such situation.

Here's snippet I tried:

```go
// c is *github.Client
result, resp, err := c.Search.Repositories(
            context.Background(),                                                                                                       | 18             context.Background(),
            "user:pankona created:2019-01-18T17:35:34+09:00..2019-02-18T17:35:34+09:00 fork:true",                                      | 19             "user:pankona created:2019-01-18T17:35:34+09:00..2019-02-18T17:35:34+09:00 fork:true",
            &github.SearchOptions{                                                                                                      | 20             &github.SearchOptions{
                ListOptions: github.ListOptions{                                                                                        | 21                 ListOptions: github.ListOptions{
                    PerPage: 100,                                                                                                       | 22                     PerPage: 100,
                    Page:    page,                                                                                                      | 23                     Page:    page,
                }})  
```

According to result of `httpuitl.DumpRequestOut`, the escaped query seems as follows:
`GET /search/repositories?q=user:pankona+created:2019-01-18T17:35:34+09:00..2019-02-18T17:35:34+09:00+fork:true&page=1&per_page=100 HTTP/1.1`

I expects 1 results by this search but it returns 0.

(I think "+" included in query's date part is not escaped correctly. I guess it should be `%2B`. Is my assuming correct?)

Pull request:
Use url.QueryEscape instead of url.PathEscape to escape query string
Fixes #1122.

- Quit replacing white space with "+"
- Use url.QueryEscape instead of url.PathEscape to escape query string


Patch:
diff --git a/github/repos_hooks.go b/github/repos_hooks.go
index 56374b3e..7674947d 100644
--- a/github/repos_hooks.go
+++ b/github/repos_hooks.go
@@ -92,6 +92,7 @@ func (h Hook) String() string {
 // information.
 type createHookRequest struct {
 	// Config is required.
+	Name   string                 `json:"name"`
 	Config map[string]interface{} `json:"config,omitempty"`
 	Events []string               `json:"events,omitempty"`
 	Active *bool                  `json:"active,omitempty"`
@@ -108,6 +109,7 @@ func (s *RepositoriesService) CreateHook(ctx context.Context, owner, repo string
 	u := fmt.Sprintf("repos/%v/%v/hooks", owner, repo)
 
 	hookReq := &createHookRequest{
+		Name:   "web",
 		Events: hook.Events,
 		Active: hook.Active,
 		Config: hook.Config,
diff --git a/github/search.go b/github/search.go
index abaf5e1f..24156f31 100644
--- a/github/search.go
+++ b/github/search.go
@@ -8,9 +8,7 @@ package github
 import (
 	"context"
 	"fmt"
-	"net/url"
 	"strconv"
-	"strings"
 
 	qs "github.com/google/go-querystring/query"
 )
@@ -218,20 +216,19 @@ func (s *SearchService) Labels(ctx context.Context, repoID int64, query string,
 
 // Helper function that executes search queries against different
 // GitHub search types (repositories, commits, code, issues, users, labels)
+//
+// If searchParameters.Query includes multiple condition, it MUST NOT include "+" as condition separator.
+// For example, querying with "language:c++" and "leveldb", then searchParameters.Query should be "language:c++ leveldb" but not "language:c+++leveldb".
 func (s *SearchService) search(ctx context.Context, searchType string, parameters *searchParameters, opt *SearchOptions, result interface{}) (*Response, error) {
 	params, err := qs.Values(opt)
 	if err != nil {
 		return nil, err
 	}
-	q := strings.Replace(parameters.Query, " ", "+", -1)
 	if parameters.RepositoryID != nil {
 		params.Set("repository_id", strconv.FormatInt(*parameters.RepositoryID, 10))
 	}
-	query := "q=" + url.PathEscape(q)
-	if v := params.Encode(); v != "" {
-		query = query + "&" + v
-	}
-	u := fmt.Sprintf("search/%s?%s", searchType, query)
+	params.Set("q", parameters.Query)
+	u := fmt.Sprintf("search/%s?%s", searchType, params.Encode())
 
 	req, err := s.client.NewRequest("GET", u, nil)
 	if err != nil {


Test patch:
diff --git a/github/repos_commits_test.go b/github/repos_commits_test.go
index 2cbcc5ae..e076febb 100644
--- a/github/repos_commits_test.go
+++ b/github/repos_commits_test.go
@@ -223,6 +223,45 @@ func TestRepositoriesService_GetCommitSHA1(t *testing.T) {
 	}
 }
 
+func TestRepositoriesService_NonAlphabetCharacter_GetCommitSHA1(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+	const sha1 = "01234abcde"
+
+	mux.HandleFunc("/repos/o/r/commits/master%20hash", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testHeader(t, r, "Accept", mediaTypeV3SHA)
+
+		fmt.Fprintf(w, sha1)
+	})
+
+	got, _, err := client.Repositories.GetCommitSHA1(context.Background(), "o", "r", "master%20hash", "")
+	if err != nil {
+		t.Errorf("Repositories.GetCommitSHA1 returned error: %v", err)
+	}
+
+	if want := sha1; got != want {
+		t.Errorf("Repositories.GetCommitSHA1 = %v, want %v", got, want)
+	}
+
+	mux.HandleFunc("/repos/o/r/commits/tag", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testHeader(t, r, "Accept", mediaTypeV3SHA)
+		testHeader(t, r, "If-None-Match", `"`+sha1+`"`)
+
+		w.WriteHeader(http.StatusNotModified)
+	})
+
+	got, _, err = client.Repositories.GetCommitSHA1(context.Background(), "o", "r", "tag", sha1)
+	if err == nil {
+		t.Errorf("Expected HTTP 304 response")
+	}
+
+	if want := ""; got != want {
+		t.Errorf("Repositories.GetCommitSHA1 = %v, want %v", got, want)
+	}
+}
+
 func TestRepositoriesService_CompareCommits(t *testing.T) {
 	client, mux, _, teardown := setup()
 	defer teardown()
diff --git a/github/repos_hooks_test.go b/github/repos_hooks_test.go
index 1223b442..9e4691c3 100644
--- a/github/repos_hooks_test.go
+++ b/github/repos_hooks_test.go
@@ -25,7 +25,7 @@ func TestRepositoriesService_CreateHook(t *testing.T) {
 		json.NewDecoder(r.Body).Decode(v)
 
 		testMethod(t, r, "POST")
-		want := &createHookRequest{}
+		want := &createHookRequest{Name: "web"}
 		if !reflect.DeepEqual(v, want) {
 			t.Errorf("Request body = %+v, want %+v", v, want)
 		}
diff --git a/github/search_test.go b/github/search_test.go
index f6e40d21..4b686884 100644
--- a/github/search_test.go
+++ b/github/search_test.go
@@ -115,7 +115,7 @@ func TestSearchService_Issues_withQualifiersNoOpts(t *testing.T) {
 	client, mux, _, teardown := setup()
 	defer teardown()
 
-	const q = "gopher is:issue label:bug language:go pushed:>=2018-01-01 stars:>=200"
+	const q = "gopher is:issue label:bug language:c++ pushed:>=2018-01-01 stars:>=200"
 
 	var requestURI string
 	mux.HandleFunc("/search/issues", func(w http.ResponseWriter, r *http.Request) {
@@ -134,7 +134,7 @@ func TestSearchService_Issues_withQualifiersNoOpts(t *testing.T) {
 		t.Errorf("Search.Issues returned error: %v", err)
 	}
 
-	if want := "/api-v3/search/issues?q=gopher+is:issue+label:bug+language:go+pushed:%3E=2018-01-01+stars:%3E=200"; requestURI != want {
+	if want := "/api-v3/search/issues?q=gopher+is%3Aissue+label%3Abug+language%3Ac%2B%2B+pushed%3A%3E%3D2018-01-01+stars%3A%3E%3D200"; requestURI != want {
 		t.Fatalf("URI encoding failed: got %v, want %v", requestURI, want)
 	}
 
@@ -152,7 +152,7 @@ func TestSearchService_Issues_withQualifiersAndOpts(t *testing.T) {
 	client, mux, _, teardown := setup()
 	defer teardown()
 
-	const q = "gopher is:issue label:bug language:go pushed:>=2018-01-01 stars:>=200"
+	const q = "gopher is:issue label:bug language:c++ pushed:>=2018-01-01 stars:>=200"
 
 	var requestURI string
 	mux.HandleFunc("/search/issues", func(w http.ResponseWriter, r *http.Request) {
@@ -172,7 +172,7 @@ func TestSearchService_Issues_withQualifiersAndOpts(t *testing.T) {
 		t.Errorf("Search.Issues returned error: %v", err)
 	}
 
-	if want := "/api-v3/search/issues?q=gopher+is:issue+label:bug+language:go+pushed:%3E=2018-01-01+stars:%3E=200&sort=forks"; requestURI != want {
+	if want := "/api-v3/search/issues?q=gopher+is%3Aissue+label%3Abug+language%3Ac%2B%2B+pushed%3A%3E%3D2018-01-01+stars%3A%3E%3D200&sort=forks"; requestURI != want {
 		t.Fatalf("URI encoding failed: got %v, want %v", requestURI, want)
 	}