Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ first. For more complete details see
instead of a hard coded value when comparing response codes.
* Updated AccountInfo.AccountID to be omitted of empty (such as when
used in ApprovalInfo).
* + and : in url parameters for queries are no longer escaped. This was
causing `400 Bad Request` to be returned when the + symbol was
included as part of the query. To match behavior with Gerrit's search
handling, the : symbol was also excluded.
* Fixed documentation for NewClient and moved fmt.Errorf call from
inside the function to a `ErrNoInstanceGiven` variable so it's
easier to compare against.
Expand Down
27 changes: 27 additions & 0 deletions changes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,30 @@ func ExampleChangesService_QueryChanges() {
// Output:
// Project: platform/art -> ART: Change return types of field access entrypoints -> https://android-review.googlesource.com/249244
}

// Prior to fixing #18 this test would fail.
func ExampleChangesService_QueryChangesWithSymbols() {
instance := "https://android-review.googlesource.com/"
client, err := gerrit.NewClient(instance, nil)
if err != nil {
panic(err)
}

opt := &gerrit.QueryChangeOptions{}
opt.Query = []string{
"change:249244+status:merged",
}
opt.Limit = 2
opt.AdditionalFields = []string{"LABELS"}
changes, _, err := client.Changes.QueryChanges(opt)
if err != nil {
panic(err)
}

for _, change := range *changes {
fmt.Printf("Project: %s -> %s -> %s%d\n", change.Project, change.Subject, instance, change.Number)
}

// Output:
// Project: platform/art -> ART: Change return types of field access entrypoints -> https://android-review.googlesource.com/249244
}
40 changes: 39 additions & 1 deletion gerrit.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,14 @@ func CheckResponse(r *http.Response) error {
return err
}

// queryParameterReplacements are values in a url, specifically the query
// portion of the url, which should not be escaped before being sent to
// Gerrit. Note, Gerrit itself does not escape these values when using the
// search box so we shouldn't escape them either.
var queryParameterReplacements = map[string]string{
"+": "GOGERRIT_URL_PLACEHOLDER_PLUS",
":": "GOGERRIT_URL_PLACEHOLDER_COLON"}

// addOptions adds the parameters in opt as URL query parameters to s.
// opt must be a struct whose fields may contain "url" tags.
func addOptions(s string, opt interface{}) (string, error) {
Expand All @@ -367,7 +375,37 @@ func addOptions(s string, opt interface{}) (string, error) {
return s, err
}

u.RawQuery = qs.Encode()
// If the url contained one or more query parameters (q) then we need
// to do some escaping on these values before Encode() is called. By
// doing so we're ensuring that : and + don't get encoded which means
// they'll be passed along to Gerrit as raw ascii. Without this Gerrit
// could return 400 Bad Request depending on the query parameters. For
// more complete information see this issue on GitHub:
// https://github.com/andygrunwald/go-gerrit/issues/18
_, hasQuery := qs["q"]
if hasQuery {
values := []string{}
for _, value := range qs["q"] {
for key, replacement := range queryParameterReplacements {
value = strings.Replace(value, key, replacement, -1)
}
values = append(values, value)
}

qs.Del("q")
for _, value := range values {
qs.Add("q", value)
}
}
encoded := qs.Encode()

if hasQuery {
for key, replacement := range queryParameterReplacements {
encoded = strings.Replace(encoded, replacement, key, -1)
}
}

u.RawQuery = encoded
return u.String(), nil
}

Expand Down