blob: 4850ba4b1411235dc93c4361e88e463062e18084 [file] [log] [blame]
package gerrit
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/url"
"time"
)
// PatchSet contains detailed information about a specific patch set.
//
// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/json.html#patchSet
type PatchSet struct {
Number Number `json:"number"`
Revision string `json:"revision"`
Parents []string `json:"parents"`
Ref string `json:"ref"`
Uploader AccountInfo `json:"uploader"`
Author AccountInfo `json:"author"`
CreatedOn int `json:"createdOn"`
IsDraft bool `json:"isDraft"`
Kind string `json:"kind"`
}
// RefUpdate contains data about a reference update.
//
// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/json.html#refUpdate
type RefUpdate struct {
OldRev string `json:"oldRev"`
NewRev string `json:"newRev"`
RefName string `json:"refName"`
Project string `json:"project"`
}
// EventInfo contains information about an event emitted by Gerrit. This
// structure can be used either when parsing streamed events or when reading
// the output of the events-log plugin.
//
// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/cmd-stream-events.html#events
type EventInfo struct {
Type string `json:"type"`
Change ChangeInfo `json:"change,omitempty"`
ChangeKey ChangeInfo `json:"changeKey,omitempty"`
PatchSet PatchSet `json:"patchSet,omitempty"`
EventCreatedOn int `json:"eventCreatedOn,omitempty"`
Reason string `json:"reason,omitempty"`
Abandoner AccountInfo `json:"abandoner,omitempty"`
Restorer AccountInfo `json:"restorer,omitempty"`
Submitter AccountInfo `json:"submitter,omitempty"`
Author AccountInfo `json:"author,omitempty"`
Uploader AccountInfo `json:"uploader,omitempty"`
Approvals []AccountInfo `json:"approvals,omitempty"`
Comment string `json:"comment,omitempty"`
Editor AccountInfo `json:"editor,omitempty"`
Added []string `json:"added,omitempty"`
Removed []string `json:"removed,omitempty"`
Hashtags []string `json:"hashtags,omitempty"`
RefUpdate RefUpdate `json:"refUpdate,omitempty"`
Project ProjectInfo `json:"project,omitempty"`
Reviewer AccountInfo `json:"reviewer,omitempty"`
OldTopic string `json:"oldTopic,omitempty"`
Changer AccountInfo `json:"changer,omitempty"`
}
// EventsLogService contains functions for querying the API provided
// by the optional events-log plugin.
type EventsLogService struct {
client *Client
}
// EventsLogOptions contains options for querying events from the events-logs
// plugin.
type EventsLogOptions struct {
From time.Time
To time.Time
// IgnoreUnmarshalErrors will cause GetEvents to ignore any errors
// that come up when calling json.Unmarshal. This can be useful in
// cases where the events-log plugin was not kept up to date with
// the Gerrit version for some reason. In these cases the events-log
// plugin will return data structs that don't match the EventInfo
// struct which in turn causes issues for json.Unmarshal.
IgnoreUnmarshalErrors bool
}
// getURL returns the url that should be used in the request. This will vary
// depending on the options provided to GetEvents.
func (events *EventsLogService) getURL(options *EventsLogOptions) (string, error) {
parsed, err := url.Parse("/plugins/events-log/events/")
if err != nil {
return "", err
}
query := parsed.Query()
if !options.From.IsZero() {
query.Set("t1", options.From.Format("2006-01-02 15:04:05"))
}
if !options.To.IsZero() {
query.Set("t2", options.To.Format("2006-01-02 15:04:05"))
}
encoded := query.Encode()
if len(encoded) > 0 {
parsed.RawQuery = encoded
}
return parsed.String(), nil
}
// GetEvents returns a list of events for the given input options. Use of this
// function requires an authenticated user and for the events-log plugin to be
// installed. This function returns the unmarshalled EventInfo structs, response,
// failed lines and errors. Marshaling errors will cause this function to return
// before processing is complete unless you set EventsLogOptions.IgnoreUnmarshalErrors
// to true. This can be useful in cases where the events-log plugin got out of sync
// with the Gerrit version which in turn produced events which can't be transformed
// unmarshalled into EventInfo.
//
// Gerrit API docs: https://<yourserver>/plugins/events-log/Documentation/rest-api-events.html
func (events *EventsLogService) GetEvents(options *EventsLogOptions) ([]EventInfo, *Response, [][]byte, error) {
info := []EventInfo{}
failures := [][]byte{}
requestURL, err := events.getURL(options)
if err != nil {
return info, nil, failures, err
}
request, err := events.client.NewRequest("GET", requestURL, nil)
if err != nil {
return info, nil, failures, err
}
// Perform the request but do not pass in a structure to unpack
// the response into. The format of the response is one EventInfo
// object per line so we need to manually handle the response here.
response, err := events.client.Do(request, nil)
if err != nil {
return info, response, failures, err
}
body, err := ioutil.ReadAll(response.Body)
defer response.Body.Close() // nolint: errcheck
if err != nil {
return info, response, failures, err
}
for _, line := range bytes.Split(body, []byte("\n")) {
if len(line) > 0 {
event := EventInfo{}
if err := json.Unmarshal(line, &event); err != nil { // nolint: vetshadow
failures = append(failures, line)
if !options.IgnoreUnmarshalErrors {
return info, response, failures, err
}
continue
}
info = append(info, event)
}
}
return info, response, failures, err
}