This commit is contained in:
Alex Suraci
2016-01-30 11:45:07 -08:00
parent 13faed5472
commit edcd5c99e4
116 changed files with 3353 additions and 1454 deletions

View File

@@ -30,7 +30,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Protocol buffer deep copy and merge.
// TODO: MessageSet and RawMessage.
// TODO: RawMessage.
package proto

View File

@@ -105,6 +105,11 @@ func (p *Buffer) EncodeVarint(x uint64) error {
return nil
}
// SizeVarint returns the varint encoding size of an integer.
func SizeVarint(x uint64) int {
return sizeVarint(x)
}
func sizeVarint(x uint64) (n int) {
for {
n++
@@ -1248,24 +1253,9 @@ func size_struct(prop *StructProperties, base structPointer) (n int) {
}
// Factor in any oneof fields.
// TODO: This could be faster and use less reflection.
if prop.oneofMarshaler != nil {
sv := reflect.ValueOf(structPointer_Interface(base, prop.stype)).Elem()
for i := 0; i < prop.stype.NumField(); i++ {
fv := sv.Field(i)
if fv.Kind() != reflect.Interface || fv.IsNil() {
continue
}
if prop.stype.Field(i).Tag.Get("protobuf_oneof") == "" {
continue
}
spv := fv.Elem() // interface -> *T
sv := spv.Elem() // *T -> T
sf := sv.Type().Field(0) // StructField inside T
var prop Properties
prop.Init(sf.Type, "whatever", sf.Tag.Get("protobuf"), &sf)
n += prop.size(&prop, toStructPointer(spv))
}
if prop.oneofSizer != nil {
m := structPointer_Interface(base, prop.stype).(Message)
n += prop.oneofSizer(m)
}
return

View File

@@ -30,7 +30,6 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Protocol buffer comparison.
// TODO: MessageSet.
package proto
@@ -51,7 +50,9 @@ Equality is defined in this way:
are equal, and extensions sets are equal.
- Two set scalar fields are equal iff their values are equal.
If the fields are of a floating-point type, remember that
NaN != x for all x, including NaN.
NaN != x for all x, including NaN. If the message is defined
in a proto3 .proto file, fields are not "set"; specifically,
zero length proto3 "bytes" fields are equal (nil == {}).
- Two repeated fields are equal iff their lengths are the same,
and their corresponding elements are equal (a "bytes" field,
although represented by []byte, is not a repeated field)
@@ -89,6 +90,7 @@ func Equal(a, b Message) bool {
// v1 and v2 are known to have the same type.
func equalStruct(v1, v2 reflect.Value) bool {
sprop := GetProperties(v1.Type())
for i := 0; i < v1.NumField(); i++ {
f := v1.Type().Field(i)
if strings.HasPrefix(f.Name, "XXX_") {
@@ -114,7 +116,7 @@ func equalStruct(v1, v2 reflect.Value) bool {
}
f1, f2 = f1.Elem(), f2.Elem()
}
if !equalAny(f1, f2) {
if !equalAny(f1, f2, sprop.Prop[i]) {
return false
}
}
@@ -141,7 +143,8 @@ func equalStruct(v1, v2 reflect.Value) bool {
}
// v1 and v2 are known to have the same type.
func equalAny(v1, v2 reflect.Value) bool {
// prop may be nil.
func equalAny(v1, v2 reflect.Value, prop *Properties) bool {
if v1.Type() == protoMessageType {
m1, _ := v1.Interface().(Message)
m2, _ := v2.Interface().(Message)
@@ -164,7 +167,7 @@ func equalAny(v1, v2 reflect.Value) bool {
if e1.Type() != e2.Type() {
return false
}
return equalAny(e1, e2)
return equalAny(e1, e2, nil)
case reflect.Map:
if v1.Len() != v2.Len() {
return false
@@ -175,16 +178,22 @@ func equalAny(v1, v2 reflect.Value) bool {
// This key was not found in the second map.
return false
}
if !equalAny(v1.MapIndex(key), val2) {
if !equalAny(v1.MapIndex(key), val2, nil) {
return false
}
}
return true
case reflect.Ptr:
return equalAny(v1.Elem(), v2.Elem())
return equalAny(v1.Elem(), v2.Elem(), prop)
case reflect.Slice:
if v1.Type().Elem().Kind() == reflect.Uint8 {
// short circuit: []byte
// Edge case: if this is in a proto3 message, a zero length
// bytes field is considered the zero value.
if prop != nil && prop.proto3 && v1.Len() == 0 && v2.Len() == 0 {
return true
}
if v1.IsNil() != v2.IsNil() {
return false
}
@@ -195,7 +204,7 @@ func equalAny(v1, v2 reflect.Value) bool {
return false
}
for i := 0; i < v1.Len(); i++ {
if !equalAny(v1.Index(i), v2.Index(i)) {
if !equalAny(v1.Index(i), v2.Index(i), prop) {
return false
}
}
@@ -230,7 +239,7 @@ func equalExtensions(base reflect.Type, em1, em2 map[int32]Extension) bool {
if m1 != nil && m2 != nil {
// Both are unencoded.
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2)) {
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) {
return false
}
continue
@@ -258,7 +267,7 @@ func equalExtensions(base reflect.Type, em1, em2 map[int32]Extension) bool {
log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err)
return false
}
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2)) {
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) {
return false
}
}

View File

@@ -301,7 +301,6 @@ func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) {
o := NewBuffer(b)
t := reflect.TypeOf(extension.ExtensionType)
rep := extension.repeated()
props := extensionProperties(extension)
@@ -323,7 +322,7 @@ func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) {
return nil, err
}
if !rep || o.index >= len(o.buf) {
if o.index >= len(o.buf) {
break
}
}

View File

@@ -70,6 +70,12 @@ for a protocol buffer variable v:
with distinguished wrapper types for each possible field value.
- Marshal and Unmarshal are functions to encode and decode the wire format.
When the .proto file specifies `syntax="proto3"`, there are some differences:
- Non-repeated fields of non-message type are values instead of pointers.
- Getters are only generated for message and oneof fields.
- Enum types do not get an Enum method.
The simplest way to describe this is to see an example.
Given file test.proto, containing
@@ -229,6 +235,7 @@ To create and play with a Test object:
test := &pb.Test{
Label: proto.String("hello"),
Type: proto.Int32(17),
Reps: []int64{1, 2, 3},
Optionalgroup: &pb.Test_OptionalGroup{
RequiredField: proto.String("good bye"),
},
@@ -881,3 +888,7 @@ func isProto3Zero(v reflect.Value) bool {
}
return false
}
// ProtoPackageIsVersion1 is referenced from generated protocol buffer files
// to assert that that code is compatible with this version of the proto package.
const ProtoPackageIsVersion1 = true

View File

@@ -44,11 +44,11 @@ import (
"sort"
)
// ErrNoMessageTypeId occurs when a protocol buffer does not have a message type ID.
// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID.
// A message type ID is required for storing a protocol buffer in a message set.
var ErrNoMessageTypeId = errors.New("proto does not have a message type ID")
var errNoMessageTypeID = errors.New("proto does not have a message type ID")
// The first two types (_MessageSet_Item and MessageSet)
// The first two types (_MessageSet_Item and messageSet)
// model what the protocol compiler produces for the following protocol message:
// message MessageSet {
// repeated group Item = 1 {
@@ -58,27 +58,20 @@ var ErrNoMessageTypeId = errors.New("proto does not have a message type ID")
// }
// That is the MessageSet wire format. We can't use a proto to generate these
// because that would introduce a circular dependency between it and this package.
//
// When a proto1 proto has a field that looks like:
// optional message<MessageSet> info = 3;
// the protocol compiler produces a field in the generated struct that looks like:
// Info *_proto_.MessageSet `protobuf:"bytes,3,opt,name=info"`
// The package is automatically inserted so there is no need for that proto file to
// import this package.
type _MessageSet_Item struct {
TypeId *int32 `protobuf:"varint,2,req,name=type_id"`
Message []byte `protobuf:"bytes,3,req,name=message"`
}
type MessageSet struct {
type messageSet struct {
Item []*_MessageSet_Item `protobuf:"group,1,rep"`
XXX_unrecognized []byte
// TODO: caching?
}
// Make sure MessageSet is a Message.
var _ Message = (*MessageSet)(nil)
// Make sure messageSet is a Message.
var _ Message = (*messageSet)(nil)
// messageTypeIder is an interface satisfied by a protocol buffer type
// that may be stored in a MessageSet.
@@ -86,7 +79,7 @@ type messageTypeIder interface {
MessageTypeId() int32
}
func (ms *MessageSet) find(pb Message) *_MessageSet_Item {
func (ms *messageSet) find(pb Message) *_MessageSet_Item {
mti, ok := pb.(messageTypeIder)
if !ok {
return nil
@@ -100,24 +93,24 @@ func (ms *MessageSet) find(pb Message) *_MessageSet_Item {
return nil
}
func (ms *MessageSet) Has(pb Message) bool {
func (ms *messageSet) Has(pb Message) bool {
if ms.find(pb) != nil {
return true
}
return false
}
func (ms *MessageSet) Unmarshal(pb Message) error {
func (ms *messageSet) Unmarshal(pb Message) error {
if item := ms.find(pb); item != nil {
return Unmarshal(item.Message, pb)
}
if _, ok := pb.(messageTypeIder); !ok {
return ErrNoMessageTypeId
return errNoMessageTypeID
}
return nil // TODO: return error instead?
}
func (ms *MessageSet) Marshal(pb Message) error {
func (ms *messageSet) Marshal(pb Message) error {
msg, err := Marshal(pb)
if err != nil {
return err
@@ -130,7 +123,7 @@ func (ms *MessageSet) Marshal(pb Message) error {
mti, ok := pb.(messageTypeIder)
if !ok {
return ErrNoMessageTypeId
return errNoMessageTypeID
}
mtid := mti.MessageTypeId()
@@ -141,9 +134,9 @@ func (ms *MessageSet) Marshal(pb Message) error {
return nil
}
func (ms *MessageSet) Reset() { *ms = MessageSet{} }
func (ms *MessageSet) String() string { return CompactTextString(ms) }
func (*MessageSet) ProtoMessage() {}
func (ms *messageSet) Reset() { *ms = messageSet{} }
func (ms *messageSet) String() string { return CompactTextString(ms) }
func (*messageSet) ProtoMessage() {}
// Support for the message_set_wire_format message option.
@@ -169,7 +162,7 @@ func MarshalMessageSet(m map[int32]Extension) ([]byte, error) {
}
sort.Ints(ids)
ms := &MessageSet{Item: make([]*_MessageSet_Item, 0, len(m))}
ms := &messageSet{Item: make([]*_MessageSet_Item, 0, len(m))}
for _, id := range ids {
e := m[int32(id)]
// Remove the wire type and field number varint, as well as the length varint.
@@ -186,7 +179,7 @@ func MarshalMessageSet(m map[int32]Extension) ([]byte, error) {
// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
// It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
func UnmarshalMessageSet(buf []byte, m map[int32]Extension) error {
ms := new(MessageSet)
ms := new(messageSet)
if err := Unmarshal(buf, ms); err != nil {
return err
}

View File

@@ -91,6 +91,9 @@ type oneofMarshaler func(Message, *Buffer) error
// A oneofUnmarshaler does the unmarshaling for a oneof field in a message.
type oneofUnmarshaler func(Message, int, int, *Buffer) (bool, error)
// A oneofSizer does the sizing for all oneof fields in a message.
type oneofSizer func(Message) int
// tagMap is an optimization over map[int]int for typical protocol buffer
// use-cases. Encoded protocol buffers are often in tag order with small tag
// numbers.
@@ -142,6 +145,7 @@ type StructProperties struct {
oneofMarshaler oneofMarshaler
oneofUnmarshaler oneofUnmarshaler
oneofSizer oneofSizer
stype reflect.Type
// OneofTypes contains information about the oneof fields in this message.
@@ -712,11 +716,11 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
sort.Sort(prop)
type oneofMessage interface {
XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), []interface{})
XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{})
}
if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok {
var oots []interface{}
prop.oneofMarshaler, prop.oneofUnmarshaler, oots = om.XXX_OneofFuncs()
prop.oneofMarshaler, prop.oneofUnmarshaler, prop.oneofSizer, oots = om.XXX_OneofFuncs()
prop.stype = t
// Interpret oneof metadata.

View File

@@ -170,20 +170,12 @@ func writeName(w *textWriter, props *Properties) error {
return nil
}
var (
messageSetType = reflect.TypeOf((*MessageSet)(nil)).Elem()
)
// raw is the interface satisfied by RawMessage.
type raw interface {
Bytes() []byte
}
func writeStruct(w *textWriter, sv reflect.Value) error {
if sv.Type() == messageSetType {
return writeMessageSet(w, sv.Addr().Interface().(*MessageSet))
}
st := sv.Type()
sprops := GetProperties(st)
for i := 0; i < sv.NumField(); i++ {
@@ -525,44 +517,6 @@ func writeString(w *textWriter, s string) error {
return w.WriteByte('"')
}
func writeMessageSet(w *textWriter, ms *MessageSet) error {
for _, item := range ms.Item {
id := *item.TypeId
if msd, ok := messageSetMap[id]; ok {
// Known message set type.
if _, err := fmt.Fprintf(w, "[%s]: <\n", msd.name); err != nil {
return err
}
w.indent()
pb := reflect.New(msd.t.Elem())
if err := Unmarshal(item.Message, pb.Interface().(Message)); err != nil {
if _, err := fmt.Fprintf(w, "/* bad message: %v */\n", err); err != nil {
return err
}
} else {
if err := writeStruct(w, pb.Elem()); err != nil {
return err
}
}
} else {
// Unknown type.
if _, err := fmt.Fprintf(w, "[%d]: <\n", id); err != nil {
return err
}
w.indent()
if err := writeUnknownStruct(w, item.Message); err != nil {
return err
}
}
w.unindent()
if _, err := w.Write(gtNewline); err != nil {
return err
}
}
return nil
}
func writeUnknownStruct(w *textWriter, data []byte) (err error) {
if !w.compact {
if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil {

View File

@@ -249,11 +249,11 @@ func (s *ActivityService) ListEventsPerformedByUser(user string, publicOnly bool
return *events, resp, err
}
// ListEventsRecievedByUser lists the events recieved by a user. If publicOnly is
// ListEventsReceivedByUser lists the events received by a user. If publicOnly is
// true, only public events will be returned.
//
// GitHub API docs: http://developer.github.com/v3/activity/events/#list-events-that-a-user-has-received
func (s *ActivityService) ListEventsRecievedByUser(user string, publicOnly bool, opt *ListOptions) ([]Event, *Response, error) {
func (s *ActivityService) ListEventsReceivedByUser(user string, publicOnly bool, opt *ListOptions) ([]Event, *Response, error) {
var u string
if publicOnly {
u = fmt.Sprintf("users/%v/received_events/public", user)

View File

@@ -41,6 +41,7 @@ type NotificationListOptions struct {
All bool `url:"all,omitempty"`
Participating bool `url:"participating,omitempty"`
Since time.Time `url:"since,omitempty"`
Before time.Time `url:"before,omitempty"`
}
// ListNotifications lists all notifications for the authenticated user.

View File

@@ -50,13 +50,18 @@ func (s *ActivityService) ListWatchers(owner, repo string, opt *ListOptions) ([]
// the empty string will fetch watched repos for the authenticated user.
//
// GitHub API Docs: https://developer.github.com/v3/activity/watching/#list-repositories-being-watched
func (s *ActivityService) ListWatched(user string) ([]Repository, *Response, error) {
func (s *ActivityService) ListWatched(user string, opt *ListOptions) ([]Repository, *Response, error) {
var u string
if user != "" {
u = fmt.Sprintf("users/%v/subscriptions", user)
} else {
u = "user/subscriptions"
}
u, err := addOptions(u, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err

View File

@@ -74,7 +74,7 @@ The GitHub API has good support for conditional requests which will help
prevent you from burning through your rate limit, as well as help speed up your
application. go-github does not handle conditional requests directly, but is
instead designed to work with a caching http.Transport. We recommend using
https://github.com/gregjones/httpcache, which can be used in conjuction with
https://github.com/gregjones/httpcache, which can be used in conjunction with
https://github.com/sourcegraph/apiproxy to provide additional flexibility and
control of caching rules.

View File

@@ -33,7 +33,7 @@ func (s *GitService) GetBlob(owner string, repo string, sha string) (*Blob, *Res
// CreateBlob creates a blob object.
//
// GitHub API docs: http://developer.github.com/v3/git/blobs/#create-a-blob
// GitHub API docs: https://developer.github.com/v3/git/blobs/#create-a-blob
func (s *GitService) CreateBlob(owner string, repo string, blob *Blob) (*Blob, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/git/blobs", owner, repo)
req, err := s.client.NewRequest("POST", u, blob)

View File

@@ -17,6 +17,7 @@ import (
"reflect"
"strconv"
"strings"
"sync"
"time"
"github.com/google/go-querystring/query"
@@ -31,6 +32,7 @@ const (
headerRateLimit = "X-RateLimit-Limit"
headerRateRemaining = "X-RateLimit-Remaining"
headerRateReset = "X-RateLimit-Reset"
headerOTP = "X-GitHub-OTP"
mediaTypeV3 = "application/vnd.github.v3+json"
defaultMediaType = "application/octet-stream"
@@ -46,6 +48,9 @@ const (
// https://developer.github.com/changes/2015-06-24-api-enhancements-for-working-with-organization-permissions/
mediaTypeOrgPermissionPreview = "application/vnd.github.ironman-preview+json"
mediaTypeOrgPermissionRepoPreview = "application/vnd.github.ironman-preview.repository+json"
// https://developer.github.com/changes/2015-11-11-protected-branches-api/
mediaTypeProtectedBranchesPreview = "application/vnd.github.loki-preview+json"
)
// A Client manages communication with the GitHub API.
@@ -64,11 +69,8 @@ type Client struct {
// User agent used when communicating with the GitHub API.
UserAgent string
// Rate specifies the current rate limit for the client as determined by the
// most recent API call. If the client is used in a multi-user application,
// this rate may not always be up-to-date. Call RateLimit() to check the
// current rate.
Rate Rate
rateMu sync.Mutex
rate Rate
// Services used for talking to different parts of the GitHub API.
Activity *ActivityService
@@ -292,6 +294,17 @@ func (r *Response) populateRate() {
}
}
// Rate specifies the current rate limit for the client as determined by the
// most recent API call. If the client is used in a multi-user application,
// this rate may not always be up-to-date. Call RateLimits() to check the
// current rate.
func (c *Client) Rate() Rate {
c.rateMu.Lock()
rate := c.rate
c.rateMu.Unlock()
return rate
}
// Do sends an API request and returns the API response. The API response is
// JSON decoded and stored in the value pointed to by v, or returned as an
// error if an API error has occurred. If v implements the io.Writer
@@ -307,7 +320,9 @@ func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
response := newResponse(resp)
c.Rate = response.Rate
c.rateMu.Lock()
c.rate = response.Rate
c.rateMu.Unlock()
err = CheckResponse(resp)
if err != nil {
@@ -321,6 +336,9 @@ func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
io.Copy(w, resp.Body)
} else {
err = json.NewDecoder(resp.Body).Decode(v)
if err == io.EOF {
err = nil // ignore EOF errors caused by empty response body
}
}
}
return response, err
@@ -343,8 +361,15 @@ func (r *ErrorResponse) Error() string {
r.Response.StatusCode, r.Message, r.Errors)
}
// sanitizeURL redacts the client_id and client_secret tokens from the URL which
// may be exposed to the user, specifically in the ErrorResponse error message.
// TwoFactorAuthError occurs when using HTTP Basic Authentication for a user
// that has two-factor authentication enabled. The request can be reattempted
// by providing a one-time password in the request.
type TwoFactorAuthError ErrorResponse
func (r *TwoFactorAuthError) Error() string { return (*ErrorResponse)(r).Error() }
// sanitizeURL redacts the client_secret parameter from the URL which may be
// exposed to the user, specifically in the ErrorResponse error message.
func sanitizeURL(uri *url.URL) *url.URL {
if uri == nil {
return nil
@@ -397,6 +422,9 @@ func CheckResponse(r *http.Response) error {
if err == nil && data != nil {
json.Unmarshal(data, errorResponse)
}
if r.StatusCode == http.StatusUnauthorized && strings.HasPrefix(r.Header.Get(headerOTP), "required") {
return (*TwoFactorAuthError)(errorResponse)
}
return errorResponse
}
@@ -548,6 +576,43 @@ func (t *UnauthenticatedRateLimitedTransport) transport() http.RoundTripper {
return http.DefaultTransport
}
// BasicAuthTransport is an http.RoundTripper that authenticates all requests
// using HTTP Basic Authentication with the provided username and password. It
// additionally supports users who have two-factor authentication enabled on
// their GitHub account.
type BasicAuthTransport struct {
Username string // GitHub username
Password string // GitHub password
OTP string // one-time password for users with two-factor auth enabled
// Transport is the underlying HTTP transport to use when making requests.
// It will default to http.DefaultTransport if nil.
Transport http.RoundTripper
}
// RoundTrip implements the RoundTripper interface.
func (t *BasicAuthTransport) RoundTrip(req *http.Request) (*http.Response, error) {
req = cloneRequest(req) // per RoundTrip contract
req.SetBasicAuth(t.Username, t.Password)
if t.OTP != "" {
req.Header.Add(headerOTP, t.OTP)
}
return t.transport().RoundTrip(req)
}
// Client returns an *http.Client that makes requests that are authenticated
// using HTTP Basic Authentication.
func (t *BasicAuthTransport) Client() *http.Client {
return &http.Client{Transport: t}
}
func (t *BasicAuthTransport) transport() http.RoundTripper {
if t.Transport != nil {
return t.Transport
}
return http.DefaultTransport
}
// cloneRequest returns a clone of the provided *http.Request. The clone is a
// shallow copy of the struct and its Header map.
func cloneRequest(r *http.Request) *http.Request {
@@ -555,9 +620,9 @@ func cloneRequest(r *http.Request) *http.Request {
r2 := new(http.Request)
*r2 = *r
// deep copy of the Header
r2.Header = make(http.Header)
r2.Header = make(http.Header, len(r.Header))
for k, s := range r.Header {
r2.Header[k] = s
r2.Header[k] = append([]string(nil), s...)
}
return r2
}

View File

@@ -65,7 +65,7 @@ type IssueListOptions struct {
Filter string `url:"filter,omitempty"`
// State filters issues based on their state. Possible values are: open,
// closed. Default is "open".
// closed, all. Default is "open".
State string `url:"state,omitempty"`
// Labels filters issues based on their label.
@@ -76,7 +76,7 @@ type IssueListOptions struct {
Sort string `url:"sort,omitempty"`
// Direction in which to sort issues. Possible values are: asc, desc.
// Default is "asc".
// Default is "desc".
Direction string `url:"direction,omitempty"`
// Since filters issues by time.
@@ -148,7 +148,7 @@ type IssueListByRepoOptions struct {
Milestone string `url:"milestone,omitempty"`
// State filters issues based on their state. Possible values are: open,
// closed. Default is "open".
// closed, all. Default is "open".
State string `url:"state,omitempty"`
// Assignee filters issues based on their assignee. Possible values are a
@@ -156,10 +156,10 @@ type IssueListByRepoOptions struct {
// any assigned user.
Assignee string `url:"assignee,omitempty"`
// Assignee filters issues based on their creator.
// Creator filters issues based on their creator.
Creator string `url:"creator,omitempty"`
// Assignee filters issues to those mentioned a specific user.
// Mentioned filters issues to those mentioned a specific user.
Mentioned string `url:"mentioned,omitempty"`
// Labels filters issues based on their label.
@@ -170,7 +170,7 @@ type IssueListByRepoOptions struct {
Sort string `url:"sort,omitempty"`
// Direction in which to sort issues. Possible values are: asc, desc.
// Default is "asc".
// Default is "desc".
Direction string `url:"direction,omitempty"`
// Since filters issues by time.

View File

@@ -22,40 +22,52 @@ type IssueEvent struct {
// values are:
//
// closed
// The issue was closed by the actor. When the commit_id is
// present, it identifies the commit that closed the issue using
// “closes / fixes #NN” syntax.
//
// reopened
// The issue was reopened by the actor.
//
// subscribed
// The actor subscribed to receive notifications for an issue.
// The Actor closed the issue.
// If the issue was closed by commit message, CommitID holds the SHA1 hash of the commit.
//
// merged
// The issue was merged by the actor. The commit_id attribute is the SHA1 of the HEAD commit that was merged.
// The Actor merged into master a branch containing a commit mentioning the issue.
// CommitID holds the SHA1 of the merge commit.
//
// referenced
// The issue was referenced from a commit message. The commit_id attribute is the commit SHA1 of where that happened.
// The Actor committed to master a commit mentioning the issue in its commit message.
// CommitID holds the SHA1 of the commit.
//
// reopened, locked, unlocked
// The Actor did that to the issue.
//
// renamed
// The Actor changed the issue title from Rename.From to Rename.To.
//
// mentioned
// The actor was @mentioned in an issue body.
// Someone unspecified @mentioned the Actor [sic] in an issue comment body.
//
// assigned
// The issue was assigned to the actor.
// assigned, unassigned
// The Actor assigned the issue to or removed the assignment from the Assignee.
//
// head_ref_deleted
// The pull requests branch was deleted.
// labeled, unlabeled
// The Actor added or removed the Label from the issue.
//
// milestoned, demilestoned
// The Actor added or removed the issue from the Milestone.
//
// subscribed, unsubscribed
// The Actor subscribed to or unsubscribed from notifications for an issue.
//
// head_ref_deleted, head_ref_restored
// The pull requests branch was deleted or restored.
//
// head_ref_restored
// The pull requests branch was restored.
Event *string `json:"event,omitempty"`
// The SHA of the commit that referenced this commit, if applicable.
CommitID *string `json:"commit_id,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
Issue *Issue `json:"issue,omitempty"`
// Only present on certain events; see above.
Assignee *User `json:"assignee,omitempty"`
CommitID *string `json:"commit_id,omitempty"`
Milestone *Milestone `json:"milestone,omitempty"`
Label *Label `json:"label,omitempty"`
Rename *Rename `json:"rename,omitempty"`
}
// ListIssueEvents lists events for the specified issue.
@@ -125,3 +137,13 @@ func (s *IssuesService) GetEvent(owner, repo string, id int) (*IssueEvent, *Resp
return event, resp, err
}
// Rename contains details for 'renamed' events.
type Rename struct {
From *string `json:"from,omitempty"`
To *string `json:"to,omitempty"`
}
func (r Rename) String() string {
return Stringify(r)
}

View File

@@ -49,7 +49,7 @@ type MilestoneListOptions struct {
//
// GitHub API docs: https://developer.github.com/v3/issues/milestones/#list-milestones-for-a-repository
func (s *IssuesService) ListMilestones(owner string, repo string, opt *MilestoneListOptions) ([]Milestone, *Response, error) {
u := fmt.Sprintf("/repos/%v/%v/milestones", owner, repo)
u := fmt.Sprintf("repos/%v/%v/milestones", owner, repo)
u, err := addOptions(u, opt)
if err != nil {
return nil, nil, err
@@ -73,7 +73,7 @@ func (s *IssuesService) ListMilestones(owner string, repo string, opt *Milestone
//
// GitHub API docs: https://developer.github.com/v3/issues/milestones/#get-a-single-milestone
func (s *IssuesService) GetMilestone(owner string, repo string, number int) (*Milestone, *Response, error) {
u := fmt.Sprintf("/repos/%v/%v/milestones/%d", owner, repo, number)
u := fmt.Sprintf("repos/%v/%v/milestones/%d", owner, repo, number)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
@@ -92,7 +92,7 @@ func (s *IssuesService) GetMilestone(owner string, repo string, number int) (*Mi
//
// GitHub API docs: https://developer.github.com/v3/issues/milestones/#create-a-milestone
func (s *IssuesService) CreateMilestone(owner string, repo string, milestone *Milestone) (*Milestone, *Response, error) {
u := fmt.Sprintf("/repos/%v/%v/milestones", owner, repo)
u := fmt.Sprintf("repos/%v/%v/milestones", owner, repo)
req, err := s.client.NewRequest("POST", u, milestone)
if err != nil {
return nil, nil, err

View File

@@ -52,7 +52,7 @@ type ListMembersOptions struct {
// 2fa_disabled, all. Default is "all".
Filter string `url:"filter,omitempty"`
// Role filters memebers returned by their role in the organization.
// Role filters members returned by their role in the organization.
// Possible values are:
// all - all members of the organization, regardless of role
// admin - organization owners
@@ -172,7 +172,7 @@ func (s *OrganizationsService) ConcealMembership(org, user string) (*Response, e
// ListOrgMembershipsOptions specifies optional parameters to the
// OrganizationsService.ListOrgMemberships method.
type ListOrgMembershipsOptions struct {
// Filter memberships to include only those withe the specified state.
// Filter memberships to include only those with the specified state.
// Possible values are: "active", "pending".
State string `url:"state,omitempty"`
@@ -238,14 +238,16 @@ func (s *OrganizationsService) GetOrgMembership(user, org string) (*Membership,
// GitHub API docs: https://developer.github.com/v3/orgs/members/#add-or-update-organization-membership
// GitHub API docs: https://developer.github.com/v3/orgs/members/#edit-your-organization-membership
func (s *OrganizationsService) EditOrgMembership(user, org string, membership *Membership) (*Membership, *Response, error) {
var u string
var u, method string
if user != "" {
u = fmt.Sprintf("orgs/%v/memberships/%v", org, user)
method = "PUT"
} else {
u = fmt.Sprintf("user/memberships/orgs/%v", org)
method = "PATCH"
}
req, err := s.client.NewRequest("PATCH", u, membership)
req, err := s.client.NewRequest(method, u, membership)
if err != nil {
return nil, nil, err
}

View File

@@ -12,14 +12,17 @@ import (
// PullRequestComment represents a comment left on a pull request.
type PullRequestComment struct {
ID *int `json:"id,omitempty"`
Body *string `json:"body,omitempty"`
Path *string `json:"path,omitempty"`
Position *int `json:"position,omitempty"`
CommitID *string `json:"commit_id,omitempty"`
User *User `json:"user,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
ID *int `json:"id,omitempty"`
Body *string `json:"body,omitempty"`
Path *string `json:"path,omitempty"`
DiffHunk *string `json:"diff_hunk,omitempty"`
Position *int `json:"position,omitempty"`
OriginalPosition *int `json:"original_position,omitempty"`
CommitID *string `json:"commit_id,omitempty"`
OriginalCommitID *string `json:"original_commit_id,omitempty"`
User *User `json:"user,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
}
func (p PullRequestComment) String() string {

View File

@@ -146,6 +146,9 @@ func (s *RepositoriesService) List(user string, opt *RepositoryListOptions) ([]R
return nil, nil, err
}
// TODO: remove custom Accept header when license support fully launches
req.Header.Set("Accept", mediaTypeLicensesPreview)
repos := new([]Repository)
resp, err := s.client.Do(req, repos)
if err != nil {
@@ -180,6 +183,9 @@ func (s *RepositoriesService) ListByOrg(org string, opt *RepositoryListByOrgOpti
return nil, nil, err
}
// TODO: remove custom Accept header when license support fully launches
req.Header.Set("Accept", mediaTypeLicensesPreview)
repos := new([]Repository)
resp, err := s.client.Do(req, repos)
if err != nil {
@@ -442,8 +448,27 @@ func (s *RepositoriesService) ListTags(owner string, repo string, opt *ListOptio
// Branch represents a repository branch
type Branch struct {
Name *string `json:"name,omitempty"`
Commit *Commit `json:"commit,omitempty"`
Name *string `json:"name,omitempty"`
Commit *Commit `json:"commit,omitempty"`
Protection *Protection `json:"protection,omitempty"`
}
// Protection represents a repository branch's protection
type Protection struct {
Enabled *bool `json:"enabled,omitempty"`
RequiredStatusChecks *RequiredStatusChecks `json:"required_status_checks,omitempty"`
}
// RequiredStatusChecks represents the protection status of a individual branch
type RequiredStatusChecks struct {
// Who required status checks apply to.
// Possible values are:
// off
// non_admins
// everyone
EnforcementLevel *string `json:"enforcement_level,omitempty"`
// The list of status checks which are required
Contexts *[]string `json:"contexts,omitempty"`
}
// ListBranches lists branches for the specified repository.
@@ -480,6 +505,29 @@ func (s *RepositoriesService) GetBranch(owner, repo, branch string) (*Branch, *R
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)
b := new(Branch)
resp, err := s.client.Do(req, b)
if err != nil {
return nil, resp, err
}
return b, resp, err
}
// EditBranch edits the branch (currently only Branch Protection)
//
// GitHub API docs: https://developer.github.com/v3/repos/#enabling-and-disabling-branch-protection
func (s *RepositoriesService) EditBranch(owner, repo, branchName string, branch *Branch) (*Branch, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/branches/%v", owner, repo, branchName)
req, err := s.client.NewRequest("PATCH", u, branch)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)
b := new(Branch)
resp, err := s.client.Do(req, b)
if err != nil {

View File

@@ -70,6 +70,7 @@ type Hook struct {
CreatedAt *time.Time `json:"created_at,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
Name *string `json:"name,omitempty"`
URL *string `json:"url,omitempty"`
Events []string `json:"events,omitempty"`
Active *bool `json:"active,omitempty"`
Config map[string]interface{} `json:"config,omitempty"`

View File

@@ -10,7 +10,6 @@ import (
"fmt"
"io"
"mime"
"net/http"
"os"
"path/filepath"
)
@@ -213,9 +212,9 @@ func (s *RepositoriesService) GetReleaseAsset(owner, repo string, id int) (*Rele
return asset, resp, err
}
// DowloadReleaseAsset downloads a release asset.
// DownloadReleaseAsset downloads a release asset.
//
// DowloadReleaseAsset returns an io.ReadCloser that reads the contents of the
// DownloadReleaseAsset returns an io.ReadCloser that reads the contents of the
// specified release asset. It is the caller's responsibility to close the ReadCloser.
//
// GitHub API docs : http://developer.github.com/v3/repos/releases/#get-a-single-release-asset
@@ -228,32 +227,7 @@ func (s *RepositoriesService) DownloadReleaseAsset(owner, repo string, id int) (
}
req.Header.Set("Accept", defaultMediaType)
var resp *http.Response
if s.client.client.Transport == nil {
resp, err = http.DefaultTransport.RoundTrip(req)
} else {
resp, err = s.client.client.Transport.RoundTrip(req)
}
if err != nil {
return nil, err
}
// GitHub API streamed the asset directly
if resp.StatusCode == http.StatusOK {
return resp.Body, nil
}
if resp.StatusCode != http.StatusFound {
return nil, fmt.Errorf("Expected status code 200 or 302, got %d", resp.StatusCode)
}
// GitHub API redirected to pre-signed S3 URL
downloadURL, err := resp.Location()
if err != nil {
return nil, err
}
resp, err = http.Get(downloadURL.String())
resp, err := s.client.client.Do(req)
if err != nil {
return nil, err
}

View File

@@ -113,7 +113,7 @@ func (s *UsersService) Edit(user *User) (*User, *Response, error) {
return uResp, resp, err
}
// UserListOptions specifies optional parameters to the UsersService.List
// UserListOptions specifies optional parameters to the UsersService.ListAll
// method.
type UserListOptions struct {
// ID of the last user seen

View File

@@ -79,7 +79,7 @@ func Flags(flagSet *flag.FlagSet, prefix string, includeParallelFlags bool) {
}
flagSet.BoolVar(&(DefaultReporterConfig.NoColor), prefix+"noColor", false, "If set, suppress color output in default reporter.")
flagSet.Float64Var(&(DefaultReporterConfig.SlowSpecThreshold), prefix+"slowSpecThreshold", 5.0, "(in seconds) Specs that take longer to run than this threshold are flagged as slow by the default reporter (default: 5 seconds).")
flagSet.Float64Var(&(DefaultReporterConfig.SlowSpecThreshold), prefix+"slowSpecThreshold", 5.0, "(in seconds) Specs that take longer to run than this threshold are flagged as slow by the default reporter.")
flagSet.BoolVar(&(DefaultReporterConfig.NoisyPendings), prefix+"noisyPendings", true, "If set, default reporter will shout about pending tests.")
flagSet.BoolVar(&(DefaultReporterConfig.Verbose), prefix+"v", false, "If set, default reporter print out all specs as they begin.")
flagSet.BoolVar(&(DefaultReporterConfig.Succinct), prefix+"succinct", false, "If set, default reporter prints out a very succinct report")

View File

@@ -63,6 +63,8 @@ func findSuiteFile() (string, os.FileMode) {
if err != nil {
complainAndQuit("Could not find suite file for nodot: " + err.Error())
}
defer f.Close()
if re.MatchReader(bufio.NewReader(f)) {
return path, file.Mode()
}

View File

@@ -4,6 +4,7 @@ import (
"errors"
"io/ioutil"
"os"
"path"
"path/filepath"
"regexp"
"strings"
@@ -47,6 +48,15 @@ func PrecompiledTestSuite(path string) (TestSuite, error) {
func SuitesInDir(dir string, recurse bool) []TestSuite {
suites := []TestSuite{}
// "This change will only be enabled if the go command is run with
// GO15VENDOREXPERIMENT=1 in its environment."
// c.f. the vendor-experiment proposal https://goo.gl/2ucMeC
vendorExperiment := os.Getenv("GO15VENDOREXPERIMENT")
if (vendorExperiment == "1") && path.Base(dir) == "vendor" {
return suites
}
files, _ := ioutil.ReadDir(dir)
re := regexp.MustCompile(`_test\.go$`)
for _, file := range files {

View File

@@ -24,6 +24,8 @@ func unfocusSpecs([]string, []string) {
unfocus("Context")
unfocus("It")
unfocus("Measure")
unfocus("DescribeTable")
unfocus("Entry")
}
func unfocus(component string) {

View File

@@ -68,7 +68,7 @@ func (r *runner) runAsync() (outcome types.SpecState, failure types.SpecFailure)
done := make(chan interface{}, 1)
go func() {
finished := false
finished := false
defer func() {
if e := recover(); e != nil || !finished {
@@ -83,7 +83,7 @@ func (r *runner) runAsync() (outcome types.SpecState, failure types.SpecFailure)
}()
r.asyncFunc(done)
finished = true
finished = true
}()
select {
@@ -96,7 +96,7 @@ func (r *runner) runAsync() (outcome types.SpecState, failure types.SpecFailure)
return
}
func (r *runner) runSync() (outcome types.SpecState, failure types.SpecFailure) {
finished := false
finished := false
defer func() {
if e := recover(); e != nil || !finished {
@@ -107,7 +107,7 @@ func (r *runner) runSync() (outcome types.SpecState, failure types.SpecFailure)
}()
r.syncFunc()
finished = true
finished = true
return
}

View File

@@ -8,6 +8,7 @@ package stenographer
import (
"fmt"
"runtime"
"strings"
"github.com/onsi/ginkgo/types"
@@ -59,14 +60,20 @@ type Stenographer interface {
}
func New(color bool) Stenographer {
denoter := "•"
if runtime.GOOS == "windows" {
denoter = "+"
}
return &consoleStenographer{
color: color,
denoter: denoter,
cursorState: cursorStateTop,
}
}
type consoleStenographer struct {
color bool
denoter string
cursorState cursorStateType
}
@@ -216,13 +223,13 @@ func (s *consoleStenographer) AnnounceCapturedOutput(output string) {
}
func (s *consoleStenographer) AnnounceSuccesfulSpec(spec *types.SpecSummary) {
s.print(0, s.colorize(greenColor, "•"))
s.print(0, s.colorize(greenColor, s.denoter))
s.stream()
}
func (s *consoleStenographer) AnnounceSuccesfulSlowSpec(spec *types.SpecSummary, succinct bool) {
s.printBlockWithMessage(
s.colorize(greenColor, " [SLOW TEST:%.3f seconds]", spec.RunTime.Seconds()),
s.colorize(greenColor, "%s [SLOW TEST:%.3f seconds]", s.denoter, spec.RunTime.Seconds()),
"",
spec,
succinct,
@@ -231,7 +238,7 @@ func (s *consoleStenographer) AnnounceSuccesfulSlowSpec(spec *types.SpecSummary,
func (s *consoleStenographer) AnnounceSuccesfulMeasurement(spec *types.SpecSummary, succinct bool) {
s.printBlockWithMessage(
s.colorize(greenColor, " [MEASUREMENT]"),
s.colorize(greenColor, "%s [MEASUREMENT]", s.denoter),
s.measurementReport(spec, succinct),
spec,
succinct,
@@ -270,15 +277,15 @@ func (s *consoleStenographer) AnnounceSkippedSpec(spec *types.SpecSummary, succi
}
func (s *consoleStenographer) AnnounceSpecTimedOut(spec *types.SpecSummary, succinct bool, fullTrace bool) {
s.printSpecFailure("•... Timeout", spec, succinct, fullTrace)
s.printSpecFailure(fmt.Sprintf("%s... Timeout", s.denoter), spec, succinct, fullTrace)
}
func (s *consoleStenographer) AnnounceSpecPanicked(spec *types.SpecSummary, succinct bool, fullTrace bool) {
s.printSpecFailure("•! Panic", spec, succinct, fullTrace)
s.printSpecFailure(fmt.Sprintf("%s! Panic", s.denoter), spec, succinct, fullTrace)
}
func (s *consoleStenographer) AnnounceSpecFailed(spec *types.SpecSummary, succinct bool, fullTrace bool) {
s.printSpecFailure("• Failure", spec, succinct, fullTrace)
s.printSpecFailure(fmt.Sprintf("%s Failure", s.denoter), spec, succinct, fullTrace)
}
func (s *consoleStenographer) SummarizeFailures(summaries []*types.SpecSummary) {

View File

@@ -1,3 +1,5 @@
.DS_Store
*.test
.
.idea
gomega.iml

View File

@@ -10,15 +10,18 @@ type HaveOccurredMatcher struct {
}
func (matcher *HaveOccurredMatcher) Match(actual interface{}) (success bool, err error) {
if isNil(actual) {
// is purely nil?
if actual == nil {
return false, nil
}
if isError(actual) {
return true, nil
// must be an 'error' type
if !isError(actual) {
return false, fmt.Errorf("Expected an error-type. Got:\n%s", format.Object(actual, 1))
}
return false, fmt.Errorf("Expected an error. Got:\n%s", format.Object(actual, 1))
// must be non-nil (or a pointer to a non-nil)
return !isNil(actual), nil
}
func (matcher *HaveOccurredMatcher) FailureMessage(actual interface{}) (message string) {

View File

@@ -16,7 +16,7 @@ func (matcher *HaveSuffixMatcher) Match(actual interface{}) (success bool, err e
return false, fmt.Errorf("HaveSuffix matcher requires a string or stringer. Got:\n%s", format.Object(actual, 1))
}
suffix := matcher.suffix()
return len(actualString) >= len(suffix) && actualString[len(actualString) - len(suffix):] == suffix, nil
return len(actualString) >= len(suffix) && actualString[len(actualString)-len(suffix):] == suffix, nil
}
func (matcher *HaveSuffixMatcher) suffix() string {

View File

@@ -10,15 +10,18 @@ type SucceedMatcher struct {
}
func (matcher *SucceedMatcher) Match(actual interface{}) (success bool, err error) {
// is purely nil?
if actual == nil {
return true, nil
}
if isError(actual) {
return false, nil
// must be an 'error' type
if !isError(actual) {
return false, fmt.Errorf("Expected an error-type. Got:\n%s", format.Object(actual, 1))
}
return false, fmt.Errorf("Expected an error-type. Got:\n%s", format.Object(actual, 1))
// must be nil (or a pointer to a nil)
return isNil(actual), nil
}
func (matcher *SucceedMatcher) FailureMessage(actual interface{}) (message string) {

View File

@@ -3,5 +3,5 @@ package util
import "math"
func Odd(n int) bool {
return math.Mod(float64(n), 2.0) == 1.0
}
return math.Mod(float64(n), 2.0) == 1.0
}