This commit is contained in:
Brad Rydzewski 2015-12-06 23:44:06 -08:00
Родитель bded6baf44
Коммит 831a8e5ee0
202 изменённых файлов: 31660 добавлений и 13 удалений

1
.drone.sec Normal file
Просмотреть файл

@ -0,0 +1 @@
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.lG84en0N7UeCNd8ZJXVmwTvLhb0nIPTJdRhP_aTMcAtDVnXAJgHFOcgYkhc1YWW_dMRrSWA8gCgucFesar5DMvFeXj580Jyc17nUfSeShoZpsVJ-RIDyQ5k1zFCoskJNrazSQtelQKtz0IpQvo-OLmDsqqn8u44jt-XiCcXwgb5Wa-kBLGchuCeUc3bqmRj1oRwYkx616rwHybjHQg08g2gHHXDVFWQEvup1cu9Y6KYaepKKKnpn0HEFAh2TYBGSnUMre5DAbQRGpuK3CCCP2B9a8xUp0mJuIPwF58uzUsXNJHiEBJ6CvR02gR2GPzG83Xwx5_5cMR2A1pICx59lLA.-U379Q7zmakJUI8Y.qUJtiwBo5yuf5wcMmSnYBqyq8b2hUHP5DlWae4TS_jacnpbBfEFKQY2EMyqxyvpooHDwGSi_8l2tls1EoQW355Xat3BnnPCsZ84glo5DnnMbJQhOUxtLyCwqHORnLUmjwreGl_TPJxgUL-W00gP0D8XCtYSB4aOHx77p7X1Q6jdiCL3BMQ7F2iY1mlsDBl5mFA.MAmz3dPyJQEIQkm_V1Jlmw

Просмотреть файл

@ -5,18 +5,25 @@ build:
commands:
# compile lgtm for all architectures
- GOOS=linux GOARCH=amd64 go build -o ./bin/linux_amd64/lgtm github.com/lgtmco/lgtm-cli/lgtm
- GOOS=linux GOARCH=386 go build -o ./bin/linux_386/lgtm github.com/lgtmco/lgtm-cli/lgtm
- GOOS=linux GOARCH=arm go build -o ./bin/linux_arm/lgtm github.com/lgtmco/lgtm-cli/lgtm
- GOOS=darwin GOARCH=amd64 go build -o ./bin/darwin_amd64/lgtm github.com/lgtmco/lgtm-cli/lgtm
- GOOS=windows GOARCH=386 go build -o ./bin/windows_386/lgtm github.com/lgtmco/lgtm-cli/lgtm
- GOOS=windows GOARCH=amd64 go build -o ./bin/windows_amd64/lgtm github.com/lgtmco/lgtm-cli/lgtm
- GOOS=linux GOARCH=amd64 go build -o ./release/linux_amd64/lgtm github.com/lgtmco/lgtm-cli/lgtm
- GOOS=linux GOARCH=386 go build -o ./release/linux_386/lgtm github.com/lgtmco/lgtm-cli/lgtm
- GOOS=linux GOARCH=arm go build -o ./release/linux_arm/lgtm github.com/lgtmco/lgtm-cli/lgtm
- GOOS=darwin GOARCH=amd64 go build -o ./release/darwin_amd64/lgtm github.com/lgtmco/lgtm-cli/lgtm
- GOOS=windows GOARCH=386 go build -o ./release/windows_386/lgtm github.com/lgtmco/lgtm-cli/lgtm
- GOOS=windows GOARCH=amd64 go build -o ./release/windows_amd64/lgtm github.com/lgtmco/lgtm-cli/lgtm
# tar binary files prior to upload
- mkdir dist
- tar -cvzf dist/lgtm_linux_amd64.tar.gz --directory=bin/linux_amd64 lgtm
- tar -cvzf dist/lgtm_linux_386.tar.gz --directory=bin/linux_386 lgtm
- tar -cvzf dist/lgtm_linux_arm.tar.gz --directory=bin/linux_arm lgtm
- tar -cvzf dist/lgtm_darwin_amd64.tar.gz --directory=bin/darwin_amd64 lgtm
- tar -cvzf dist/lgtm_windows_386.tar.gz --directory=bin/windows_386 lgtm
- tar -cvzf dist/lgtm_windows_amd64.tar.gz --directory=bin/windows_amd64 lgtm
- tar -cvzf release/lgtm_linux_amd64.tar.gz --directory=release/linux_amd64 lgtm
- tar -cvzf release/lgtm_linux_386.tar.gz --directory=release/linux_386 lgtm
- tar -cvzf release/lgtm_linux_arm.tar.gz --directory=release/linux_arm lgtm
- tar -cvzf release/lgtm_darwin_amd64.tar.gz --directory=release/darwin_amd64 lgtm
- tar -cvzf release/lgtm_windows_386.tar.gz --directory=release/windows_386 lgtm
- tar -cvzf release/lgtm_windows_amd64.tar.gz --directory=release/windows_amd64 lgtm
publish:
github_release:
api_key: $$GITHUB_TOKEN
files:
- release/*.tar.gz
when:
event: tag

1
.gitignore поставляемый
Просмотреть файл

@ -23,4 +23,5 @@ _testmain.go
*.test
*.prof
release/
lgtm/lgtm

3
vendor/github.com/BurntSushi/toml/COMPATIBLE сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,3 @@
Compatible with TOML version
[v0.2.0](https://github.com/mojombo/toml/blob/master/versions/toml-v0.2.0.md)

14
vendor/github.com/BurntSushi/toml/COPYING сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,14 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

14
vendor/github.com/BurntSushi/toml/Makefile сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,14 @@
install:
go install
fmt:
gofmt -w *.go */*.go
colcheck *.go */*.go
tags:
find ./ -name '*.go' -print0 | xargs -0 gotags > TAGS
push:
git push origin master
git push github master

218
vendor/github.com/BurntSushi/toml/README.md сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,218 @@
# TOML parser and encoder for Go with reflection
TOML stands for Tom's Obvious, Minimal Language. This Go package provides a
reflection interface similar to Go's standard library `json` and `xml`
packages. This package also supports the `encoding.TextUnmarshaler` and
`encoding.TextMarshaler` interfaces so that you can define custom data
representations. (There is an example of this below.)
Spec: https://github.com/mojombo/toml
Compatible with TOML version
[v0.2.0](https://github.com/mojombo/toml/blob/master/versions/toml-v0.2.0.md)
Documentation: http://godoc.org/github.com/BurntSushi/toml
Installation:
```bash
go get github.com/BurntSushi/toml
```
Try the toml validator:
```bash
go get github.com/BurntSushi/toml/tomlv
tomlv some-toml-file.toml
```
## Testing
This package passes all tests in
[toml-test](https://github.com/BurntSushi/toml-test) for both the decoder
and the encoder.
## Examples
This package works similarly to how the Go standard library handles `XML`
and `JSON`. Namely, data is loaded into Go values via reflection.
For the simplest example, consider some TOML file as just a list of keys
and values:
```toml
Age = 25
Cats = [ "Cauchy", "Plato" ]
Pi = 3.14
Perfection = [ 6, 28, 496, 8128 ]
DOB = 1987-07-05T05:45:00Z
```
Which could be defined in Go as:
```go
type Config struct {
Age int
Cats []string
Pi float64
Perfection []int
DOB time.Time // requires `import time`
}
```
And then decoded with:
```go
var conf Config
if _, err := toml.Decode(tomlData, &conf); err != nil {
// handle error
}
```
You can also use struct tags if your struct field name doesn't map to a TOML
key value directly:
```toml
some_key_NAME = "wat"
```
```go
type TOML struct {
ObscureKey string `toml:"some_key_NAME"`
}
```
## Using the `encoding.TextUnmarshaler` interface
Here's an example that automatically parses duration strings into
`time.Duration` values:
```toml
[[song]]
name = "Thunder Road"
duration = "4m49s"
[[song]]
name = "Stairway to Heaven"
duration = "8m03s"
```
Which can be decoded with:
```go
type song struct {
Name string
Duration duration
}
type songs struct {
Song []song
}
var favorites songs
if _, err := Decode(blob, &favorites); err != nil {
log.Fatal(err)
}
for _, s := range favorites.Song {
fmt.Printf("%s (%s)\n", s.Name, s.Duration)
}
```
And you'll also need a `duration` type that satisfies the
`encoding.TextUnmarshaler` interface:
```go
type duration struct {
time.Duration
}
func (d *duration) UnmarshalText(text []byte) error {
var err error
d.Duration, err = time.ParseDuration(string(text))
return err
}
```
## More complex usage
Here's an example of how to load the example from the official spec page:
```toml
# This is a TOML document. Boom.
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
organization = "GitHub"
bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
dob = 1979-05-27T07:32:00Z # First class dates? Why not?
[database]
server = "192.168.1.1"
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true
[servers]
# You can indent as you please. Tabs or spaces. TOML don't care.
[servers.alpha]
ip = "10.0.0.1"
dc = "eqdc10"
[servers.beta]
ip = "10.0.0.2"
dc = "eqdc10"
[clients]
data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it
# Line breaks are OK when inside arrays
hosts = [
"alpha",
"omega"
]
```
And the corresponding Go types are:
```go
type tomlConfig struct {
Title string
Owner ownerInfo
DB database `toml:"database"`
Servers map[string]server
Clients clients
}
type ownerInfo struct {
Name string
Org string `toml:"organization"`
Bio string
DOB time.Time
}
type database struct {
Server string
Ports []int
ConnMax int `toml:"connection_max"`
Enabled bool
}
type server struct {
IP string
DC string
}
type clients struct {
Data [][]interface{}
Hosts []string
}
```
Note that a case insensitive match will be tried if an exact match can't be
found.
A working example of the above can be found in `_examples/example.{go,toml}`.

565
vendor/github.com/BurntSushi/toml/decode.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,565 @@
package toml
import (
"fmt"
"io"
"io/ioutil"
"reflect"
"strings"
"time"
)
var e = fmt.Errorf
// Primitive is a TOML value that hasn't been decoded into a Go value.
// When using the various `Decode*` functions, the type `Primitive` may
// be given to any value, and its decoding will be delayed.
//
// A `Primitive` value can be decoded using the `PrimitiveDecode` function.
//
// The underlying representation of a `Primitive` value is subject to change.
// Do not rely on it.
//
// N.B. Primitive values are still parsed, so using them will only avoid
// the overhead of reflection. They can be useful when you don't know the
// exact type of TOML data until run time.
type Primitive interface{}
// PrimitiveDecode is just like the other `Decode*` functions, except it
// decodes a TOML value that has already been parsed. Valid primitive values
// can *only* be obtained from values filled by the decoder functions,
// including `PrimitiveDecode`. (i.e., `v` may contain more `Primitive`
// values.)
//
// Meta data for primitive values is included in the meta data returned by
// the `Decode*` functions.
func PrimitiveDecode(primValue Primitive, v interface{}) error {
return unify(primValue, rvalue(v))
}
// Decode will decode the contents of `data` in TOML format into a pointer
// `v`.
//
// TOML hashes correspond to Go structs or maps. (Dealer's choice. They can be
// used interchangeably.)
//
// TOML arrays of tables correspond to either a slice of structs or a slice
// of maps.
//
// TOML datetimes correspond to Go `time.Time` values.
//
// All other TOML types (float, string, int, bool and array) correspond
// to the obvious Go types.
//
// An exception to the above rules is if a type implements the
// encoding.TextUnmarshaler interface. In this case, any primitive TOML value
// (floats, strings, integers, booleans and datetimes) will be converted to
// a byte string and given to the value's UnmarshalText method. Here's an
// example for parsing durations:
//
// type duration struct {
// time.Duration
// }
//
// func (d *duration) UnmarshalText(text []byte) error {
// var err error
// d.Duration, err = time.ParseDuration(string(text))
// return err
// }
//
// func ExampleUnmarshaler() {
// blob := `
// [[song]]
// name = "Thunder Road"
// duration = "4m49s"
//
// [[song]]
// name = "Stairway to Heaven"
// duration = "8m03s"
// `
// type song struct {
// Name string
// Duration duration
// }
// type songs struct {
// Song []song
// }
// var favorites songs
// if _, err := Decode(blob, &favorites); err != nil {
// log.Fatal(err)
// }
//
// for _, s := range favorites.Song {
// fmt.Printf("%s (%s)\n", s.Name, s.Duration)
// }
// // Output:
// // Thunder Road (4m49s)
// // Stairway to Heaven (8m3s)
// }
//
// Key mapping
//
// TOML keys can map to either keys in a Go map or field names in a Go
// struct. The special `toml` struct tag may be used to map TOML keys to
// struct fields that don't match the key name exactly. (See the example.)
// A case insensitive match to struct names will be tried if an exact match
// can't be found.
//
// The mapping between TOML values and Go values is loose. That is, there
// may exist TOML values that cannot be placed into your representation, and
// there may be parts of your representation that do not correspond to
// TOML values.
//
// This decoder will not handle cyclic types. If a cyclic type is passed,
// `Decode` will not terminate.
func Decode(data string, v interface{}) (MetaData, error) {
p, err := parse(data)
if err != nil {
return MetaData{}, err
}
return MetaData{p.mapping, p.types, p.ordered}, unify(p.mapping, rvalue(v))
}
// DecodeFile is just like Decode, except it will automatically read the
// contents of the file at `fpath` and decode it for you.
func DecodeFile(fpath string, v interface{}) (MetaData, error) {
bs, err := ioutil.ReadFile(fpath)
if err != nil {
return MetaData{}, err
}
return Decode(string(bs), v)
}
// DecodeReader is just like Decode, except it will consume all bytes
// from the reader and decode it for you.
func DecodeReader(r io.Reader, v interface{}) (MetaData, error) {
bs, err := ioutil.ReadAll(r)
if err != nil {
return MetaData{}, err
}
return Decode(string(bs), v)
}
// unify performs a sort of type unification based on the structure of `rv`,
// which is the client representation.
//
// Any type mismatch produces an error. Finding a type that we don't know
// how to handle produces an unsupported type error.
func unify(data interface{}, rv reflect.Value) error {
// Special case. Look for a `Primitive` value.
if rv.Type() == reflect.TypeOf((*Primitive)(nil)).Elem() {
return unifyAnything(data, rv)
}
// Special case. Look for a value satisfying the TextUnmarshaler interface.
if v, ok := rv.Interface().(TextUnmarshaler); ok {
return unifyText(data, v)
}
// BUG(burntsushi)
// The behavior here is incorrect whenever a Go type satisfies the
// encoding.TextUnmarshaler interface but also corresponds to a TOML
// hash or array. In particular, the unmarshaler should only be applied
// to primitive TOML values. But at this point, it will be applied to
// all kinds of values and produce an incorrect error whenever those values
// are hashes or arrays (including arrays of tables).
k := rv.Kind()
// laziness
if k >= reflect.Int && k <= reflect.Uint64 {
return unifyInt(data, rv)
}
switch k {
case reflect.Ptr:
elem := reflect.New(rv.Type().Elem())
err := unify(data, reflect.Indirect(elem))
if err != nil {
return err
}
rv.Set(elem)
return nil
case reflect.Struct:
return unifyStruct(data, rv)
case reflect.Map:
return unifyMap(data, rv)
case reflect.Array:
return unifyArray(data, rv)
case reflect.Slice:
return unifySlice(data, rv)
case reflect.String:
return unifyString(data, rv)
case reflect.Bool:
return unifyBool(data, rv)
case reflect.Interface:
// we only support empty interfaces.
if rv.NumMethod() > 0 {
return e("Unsupported type '%s'.", rv.Kind())
}
return unifyAnything(data, rv)
case reflect.Float32:
fallthrough
case reflect.Float64:
return unifyFloat64(data, rv)
}
return e("Unsupported type '%s'.", rv.Kind())
}
func unifyStruct(mapping interface{}, rv reflect.Value) error {
tmap, ok := mapping.(map[string]interface{})
if !ok {
return mismatch(rv, "map", mapping)
}
for key, datum := range tmap {
var f *field
fields := cachedTypeFields(rv.Type())
for i := range fields {
ff := &fields[i]
if ff.name == key {
f = ff
break
}
if f == nil && strings.EqualFold(ff.name, key) {
f = ff
}
}
if f != nil {
subv := rv
for _, i := range f.index {
if subv.Kind() == reflect.Ptr {
if subv.IsNil() {
subv.Set(reflect.New(subv.Type().Elem()))
}
subv = subv.Elem()
}
subv = subv.Field(i)
}
sf := indirect(subv)
if isUnifiable(sf) {
if err := unify(datum, sf); err != nil {
return e("Type mismatch for '%s.%s': %s",
rv.Type().String(), f.name, err)
}
} else if f.name != "" {
// Bad user! No soup for you!
return e("Field '%s.%s' is unexported, and therefore cannot "+
"be loaded with reflection.", rv.Type().String(), f.name)
}
}
}
return nil
}
func unifyMap(mapping interface{}, rv reflect.Value) error {
tmap, ok := mapping.(map[string]interface{})
if !ok {
return badtype("map", mapping)
}
if rv.IsNil() {
rv.Set(reflect.MakeMap(rv.Type()))
}
for k, v := range tmap {
rvkey := indirect(reflect.New(rv.Type().Key()))
rvval := reflect.Indirect(reflect.New(rv.Type().Elem()))
if err := unify(v, rvval); err != nil {
return err
}
rvkey.SetString(k)
rv.SetMapIndex(rvkey, rvval)
}
return nil
}
func unifyArray(data interface{}, rv reflect.Value) error {
datav := reflect.ValueOf(data)
if datav.Kind() != reflect.Slice {
return badtype("slice", data)
}
sliceLen := datav.Len()
if sliceLen != rv.Len() {
return e("expected array length %d; got TOML array of length %d",
rv.Len(), sliceLen)
}
for i := 0; i < sliceLen; i++ {
v := datav.Index(i).Interface()
sliceval := indirect(rv.Index(i))
if err := unify(v, sliceval); err != nil {
return err
}
}
return nil
}
func unifySlice(data interface{}, rv reflect.Value) error {
datav := reflect.ValueOf(data)
if datav.Kind() != reflect.Slice {
return badtype("slice", data)
}
sliceLen := datav.Len()
if rv.IsNil() {
rv.Set(reflect.MakeSlice(rv.Type(), sliceLen, sliceLen))
}
for i := 0; i < sliceLen; i++ {
v := datav.Index(i).Interface()
sliceval := indirect(rv.Index(i))
if err := unify(v, sliceval); err != nil {
return err
}
}
return nil
}
func unifyDatetime(data interface{}, rv reflect.Value) error {
if _, ok := data.(time.Time); ok {
rv.Set(reflect.ValueOf(data))
return nil
}
return badtype("time.Time", data)
}
func unifyString(data interface{}, rv reflect.Value) error {
if s, ok := data.(string); ok {
rv.SetString(s)
return nil
}
return badtype("string", data)
}
func unifyFloat64(data interface{}, rv reflect.Value) error {
if num, ok := data.(float64); ok {
switch rv.Kind() {
case reflect.Float32:
fallthrough
case reflect.Float64:
rv.SetFloat(num)
default:
panic("bug")
}
return nil
}
return badtype("float", data)
}
func unifyInt(data interface{}, rv reflect.Value) error {
if num, ok := data.(int64); ok {
switch rv.Kind() {
case reflect.Int:
fallthrough
case reflect.Int8:
fallthrough
case reflect.Int16:
fallthrough
case reflect.Int32:
fallthrough
case reflect.Int64:
rv.SetInt(int64(num))
case reflect.Uint:
fallthrough
case reflect.Uint8:
fallthrough
case reflect.Uint16:
fallthrough
case reflect.Uint32:
fallthrough
case reflect.Uint64:
rv.SetUint(uint64(num))
default:
panic("bug")
}
return nil
}
return badtype("integer", data)
}
func unifyBool(data interface{}, rv reflect.Value) error {
if b, ok := data.(bool); ok {
rv.SetBool(b)
return nil
}
return badtype("boolean", data)
}
func unifyAnything(data interface{}, rv reflect.Value) error {
// too awesome to fail
rv.Set(reflect.ValueOf(data))
return nil
}
func unifyText(data interface{}, v TextUnmarshaler) error {
var s string
switch sdata := data.(type) {
case TextMarshaler:
text, err := sdata.MarshalText()
if err != nil {
return err
}
s = string(text)
case fmt.Stringer:
s = sdata.String()
case string:
s = sdata
case bool:
s = fmt.Sprintf("%v", sdata)
case int64:
s = fmt.Sprintf("%d", sdata)
case float64:
s = fmt.Sprintf("%f", sdata)
default:
return badtype("primitive (string-like)", data)
}
if err := v.UnmarshalText([]byte(s)); err != nil {
return err
}
return nil
}
// rvalue returns a reflect.Value of `v`. All pointers are resolved.
func rvalue(v interface{}) reflect.Value {
return indirect(reflect.ValueOf(v))
}
// indirect returns the value pointed to by a pointer.
// Pointers are followed until the value is not a pointer.
// New values are allocated for each nil pointer.
//
// An exception to this rule is if the value satisfies an interface of
// interest to us (like encoding.TextUnmarshaler).
func indirect(v reflect.Value) reflect.Value {
if v.Kind() != reflect.Ptr {
if v.CanAddr() {
pv := v.Addr()
if _, ok := pv.Interface().(TextUnmarshaler); ok {
return pv
}
}
return v
}
if v.IsNil() {
v.Set(reflect.New(v.Type().Elem()))
}
return indirect(reflect.Indirect(v))
}
func isUnifiable(rv reflect.Value) bool {
if rv.CanSet() {
return true
}
if _, ok := rv.Interface().(TextUnmarshaler); ok {
return true
}
return false
}
func tstring(rv reflect.Value) string {
return rv.Type().String()
}
func badtype(expected string, data interface{}) error {
return e("Expected %s but found '%T'.", expected, data)
}
func mismatch(user reflect.Value, expected string, data interface{}) error {
return e("Type mismatch for %s. Expected %s but found '%T'.",
tstring(user), expected, data)
}
func insensitiveGet(
tmap map[string]interface{}, kname string) (interface{}, bool) {
if datum, ok := tmap[kname]; ok {
return datum, true
}
for k, v := range tmap {
if strings.EqualFold(kname, k) {
return v, true
}
}
return nil, false
}
// MetaData allows access to meta information about TOML data that may not
// be inferrable via reflection. In particular, whether a key has been defined
// and the TOML type of a key.
type MetaData struct {
mapping map[string]interface{}
types map[string]tomlType
keys []Key
}
// IsDefined returns true if the key given exists in the TOML data. The key
// should be specified hierarchially. e.g.,
//
// // access the TOML key 'a.b.c'
// IsDefined("a", "b", "c")
//
// IsDefined will return false if an empty key given. Keys are case sensitive.
func (md MetaData) IsDefined(key ...string) bool {
var hashOrVal interface{}
var hash map[string]interface{}
var ok bool
if len(key) == 0 {
return false
}
hashOrVal = md.mapping
for _, k := range key {
if hash, ok = hashOrVal.(map[string]interface{}); !ok {
return false
}
if hashOrVal, ok = hash[k]; !ok {
return false
}
}
return true
}
// Type returns a string representation of the type of the key specified.
//
// Type will return the empty string if given an empty key or a key that
// does not exist. Keys are case sensitive.
func (md MetaData) Type(key ...string) string {
fullkey := strings.Join(key, ".")
if typ, ok := md.types[fullkey]; ok {
return typ.typeString()
}
return ""
}
// Key is the type of any TOML key, including key groups. Use (MetaData).Keys
// to get values of this type.
type Key []string
func (k Key) String() string {
return strings.Join(k, ".")
}
func (k Key) add(piece string) Key {
newKey := make(Key, len(k))
copy(newKey, k)
return append(newKey, piece)
}
// Keys returns a slice of every key in the TOML data, including key groups.
// Each key is itself a slice, where the first element is the top of the
// hierarchy and the last is the most specific.
//
// The list will have the same order as the keys appeared in the TOML data.
//
// All keys returned are non-empty.
func (md MetaData) Keys() []Key {
return md.keys
}
func allKeys(m map[string]interface{}, context Key) []Key {
keys := make([]Key, 0, len(m))
for k, v := range m {
keys = append(keys, context.add(k))
if t, ok := v.(map[string]interface{}); ok {
keys = append(keys, allKeys(t, context.add(k))...)
}
}
return keys
}

445
vendor/github.com/BurntSushi/toml/decode_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,445 @@
package toml
import (
"encoding/json"
"fmt"
"log"
"reflect"
"testing"
"time"
)
func init() {
log.SetFlags(0)
}
var testSimple = `
age = 250
andrew = "gallant"
kait = "brady"
now = 1987-07-05T05:45:00Z
yesOrNo = true
pi = 3.14
colors = [
["red", "green", "blue"],
["cyan", "magenta", "yellow", "black"],
]
[Annoying.Cats]
plato = "smelly"
cauchy = "stupido"
`
type kitties struct {
Plato string
Cauchy string
}
type simple struct {
Age int
Colors [][]string
Pi float64
YesOrNo bool
Now time.Time
Andrew string
Kait string
Annoying map[string]kitties
}
func TestDecode(t *testing.T) {
var val simple
md, err := Decode(testSimple, &val)
if err != nil {
t.Fatal(err)
}
testf("Is 'Annoying.Cats.plato' defined? %v\n",
md.IsDefined("Annoying", "Cats", "plato"))
testf("Is 'Cats.Stinky' defined? %v\n", md.IsDefined("Cats", "Stinky"))
testf("Type of 'colors'? %s\n\n", md.Type("colors"))
testf("%v\n", val)
}
func TestDecodeEmbedded(t *testing.T) {
type Dog struct{ Name string }
tests := map[string]struct {
input string
decodeInto interface{}
wantDecoded interface{}
}{
"embedded struct": {
input: `Name = "milton"`,
decodeInto: &struct{ Dog }{},
wantDecoded: &struct{ Dog }{Dog{"milton"}},
},
"embedded non-nil pointer to struct": {
input: `Name = "milton"`,
decodeInto: &struct{ *Dog }{},
wantDecoded: &struct{ *Dog }{&Dog{"milton"}},
},
"embedded nil pointer to struct": {
input: ``,
decodeInto: &struct{ *Dog }{},
wantDecoded: &struct{ *Dog }{nil},
},
}
for label, test := range tests {
_, err := Decode(test.input, test.decodeInto)
if err != nil {
t.Fatal(err)
}
want, got := jsonstr(test.wantDecoded), jsonstr(test.decodeInto)
if want != got {
t.Errorf("%s: want decoded == %+v, got %+v", label, want, got)
}
}
}
// jsonstr allows comparison of deeply nested structs with pointer members.
func jsonstr(o interface{}) string {
s, err := json.MarshalIndent(o, "", " ")
if err != nil {
panic(err.Error())
}
return string(s)
}
var tomlTableArrays = `
[[albums]]
name = "Born to Run"
[[albums.songs]]
name = "Jungleland"
[[albums.songs]]
name = "Meeting Across the River"
[[albums]]
name = "Born in the USA"
[[albums.songs]]
name = "Glory Days"
[[albums.songs]]
name = "Dancing in the Dark"
`
type Music struct {
Albums []Album
}
type Album struct {
Name string
Songs []Song
}
type Song struct {
Name string
}
func TestTableArrays(t *testing.T) {
expected := Music{[]Album{
{"Born to Run", []Song{{"Jungleland"}, {"Meeting Across the River"}}},
{"Born in the USA", []Song{{"Glory Days"}, {"Dancing in the Dark"}}},
}}
var got Music
if _, err := Decode(tomlTableArrays, &got); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(expected, got) {
t.Fatalf("\n%#v\n!=\n%#v\n", expected, got)
}
}
// Case insensitive matching tests.
// A bit more comprehensive than needed given the current implementation,
// but implementations change.
// Probably still missing demonstrations of some ugly corner cases regarding
// case insensitive matching and multiple fields.
var caseToml = `
tOpString = "string"
tOpInt = 1
tOpFloat = 1.1
tOpBool = true
tOpdate = 2006-01-02T15:04:05Z
tOparray = [ "array" ]
Match = "i should be in Match only"
MatcH = "i should be in MatcH only"
once = "just once"
[nEst.eD]
nEstedString = "another string"
`
type Insensitive struct {
TopString string
TopInt int
TopFloat float64
TopBool bool
TopDate time.Time
TopArray []string
Match string
MatcH string
Once string
OncE string
Nest InsensitiveNest
}
type InsensitiveNest struct {
Ed InsensitiveEd
}
type InsensitiveEd struct {
NestedString string
}
func TestCase(t *testing.T) {
tme, err := time.Parse(time.RFC3339, time.RFC3339[:len(time.RFC3339)-5])
if err != nil {
panic(err)
}
expected := Insensitive{
TopString: "string",
TopInt: 1,
TopFloat: 1.1,
TopBool: true,
TopDate: tme,
TopArray: []string{"array"},
MatcH: "i should be in MatcH only",
Match: "i should be in Match only",
Once: "just once",
OncE: "",
Nest: InsensitiveNest{
Ed: InsensitiveEd{NestedString: "another string"},
},
}
var got Insensitive
_, err = Decode(caseToml, &got)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(expected, got) {
t.Fatalf("\n%#v\n!=\n%#v\n", expected, got)
}
}
func TestPointers(t *testing.T) {
type Object struct {
Type string
Description string
}
type Dict struct {
NamedObject map[string]*Object
BaseObject *Object
Strptr *string
Strptrs []*string
}
s1, s2, s3 := "blah", "abc", "def"
expected := &Dict{
Strptr: &s1,
Strptrs: []*string{&s2, &s3},
NamedObject: map[string]*Object{
"foo": {"FOO", "fooooo!!!"},
"bar": {"BAR", "ba-ba-ba-ba-barrrr!!!"},
},
BaseObject: &Object{"BASE", "da base"},
}
ex1 := `
Strptr = "blah"
Strptrs = ["abc", "def"]
[NamedObject.foo]
Type = "FOO"
Description = "fooooo!!!"
[NamedObject.bar]
Type = "BAR"
Description = "ba-ba-ba-ba-barrrr!!!"
[BaseObject]
Type = "BASE"
Description = "da base"
`
dict := new(Dict)
_, err := Decode(ex1, dict)
if err != nil {
t.Errorf("Decode error: %v", err)
}
if !reflect.DeepEqual(expected, dict) {
t.Fatalf("\n%#v\n!=\n%#v\n", expected, dict)
}
}
type sphere struct {
Center [3]float64
Radius float64
}
func TestDecodeArrays(t *testing.T) {
var s1 sphere
if _, err := Decode(`center = [0.0, 1.5, 0.0]`, &s1); err != nil {
t.Fatal(err)
}
var s2 sphere
if _, err := Decode(`center = [0.1, 2.3]`, &s2); err == nil {
t.Fatal("Expected array type mismatch error")
}
}
func ExamplePrimitiveDecode() {
var md MetaData
var err error
var tomlBlob = `
ranking = ["Springsteen", "J Geils"]
[bands.Springsteen]
started = 1973
albums = ["Greetings", "WIESS", "Born to Run", "Darkness"]
[bands.J Geils]
started = 1970
albums = ["The J. Geils Band", "Full House", "Blow Your Face Out"]
`
type band struct {
Started int
Albums []string
}
type classics struct {
Ranking []string
Bands map[string]Primitive
}
// Do the initial decode. Reflection is delayed on Primitive values.
var music classics
if md, err = Decode(tomlBlob, &music); err != nil {
log.Fatal(err)
}
// MetaData still includes information on Primitive values.
fmt.Printf("Is `bands.Springsteen` defined? %v\n",
md.IsDefined("bands", "Springsteen"))
// Decode primitive data into Go values.
for _, artist := range music.Ranking {
// A band is a primitive value, so we need to decode it to get a
// real `band` value.
primValue := music.Bands[artist]
var aBand band
if err = PrimitiveDecode(primValue, &aBand); err != nil {
log.Fatal(err)
}
fmt.Printf("%s started in %d.\n", artist, aBand.Started)
}
// Output:
// Is `bands.Springsteen` defined? true
// Springsteen started in 1973.
// J Geils started in 1970.
}
func ExampleDecode() {
var tomlBlob = `
# Some comments.
[alpha]
ip = "10.0.0.1"
[alpha.config]
Ports = [ 8001, 8002 ]
Location = "Toronto"
Created = 1987-07-05T05:45:00Z
[beta]
ip = "10.0.0.2"
[beta.config]
Ports = [ 9001, 9002 ]
Location = "New Jersey"
Created = 1887-01-05T05:55:00Z
`
type serverConfig struct {
Ports []int
Location string
Created time.Time
}
type server struct {
IP string `toml:"ip"`
Config serverConfig `toml:"config"`
}
type servers map[string]server
var config servers
if _, err := Decode(tomlBlob, &config); err != nil {
log.Fatal(err)
}
for _, name := range []string{"alpha", "beta"} {
s := config[name]
fmt.Printf("Server: %s (ip: %s) in %s created on %s\n",
name, s.IP, s.Config.Location,
s.Config.Created.Format("2006-01-02"))
fmt.Printf("Ports: %v\n", s.Config.Ports)
}
// Output:
// Server: alpha (ip: 10.0.0.1) in Toronto created on 1987-07-05
// Ports: [8001 8002]
// Server: beta (ip: 10.0.0.2) in New Jersey created on 1887-01-05
// Ports: [9001 9002]
}
type duration struct {
time.Duration
}
func (d *duration) UnmarshalText(text []byte) error {
var err error
d.Duration, err = time.ParseDuration(string(text))
return err
}
// Example Unmarshaler blah blah.
func ExampleUnmarshaler() {
blob := `
[[song]]
name = "Thunder Road"
duration = "4m49s"
[[song]]
name = "Stairway to Heaven"
duration = "8m03s"
`
type song struct {
Name string
Duration duration
}
type songs struct {
Song []song
}
var favorites songs
if _, err := Decode(blob, &favorites); err != nil {
log.Fatal(err)
}
for _, s := range favorites.Song {
fmt.Printf("%s (%s)\n", s.Name, s.Duration)
}
// Output:
// Thunder Road (4m49s)
// Stairway to Heaven (8m3s)
}

10
vendor/github.com/BurntSushi/toml/doc.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,10 @@
/*
Package toml provides facilities for decoding TOML configuration files
via reflection.
Specification: https://github.com/mojombo/toml
Use github.com/BurntSushi/toml/tomlv to check whether a file is valid
TOML or not, with helpful error messages.
*/
package toml

525
vendor/github.com/BurntSushi/toml/encode.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,525 @@
package toml
import (
"bufio"
"errors"
"fmt"
"io"
"reflect"
"sort"
"strconv"
"strings"
)
var (
ErrArrayMixedElementTypes = errors.New(
"can't encode array with mixed element types")
ErrArrayNilElement = errors.New(
"can't encode array with nil element")
)
type Encoder struct {
// A single indentation level. By default it is two spaces.
Indent string
w *bufio.Writer
// hasWritten is whether we have written any output to w yet.
hasWritten bool
}
func NewEncoder(w io.Writer) *Encoder {
return &Encoder{
w: bufio.NewWriter(w),
Indent: " ",
}
}
func (enc *Encoder) Encode(v interface{}) error {
rv := eindirect(reflect.ValueOf(v))
if err := enc.encode(Key([]string{}), rv); err != nil {
return err
}
return enc.w.Flush()
}
func (enc *Encoder) encode(key Key, rv reflect.Value) error {
// Special case. If we can marshal the type to text, then we used that.
if _, ok := rv.Interface().(TextMarshaler); ok {
err := enc.eKeyEq(key)
if err != nil {
return err
}
return enc.eElement(rv)
}
k := rv.Kind()
switch k {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
reflect.Uint64,
reflect.Float32, reflect.Float64,
reflect.String, reflect.Bool:
err := enc.eKeyEq(key)
if err != nil {
return err
}
return enc.eElement(rv)
case reflect.Array, reflect.Slice:
return enc.eArrayOrSlice(key, rv)
case reflect.Interface:
if rv.IsNil() {
return nil
}
return enc.encode(key, rv.Elem())
case reflect.Map:
if rv.IsNil() {
return nil
}
return enc.eTable(key, rv)
case reflect.Ptr:
if rv.IsNil() {
return nil
}
return enc.encode(key, rv.Elem())
case reflect.Struct:
return enc.eTable(key, rv)
}
return e("Unsupported type for key '%s': %s", key, k)
}
// eElement encodes any value that can be an array element (primitives and
// arrays).
func (enc *Encoder) eElement(rv reflect.Value) error {
ws := func(s string) error {
_, err := io.WriteString(enc.w, s)
return err
}
// By the TOML spec, all floats must have a decimal with at least one
// number on either side.
floatAddDecimal := func(fstr string) string {
if !strings.Contains(fstr, ".") {
return fstr + ".0"
}
return fstr
}
// Special case. Use text marshaler if it's available for this value.
if v, ok := rv.Interface().(TextMarshaler); ok {
s, err := v.MarshalText()
if err != nil {
return err
}
return ws(string(s))
}
var err error
k := rv.Kind()
switch k {
case reflect.Bool:
err = ws(strconv.FormatBool(rv.Bool()))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
err = ws(strconv.FormatInt(rv.Int(), 10))
case reflect.Uint, reflect.Uint8, reflect.Uint16,
reflect.Uint32, reflect.Uint64:
err = ws(strconv.FormatUint(rv.Uint(), 10))
case reflect.Float32:
err = ws(floatAddDecimal(strconv.FormatFloat(rv.Float(), 'f', -1, 32)))
case reflect.Float64:
err = ws(floatAddDecimal(strconv.FormatFloat(rv.Float(), 'f', -1, 64)))
case reflect.Array, reflect.Slice:
return enc.eArrayOrSliceElement(rv)
case reflect.Interface:
return enc.eElement(rv.Elem())
case reflect.String:
s := rv.String()
s = strings.NewReplacer(
"\t", "\\t",
"\n", "\\n",
"\r", "\\r",
"\"", "\\\"",
"\\", "\\\\",
).Replace(s)
err = ws("\"" + s + "\"")
default:
return e("Unexpected primitive type: %s", k)
}
return err
}
func (enc *Encoder) eArrayOrSlice(key Key, rv reflect.Value) error {
// Determine whether this is an array of tables or of primitives.
elemV := reflect.ValueOf(nil)
if rv.Len() > 0 {
elemV = rv.Index(0)
}
isTableType, err := isTOMLTableType(rv.Type().Elem(), elemV)
if err != nil {
return err
}
if len(key) > 0 && isTableType {
return enc.eArrayOfTables(key, rv)
}
err = enc.eKeyEq(key)
if err != nil {
return err
}
return enc.eArrayOrSliceElement(rv)
}
func (enc *Encoder) eArrayOrSliceElement(rv reflect.Value) error {
if _, err := enc.w.Write([]byte{'['}); err != nil {
return err
}
length := rv.Len()
if length > 0 {
arrayElemType, isNil := tomlTypeName(rv.Index(0))
if isNil {
return ErrArrayNilElement
}
for i := 0; i < length; i++ {
elem := rv.Index(i)
// Ensure that the array's elements each have the same TOML type.
elemType, isNil := tomlTypeName(elem)
if isNil {
return ErrArrayNilElement
}
if elemType != arrayElemType {
return ErrArrayMixedElementTypes
}
if err := enc.eElement(elem); err != nil {
return err
}
if i != length-1 {
if _, err := enc.w.Write([]byte(", ")); err != nil {
return err
}
}
}
}
if _, err := enc.w.Write([]byte{']'}); err != nil {
return err
}
return nil
}
func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) error {
if enc.hasWritten {
_, err := enc.w.Write([]byte{'\n'})
if err != nil {
return err
}
}
for i := 0; i < rv.Len(); i++ {
trv := rv.Index(i)
if isNil(trv) {
continue
}
_, err := fmt.Fprintf(enc.w, "%s[[%s]]\n",
strings.Repeat(enc.Indent, len(key)-1), key.String())
if err != nil {
return err
}
err = enc.eMapOrStruct(key, trv)
if err != nil {
return err
}
if i != rv.Len()-1 {
if _, err := enc.w.Write([]byte("\n\n")); err != nil {
return err
}
}
enc.hasWritten = true
}
return nil
}
func isStructOrMap(rv reflect.Value) bool {
switch rv.Kind() {
case reflect.Interface, reflect.Ptr:
return isStructOrMap(rv.Elem())
case reflect.Map, reflect.Struct:
return true
default:
return false
}
}
func (enc *Encoder) eTable(key Key, rv reflect.Value) error {
if enc.hasWritten {
_, err := enc.w.Write([]byte{'\n'})
if err != nil {
return err
}
}
if len(key) > 0 {
_, err := fmt.Fprintf(enc.w, "%s[%s]\n",
strings.Repeat(enc.Indent, len(key)-1), key.String())
if err != nil {
return err
}
}
return enc.eMapOrStruct(key, rv)
}
func (enc *Encoder) eMapOrStruct(key Key, rv reflect.Value) error {
switch rv.Kind() {
case reflect.Map:
return enc.eMap(key, rv)
case reflect.Struct:
return enc.eStruct(key, rv)
case reflect.Ptr, reflect.Interface:
return enc.eMapOrStruct(key, rv.Elem())
default:
panic("eTable: unhandled reflect.Value Kind: " + rv.Kind().String())
}
}
func (enc *Encoder) eMap(key Key, rv reflect.Value) error {
rt := rv.Type()
if rt.Key().Kind() != reflect.String {
return errors.New("can't encode a map with non-string key type")
}
// Sort keys so that we have deterministic output. And write keys directly
// underneath this key first, before writing sub-structs or sub-maps.
var mapKeysDirect, mapKeysSub []string
for _, mapKey := range rv.MapKeys() {
k := mapKey.String()
mrv := rv.MapIndex(mapKey)
if isStructOrMap(mrv) {
mapKeysSub = append(mapKeysSub, k)
} else {
mapKeysDirect = append(mapKeysDirect, k)
}
}
var writeMapKeys = func(mapKeys []string) error {
sort.Strings(mapKeys)
for i, mapKey := range mapKeys {
mrv := rv.MapIndex(reflect.ValueOf(mapKey))
if isNil(mrv) {
// Don't write anything for nil fields.
continue
}
if err := enc.encode(key.add(mapKey), mrv); err != nil {
return err
}
if i != len(mapKeys)-1 {
if _, err := enc.w.Write([]byte{'\n'}); err != nil {
return err
}
}
enc.hasWritten = true
}
return nil
}
err := writeMapKeys(mapKeysDirect)
if err != nil {
return err
}
err = writeMapKeys(mapKeysSub)
if err != nil {
return err
}
return nil
}
func (enc *Encoder) eStruct(key Key, rv reflect.Value) error {
// Write keys for fields directly under this key first, because if we write
// a field that creates a new table, then all keys under it will be in that
// table (not the one we're writing here).
rt := rv.Type()
var fieldsDirect, fieldsSub [][]int
var addFields func(rt reflect.Type, rv reflect.Value, start []int) error
addFields = func(rt reflect.Type, rv reflect.Value, start []int) error {
for i := 0; i < rt.NumField(); i++ {
f := rt.Field(i)
frv := rv.Field(i)
if f.Anonymous {
t := frv.Type()
if t.Kind() == reflect.Ptr {
t = t.Elem()
frv = frv.Elem()
}
if t.Kind() != reflect.Struct {
return errors.New(
"can't encode an anonymous field that is not a struct")
}
if err := addFields(t, frv, f.Index); err != nil {
return err
}
} else if isStructOrMap(frv) {
fieldsSub = append(fieldsSub, append(start, f.Index...))
} else {
fieldsDirect = append(fieldsDirect, append(start, f.Index...))
}
}
return nil
}
if err := addFields(rt, rv, nil); err != nil {
return err
}
var writeFields = func(fields [][]int) error {
for i, fieldIndex := range fields {
sft := rt.FieldByIndex(fieldIndex)
sf := rv.FieldByIndex(fieldIndex)
if isNil(sf) {
// Don't write anything for nil fields.
continue
}
keyName := sft.Tag.Get("toml")
if keyName == "-" {
continue
}
if keyName == "" {
keyName = sft.Name
}
if err := enc.encode(key.add(keyName), sf); err != nil {
return err
}
if i != len(fields)-1 {
if _, err := enc.w.Write([]byte{'\n'}); err != nil {
return err
}
}
enc.hasWritten = true
}
return nil
}
err := writeFields(fieldsDirect)
if err != nil {
return err
}
if len(fieldsDirect) > 0 && len(fieldsSub) > 0 {
_, err = enc.w.Write([]byte{'\n'})
if err != nil {
return err
}
}
err = writeFields(fieldsSub)
if err != nil {
return err
}
return nil
}
// tomlTypeName returns the TOML type name of the Go value's type. It is used to
// determine whether the types of array elements are mixed (which is forbidden).
// If the Go value is nil, then it is illegal for it to be an array element, and
// valueIsNil is returned as true.
func tomlTypeName(rv reflect.Value) (typeName string, valueIsNil bool) {
if isNil(rv) {
return "", true
}
k := rv.Kind()
switch k {
case reflect.Bool:
return "bool", false
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
reflect.Uint64:
return "integer", false
case reflect.Float32, reflect.Float64:
return "float", false
case reflect.Array, reflect.Slice:
return "array", false
case reflect.Ptr, reflect.Interface:
return tomlTypeName(rv.Elem())
case reflect.String:
return "string", false
case reflect.Map, reflect.Struct:
return "table", false
default:
panic("unexpected reflect.Kind: " + k.String())
}
}
// isTOMLTableType returns whether this type and value represents a TOML table
// type (true) or element type (false). Both rt and rv are needed to determine
// this, in case the Go type is interface{} or in case rv is nil. If there is
// some other impossible situation detected, an error is returned.
func isTOMLTableType(rt reflect.Type, rv reflect.Value) (bool, error) {
k := rt.Kind()
switch k {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
reflect.Uint64,
reflect.Float32, reflect.Float64,
reflect.String, reflect.Bool:
return false, nil
case reflect.Array, reflect.Slice:
// Make sure that these eventually contain an underlying non-table type
// element.
elemV := reflect.ValueOf(nil)
if rv.Len() > 0 {
elemV = rv.Index(0)
}
hasUnderlyingTableType, err := isTOMLTableType(rt.Elem(), elemV)
if err != nil {
return false, err
}
if hasUnderlyingTableType {
return true, errors.New("TOML array element can't contain a table")
}
return false, nil
case reflect.Ptr:
return isTOMLTableType(rt.Elem(), rv.Elem())
case reflect.Interface:
if rv.Kind() == reflect.Interface {
return false, nil
}
return isTOMLTableType(rv.Type(), rv)
case reflect.Map, reflect.Struct:
return true, nil
default:
panic("unexpected reflect.Kind: " + k.String())
}
}
func isNil(rv reflect.Value) bool {
switch rv.Kind() {
case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
return rv.IsNil()
default:
return false
}
}
func (enc *Encoder) eKeyEq(key Key) error {
_, err := io.WriteString(enc.w, strings.Repeat(enc.Indent, len(key)-1))
if err != nil {
return err
}
_, err = io.WriteString(enc.w, key[len(key)-1]+" = ")
if err != nil {
return err
}
return nil
}
func eindirect(v reflect.Value) reflect.Value {
if v.Kind() != reflect.Ptr {
return v
}
return eindirect(reflect.Indirect(v))
}

282
vendor/github.com/BurntSushi/toml/encode_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,282 @@
package toml
import (
"bytes"
"testing"
)
// XXX(burntsushi)
// I think these tests probably should be removed. They are good, but they
// ought to be obsolete by toml-test.
func TestEncode(t *testing.T) {
tests := map[string]struct {
input interface{}
wantOutput string
wantError error
}{
"bool field": {
input: struct {
BoolTrue bool
BoolFalse bool
}{true, false},
wantOutput: "BoolTrue = true\nBoolFalse = false",
},
"int fields": {
input: struct {
Int int
Int8 int8
Int16 int16
Int32 int32
Int64 int64
}{1, 2, 3, 4, 5},
wantOutput: "Int = 1\nInt8 = 2\nInt16 = 3\nInt32 = 4\nInt64 = 5",
},
"uint fields": {
input: struct {
Uint uint
Uint8 uint8
Uint16 uint16
Uint32 uint32
Uint64 uint64
}{1, 2, 3, 4, 5},
wantOutput: "Uint = 1\nUint8 = 2\nUint16 = 3\nUint32 = 4" +
"\nUint64 = 5",
},
"float fields": {
input: struct {
Float32 float32
Float64 float64
}{1.5, 2.5},
wantOutput: "Float32 = 1.5\nFloat64 = 2.5",
},
"string field": {
input: struct{ String string }{"foo"},
wantOutput: `String = "foo"`,
},
"array fields": {
input: struct {
IntArray0 [0]int
IntArray3 [3]int
}{[0]int{}, [3]int{1, 2, 3}},
wantOutput: "IntArray0 = []\nIntArray3 = [1, 2, 3]",
},
"slice fields": {
input: struct{ IntSliceNil, IntSlice0, IntSlice3 []int }{
nil, []int{}, []int{1, 2, 3},
},
wantOutput: "IntSlice0 = []\nIntSlice3 = [1, 2, 3]",
},
"nested arrays and slices": {
input: struct {
SliceOfArrays [][2]int
ArrayOfSlices [2][]int
SliceOfArraysOfSlices [][2][]int
ArrayOfSlicesOfArrays [2][][2]int
SliceOfMixedArrays [][2]interface{}
ArrayOfMixedSlices [2][]interface{}
}{
[][2]int{{1, 2}, {3, 4}},
[2][]int{{1, 2}, {3, 4}},
[][2][]int{
{
{1, 2}, {3, 4},
},
{
{5, 6}, {7, 8},
},
},
[2][][2]int{
{
{1, 2}, {3, 4},
},
{
{5, 6}, {7, 8},
},
},
[][2]interface{}{
{1, 2}, {"a", "b"},
},
[2][]interface{}{
{1, 2}, {"a", "b"},
},
},
wantOutput: `SliceOfArrays = [[1, 2], [3, 4]]
ArrayOfSlices = [[1, 2], [3, 4]]
SliceOfArraysOfSlices = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
ArrayOfSlicesOfArrays = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
SliceOfMixedArrays = [[1, 2], ["a", "b"]]
ArrayOfMixedSlices = [[1, 2], ["a", "b"]]`,
},
"(error) slice with element type mismatch (string and integer)": {
input: struct{ Mixed []interface{} }{[]interface{}{1, "a"}},
wantError: ErrArrayMixedElementTypes,
},
"(error) slice with element type mismatch (integer and float)": {
input: struct{ Mixed []interface{} }{[]interface{}{1, 2.5}},
wantError: ErrArrayMixedElementTypes,
},
"slice with elems of differing Go types, same TOML types": {
input: struct {
MixedInts []interface{}
MixedFloats []interface{}
}{
[]interface{}{
int(1), int8(2), int16(3), int32(4), int64(5),
uint(1), uint8(2), uint16(3), uint32(4), uint64(5),
},
[]interface{}{float32(1.5), float64(2.5)},
},
wantOutput: "MixedInts = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]\n" +
"MixedFloats = [1.5, 2.5]",
},
"(error) slice w/ element type mismatch (one is nested array)": {
input: struct{ Mixed []interface{} }{
[]interface{}{1, []interface{}{2}},
},
wantError: ErrArrayMixedElementTypes,
},
"(error) slice with 1 nil element": {
input: struct{ NilElement1 []interface{} }{[]interface{}{nil}},
wantError: ErrArrayNilElement,
},
"(error) slice with 1 nil element (and other non-nil elements)": {
input: struct{ NilElement []interface{} }{
[]interface{}{1, nil},
},
wantError: ErrArrayNilElement,
},
"simple map": {
input: map[string]int{"a": 1, "b": 2},
wantOutput: "a = 1\nb = 2",
},
"map with interface{} value type": {
input: map[string]interface{}{"a": 1, "b": "c"},
wantOutput: "a = 1\nb = \"c\"",
},
"map with interface{} value type, some of which are structs": {
input: map[string]interface{}{
"a": struct{ Int int }{2},
"b": 1,
},
wantOutput: "b = 1\n[a]\n Int = 2",
},
"nested map": {
input: map[string]map[string]int{
"a": {"b": 1},
"c": {"d": 2},
},
wantOutput: "[a]\n b = 1\n\n[c]\n d = 2",
},
"nested struct": {
input: struct{ Struct struct{ Int int } }{
struct{ Int int }{1},
},
wantOutput: "[Struct]\n Int = 1",
},
"nested struct and non-struct field": {
input: struct {
Struct struct{ Int int }
Bool bool
}{struct{ Int int }{1}, true},
wantOutput: "Bool = true\n\n[Struct]\n Int = 1",
},
"2 nested structs": {
input: struct{ Struct1, Struct2 struct{ Int int } }{
struct{ Int int }{1}, struct{ Int int }{2},
},
wantOutput: "[Struct1]\n Int = 1\n\n[Struct2]\n Int = 2",
},
"deeply nested structs": {
input: struct {
Struct1, Struct2 struct{ Struct3 *struct{ Int int } }
}{
struct{ Struct3 *struct{ Int int } }{&struct{ Int int }{1}},
struct{ Struct3 *struct{ Int int } }{nil},
},
wantOutput: "[Struct1]\n [Struct1.Struct3]\n Int = 1" +
"\n\n[Struct2]\n",
},
"nested struct with nil struct elem": {
input: struct {
Struct struct{ Inner *struct{ Int int } }
}{
struct{ Inner *struct{ Int int } }{nil},
},
wantOutput: "[Struct]\n",
},
"nested struct with no fields": {
input: struct {
Struct struct{ Inner struct{} }
}{
struct{ Inner struct{} }{struct{}{}},
},
wantOutput: "[Struct]\n [Struct.Inner]\n",
},
"struct with tags": {
input: struct {
Struct struct {
Int int `toml:"_int"`
} `toml:"_struct"`
Bool bool `toml:"_bool"`
}{
struct {
Int int `toml:"_int"`
}{1}, true,
},
wantOutput: "_bool = true\n\n[_struct]\n _int = 1",
},
"embedded struct": {
input: struct{ Embedded }{Embedded{1}},
wantOutput: "_int = 1",
},
"embedded *struct": {
input: struct{ *Embedded }{&Embedded{1}},
wantOutput: "_int = 1",
},
"nested embedded struct": {
input: struct {
Struct struct{ Embedded } `toml:"_struct"`
}{struct{ Embedded }{Embedded{1}}},
wantOutput: "[_struct]\n _int = 1",
},
"nested embedded *struct": {
input: struct {
Struct struct{ *Embedded } `toml:"_struct"`
}{struct{ *Embedded }{&Embedded{1}}},
wantOutput: "[_struct]\n _int = 1",
},
"array of tables": {
input: struct {
Structs []*struct{ Int int } `toml:"struct"`
}{
[]*struct{ Int int }{
{1}, nil, {3},
},
},
wantOutput: "[[struct]]\n Int = 1\n\n[[struct]]\n Int = 3",
},
}
for label, test := range tests {
var buf bytes.Buffer
e := NewEncoder(&buf)
err := e.Encode(test.input)
if err != test.wantError {
if test.wantError != nil {
t.Errorf("%s: want Encode error %v, got %v",
label, test.wantError, err)
} else {
t.Errorf("%s: Encode failed: %s", label, err)
}
}
if err != nil {
continue
}
if got := buf.String(); test.wantOutput != got {
t.Errorf("%s: want %q, got %q", label, test.wantOutput, got)
}
}
}
type Embedded struct {
Int int `toml:"_int"`
}

10
vendor/github.com/BurntSushi/toml/encoding_types.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,10 @@
// +build go1.2
package toml
import (
"encoding"
)
type TextMarshaler encoding.TextMarshaler
type TextUnmarshaler encoding.TextUnmarshaler

11
vendor/github.com/BurntSushi/toml/encoding_types_1.1.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,11 @@
// +build !go1.2
package toml
type TextMarshaler interface {
MarshalText() (text []byte, err error)
}
type TextUnmarshaler interface {
UnmarshalText(text []byte) error
}

725
vendor/github.com/BurntSushi/toml/lex.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,725 @@
package toml
import (
"fmt"
"unicode/utf8"
)
type itemType int
const (
itemError itemType = iota
itemNIL // used in the parser to indicate no type
itemEOF
itemText
itemString
itemBool
itemInteger
itemFloat
itemDatetime
itemArray // the start of an array
itemArrayEnd
itemTableStart
itemTableEnd
itemArrayTableStart
itemArrayTableEnd
itemKeyStart
itemCommentStart
)
const (
eof = 0
tableStart = '['
tableEnd = ']'
arrayTableStart = '['
arrayTableEnd = ']'
tableSep = '.'
keySep = '='
arrayStart = '['
arrayEnd = ']'
arrayValTerm = ','
commentStart = '#'
stringStart = '"'
stringEnd = '"'
)
type stateFn func(lx *lexer) stateFn
type lexer struct {
input string
start int
pos int
width int
line int
state stateFn
items chan item
// A stack of state functions used to maintain context.
// The idea is to reuse parts of the state machine in various places.
// For example, values can appear at the top level or within arbitrarily
// nested arrays. The last state on the stack is used after a value has
// been lexed. Similarly for comments.
stack []stateFn
}
type item struct {
typ itemType
val string
line int
}
func (lx *lexer) nextItem() item {
for {
select {
case item := <-lx.items:
return item
default:
lx.state = lx.state(lx)
}
}
}
func lex(input string) *lexer {
lx := &lexer{
input: input + "\n",
state: lexTop,
line: 1,
items: make(chan item, 10),
stack: make([]stateFn, 0, 10),
}
return lx
}
func (lx *lexer) push(state stateFn) {
lx.stack = append(lx.stack, state)
}
func (lx *lexer) pop() stateFn {
if len(lx.stack) == 0 {
return lx.errorf("BUG in lexer: no states to pop.")
}
last := lx.stack[len(lx.stack)-1]
lx.stack = lx.stack[0 : len(lx.stack)-1]
return last
}
func (lx *lexer) current() string {
return lx.input[lx.start:lx.pos]
}
func (lx *lexer) emit(typ itemType) {
lx.items <- item{typ, lx.current(), lx.line}
lx.start = lx.pos
}
func (lx *lexer) next() (r rune) {
if lx.pos >= len(lx.input) {
lx.width = 0
return eof
}
if lx.input[lx.pos] == '\n' {
lx.line++
}
r, lx.width = utf8.DecodeRuneInString(lx.input[lx.pos:])
lx.pos += lx.width
return r
}
// ignore skips over the pending input before this point.
func (lx *lexer) ignore() {
lx.start = lx.pos
}
// backup steps back one rune. Can be called only once per call of next.
func (lx *lexer) backup() {
lx.pos -= lx.width
if lx.pos < len(lx.input) && lx.input[lx.pos] == '\n' {
lx.line--
}
}
// accept consumes the next rune if it's equal to `valid`.
func (lx *lexer) accept(valid rune) bool {
if lx.next() == valid {
return true
}
lx.backup()
return false
}
// peek returns but does not consume the next rune in the input.
func (lx *lexer) peek() rune {
r := lx.next()
lx.backup()
return r
}
// errorf stops all lexing by emitting an error and returning `nil`.
// Note that any value that is a character is escaped if it's a special
// character (new lines, tabs, etc.).
func (lx *lexer) errorf(format string, values ...interface{}) stateFn {
lx.items <- item{
itemError,
fmt.Sprintf(format, values...),
lx.line,
}
return nil
}
// lexTop consumes elements at the top level of TOML data.
func lexTop(lx *lexer) stateFn {
r := lx.next()
if isWhitespace(r) || isNL(r) {
return lexSkip(lx, lexTop)
}
switch r {
case commentStart:
lx.push(lexTop)
return lexCommentStart
case tableStart:
return lexTableStart
case eof:
if lx.pos > lx.start {
return lx.errorf("Unexpected EOF.")
}
lx.emit(itemEOF)
return nil
}
// At this point, the only valid item can be a key, so we back up
// and let the key lexer do the rest.
lx.backup()
lx.push(lexTopEnd)
return lexKeyStart
}
// lexTopEnd is entered whenever a top-level item has been consumed. (A value
// or a table.) It must see only whitespace, and will turn back to lexTop
// upon a new line. If it sees EOF, it will quit the lexer successfully.
func lexTopEnd(lx *lexer) stateFn {
r := lx.next()
switch {
case r == commentStart:
// a comment will read to a new line for us.
lx.push(lexTop)
return lexCommentStart
case isWhitespace(r):
return lexTopEnd
case isNL(r):
lx.ignore()
return lexTop
case r == eof:
lx.ignore()
return lexTop
}
return lx.errorf("Expected a top-level item to end with a new line, "+
"comment or EOF, but got %q instead.", r)
}
// lexTable lexes the beginning of a table. Namely, it makes sure that
// it starts with a character other than '.' and ']'.
// It assumes that '[' has already been consumed.
// It also handles the case that this is an item in an array of tables.
// e.g., '[[name]]'.
func lexTableStart(lx *lexer) stateFn {
if lx.peek() == arrayTableStart {
lx.next()
lx.emit(itemArrayTableStart)
lx.push(lexArrayTableEnd)
} else {
lx.emit(itemTableStart)
lx.push(lexTableEnd)
}
return lexTableNameStart
}
func lexTableEnd(lx *lexer) stateFn {
lx.emit(itemTableEnd)
return lexTopEnd
}
func lexArrayTableEnd(lx *lexer) stateFn {
if r := lx.next(); r != arrayTableEnd {
return lx.errorf("Expected end of table array name delimiter %q, "+
"but got %q instead.", arrayTableEnd, r)
}
lx.emit(itemArrayTableEnd)
return lexTopEnd
}
func lexTableNameStart(lx *lexer) stateFn {
switch lx.next() {
case tableEnd:
return lx.errorf("Unexpected end of table. (Tables cannot " +
"be empty.)")
case tableSep:
return lx.errorf("Unexpected table separator. (Tables cannot " +
"be empty.)")
}
return lexTableName
}
// lexTableName lexes the name of a table. It assumes that at least one
// valid character for the table has already been read.
func lexTableName(lx *lexer) stateFn {
switch lx.peek() {
case tableStart:
return lx.errorf("Table names cannot contain %q or %q.",
tableStart, tableEnd)
case tableEnd:
lx.emit(itemText)
lx.next()
return lx.pop()
case tableSep:
lx.emit(itemText)
lx.next()
lx.ignore()
return lexTableNameStart
}
lx.next()
return lexTableName
}
// lexKeyStart consumes a key name up until the first non-whitespace character.
// lexKeyStart will ignore whitespace.
func lexKeyStart(lx *lexer) stateFn {
r := lx.peek()
switch {
case r == keySep:
return lx.errorf("Unexpected key separator %q.", keySep)
case isWhitespace(r) || isNL(r):
lx.next()
return lexSkip(lx, lexKeyStart)
}
lx.ignore()
lx.emit(itemKeyStart)
lx.next()
return lexKey
}
// lexKey consumes the text of a key. Assumes that the first character (which
// is not whitespace) has already been consumed.
func lexKey(lx *lexer) stateFn {
r := lx.peek()
// XXX: Possible divergence from spec?
// "Keys start with the first non-whitespace character and end with the
// last non-whitespace character before the equals sign."
// Note here that whitespace is either a tab or a space.
// But we'll call it quits if we see a new line too.
if isWhitespace(r) || isNL(r) {
lx.emit(itemText)
return lexKeyEnd
}
// Let's also call it quits if we see an equals sign.
if r == keySep {
lx.emit(itemText)
return lexKeyEnd
}
lx.next()
return lexKey
}
// lexKeyEnd consumes the end of a key (up to the key separator).
// Assumes that the first whitespace character after a key (or the '='
// separator) has NOT been consumed.
func lexKeyEnd(lx *lexer) stateFn {
r := lx.next()
switch {
case isWhitespace(r) || isNL(r):
return lexSkip(lx, lexKeyEnd)
case r == keySep:
return lexSkip(lx, lexValue)
}
return lx.errorf("Expected key separator %q, but got %q instead.",
keySep, r)
}
// lexValue starts the consumption of a value anywhere a value is expected.
// lexValue will ignore whitespace.
// After a value is lexed, the last state on the next is popped and returned.
func lexValue(lx *lexer) stateFn {
// We allow whitespace to precede a value, but NOT new lines.
// In array syntax, the array states are responsible for ignoring new lines.
r := lx.next()
if isWhitespace(r) {
return lexSkip(lx, lexValue)
}
switch {
case r == arrayStart:
lx.ignore()
lx.emit(itemArray)
return lexArrayValue
case r == stringStart:
lx.ignore() // ignore the '"'
return lexString
case r == 't':
return lexTrue
case r == 'f':
return lexFalse
case r == '-':
return lexNumberStart
case isDigit(r):
lx.backup() // avoid an extra state and use the same as above
return lexNumberOrDateStart
case r == '.': // special error case, be kind to users
return lx.errorf("Floats must start with a digit, not '.'.")
}
return lx.errorf("Expected value but found %q instead.", r)
}
// lexArrayValue consumes one value in an array. It assumes that '[' or ','
// have already been consumed. All whitespace and new lines are ignored.
func lexArrayValue(lx *lexer) stateFn {
r := lx.next()
switch {
case isWhitespace(r) || isNL(r):
return lexSkip(lx, lexArrayValue)
case r == commentStart:
lx.push(lexArrayValue)
return lexCommentStart
case r == arrayValTerm:
return lx.errorf("Unexpected array value terminator %q.",
arrayValTerm)
case r == arrayEnd:
return lexArrayEnd
}
lx.backup()
lx.push(lexArrayValueEnd)
return lexValue
}
// lexArrayValueEnd consumes the cruft between values of an array. Namely,
// it ignores whitespace and expects either a ',' or a ']'.
func lexArrayValueEnd(lx *lexer) stateFn {
r := lx.next()
switch {
case isWhitespace(r) || isNL(r):
return lexSkip(lx, lexArrayValueEnd)
case r == commentStart:
lx.push(lexArrayValueEnd)
return lexCommentStart
case r == arrayValTerm:
lx.ignore()
return lexArrayValue // move on to the next value
case r == arrayEnd:
return lexArrayEnd
}
return lx.errorf("Expected an array value terminator %q or an array "+
"terminator %q, but got %q instead.", arrayValTerm, arrayEnd, r)
}
// lexArrayEnd finishes the lexing of an array. It assumes that a ']' has
// just been consumed.
func lexArrayEnd(lx *lexer) stateFn {
lx.ignore()
lx.emit(itemArrayEnd)
return lx.pop()
}
// lexString consumes the inner contents of a string. It assumes that the
// beginning '"' has already been consumed and ignored.
func lexString(lx *lexer) stateFn {
r := lx.next()
switch {
case isNL(r):
return lx.errorf("Strings cannot contain new lines.")
case r == '\\':
return lexStringEscape
case r == stringEnd:
lx.backup()
lx.emit(itemString)
lx.next()
lx.ignore()
return lx.pop()
}
return lexString
}
// lexStringEscape consumes an escaped character. It assumes that the preceding
// '\\' has already been consumed.
func lexStringEscape(lx *lexer) stateFn {
r := lx.next()
switch r {
case 'b':
fallthrough
case 't':
fallthrough
case 'n':
fallthrough
case 'f':
fallthrough
case 'r':
fallthrough
case '"':
fallthrough
case '/':
fallthrough
case '\\':
return lexString
case 'u':
return lexStringUnicode
}
return lx.errorf("Invalid escape character %q. Only the following "+
"escape characters are allowed: "+
"\\b, \\t, \\n, \\f, \\r, \\\", \\/, \\\\, and \\uXXXX.", r)
}
// lexStringBinary consumes two hexadecimal digits following '\x'. It assumes
// that the '\x' has already been consumed.
func lexStringUnicode(lx *lexer) stateFn {
var r rune
for i := 0; i < 4; i++ {
r = lx.next()
if !isHexadecimal(r) {
return lx.errorf("Expected four hexadecimal digits after '\\x', "+
"but got '%s' instead.", lx.current())
}
}
return lexString
}
// lexNumberOrDateStart consumes either a (positive) integer, float or datetime.
// It assumes that NO negative sign has been consumed.
func lexNumberOrDateStart(lx *lexer) stateFn {
r := lx.next()
if !isDigit(r) {
if r == '.' {
return lx.errorf("Floats must start with a digit, not '.'.")
} else {
return lx.errorf("Expected a digit but got %q.", r)
}
}
return lexNumberOrDate
}
// lexNumberOrDate consumes either a (positive) integer, float or datetime.
func lexNumberOrDate(lx *lexer) stateFn {
r := lx.next()
switch {
case r == '-':
if lx.pos-lx.start != 5 {
return lx.errorf("All ISO8601 dates must be in full Zulu form.")
}
return lexDateAfterYear
case isDigit(r):
return lexNumberOrDate
case r == '.':
return lexFloatStart
}
lx.backup()
lx.emit(itemInteger)
return lx.pop()
}
// lexDateAfterYear consumes a full Zulu Datetime in ISO8601 format.
// It assumes that "YYYY-" has already been consumed.
func lexDateAfterYear(lx *lexer) stateFn {
formats := []rune{
// digits are '0'.
// everything else is direct equality.
'0', '0', '-', '0', '0',
'T',
'0', '0', ':', '0', '0', ':', '0', '0',
'Z',
}
for _, f := range formats {
r := lx.next()
if f == '0' {
if !isDigit(r) {
return lx.errorf("Expected digit in ISO8601 datetime, "+
"but found %q instead.", r)
}
} else if f != r {
return lx.errorf("Expected %q in ISO8601 datetime, "+
"but found %q instead.", f, r)
}
}
lx.emit(itemDatetime)
return lx.pop()
}
// lexNumberStart consumes either an integer or a float. It assumes that a
// negative sign has already been read, but that *no* digits have been consumed.
// lexNumberStart will move to the appropriate integer or float states.
func lexNumberStart(lx *lexer) stateFn {
// we MUST see a digit. Even floats have to start with a digit.
r := lx.next()
if !isDigit(r) {
if r == '.' {
return lx.errorf("Floats must start with a digit, not '.'.")
} else {
return lx.errorf("Expected a digit but got %q.", r)
}
}
return lexNumber
}
// lexNumber consumes an integer or a float after seeing the first digit.
func lexNumber(lx *lexer) stateFn {
r := lx.next()
switch {
case isDigit(r):
return lexNumber
case r == '.':
return lexFloatStart
}
lx.backup()
lx.emit(itemInteger)
return lx.pop()
}
// lexFloatStart starts the consumption of digits of a float after a '.'.
// Namely, at least one digit is required.
func lexFloatStart(lx *lexer) stateFn {
r := lx.next()
if !isDigit(r) {
return lx.errorf("Floats must have a digit after the '.', but got "+
"%q instead.", r)
}
return lexFloat
}
// lexFloat consumes the digits of a float after a '.'.
// Assumes that one digit has been consumed after a '.' already.
func lexFloat(lx *lexer) stateFn {
r := lx.next()
if isDigit(r) {
return lexFloat
}
lx.backup()
lx.emit(itemFloat)
return lx.pop()
}
// lexConst consumes the s[1:] in s. It assumes that s[0] has already been
// consumed.
func lexConst(lx *lexer, s string) stateFn {
for i := range s[1:] {
if r := lx.next(); r != rune(s[i+1]) {
return lx.errorf("Expected %q, but found %q instead.", s[:i+1],
s[:i]+string(r))
}
}
return nil
}
// lexTrue consumes the "rue" in "true". It assumes that 't' has already
// been consumed.
func lexTrue(lx *lexer) stateFn {
if fn := lexConst(lx, "true"); fn != nil {
return fn
}
lx.emit(itemBool)
return lx.pop()
}
// lexFalse consumes the "alse" in "false". It assumes that 'f' has already
// been consumed.
func lexFalse(lx *lexer) stateFn {
if fn := lexConst(lx, "false"); fn != nil {
return fn
}
lx.emit(itemBool)
return lx.pop()
}
// lexCommentStart begins the lexing of a comment. It will emit
// itemCommentStart and consume no characters, passing control to lexComment.
func lexCommentStart(lx *lexer) stateFn {
lx.ignore()
lx.emit(itemCommentStart)
return lexComment
}
// lexComment lexes an entire comment. It assumes that '#' has been consumed.
// It will consume *up to* the first new line character, and pass control
// back to the last state on the stack.
func lexComment(lx *lexer) stateFn {
r := lx.peek()
if isNL(r) || r == eof {
lx.emit(itemText)
return lx.pop()
}
lx.next()
return lexComment
}
// lexSkip ignores all slurped input and moves on to the next state.
func lexSkip(lx *lexer, nextState stateFn) stateFn {
return func(lx *lexer) stateFn {
lx.ignore()
return nextState
}
}
// isWhitespace returns true if `r` is a whitespace character according
// to the spec.
func isWhitespace(r rune) bool {
return r == '\t' || r == ' '
}
func isNL(r rune) bool {
return r == '\n' || r == '\r'
}
func isDigit(r rune) bool {
return r >= '0' && r <= '9'
}
func isHexadecimal(r rune) bool {
return (r >= '0' && r <= '9') ||
(r >= 'a' && r <= 'f') ||
(r >= 'A' && r <= 'F')
}
func (itype itemType) String() string {
switch itype {
case itemError:
return "Error"
case itemNIL:
return "NIL"
case itemEOF:
return "EOF"
case itemText:
return "Text"
case itemString:
return "String"
case itemBool:
return "Bool"
case itemInteger:
return "Integer"
case itemFloat:
return "Float"
case itemDatetime:
return "DateTime"
case itemTableStart:
return "TableStart"
case itemTableEnd:
return "TableEnd"
case itemKeyStart:
return "KeyStart"
case itemArray:
return "Array"
case itemArrayEnd:
return "ArrayEnd"
case itemCommentStart:
return "CommentStart"
}
panic(fmt.Sprintf("BUG: Unknown type '%d'.", int(itype)))
}
func (item item) String() string {
return fmt.Sprintf("(%s, %s)", item.typ.String(), item.val)
}

59
vendor/github.com/BurntSushi/toml/lex_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,59 @@
package toml
import (
"log"
"testing"
)
func init() {
log.SetFlags(0)
}
var testSmall = `
# This is a TOML document. Boom.
[owner]
[owner] # Whoa there.
andrew = "gallant # poopy" # weeeee
predicate = false
num = -5192
f = -0.5192
zulu = 1979-05-27T07:32:00Z
whoop = "poop"
arrs = [
1987-07-05T05:45:00Z,
5,
"wat?",
"hehe \n\r kewl",
[6], [],
5.0,
# sweetness
] # more comments
# hehe
`
var testSmaller = `
[a.b] # Do you ignore me?
andrew = "ga# ll\"ant" # what about me?
kait = "brady"
awesomeness = true
pi = 3.14
dob = 1987-07-05T17:45:00Z
perfection = [
[6, 28],
[496, 8128]
]
`
func TestLexer(t *testing.T) {
lx := lex(testSmaller)
for {
item := lx.nextItem()
if item.typ == itemEOF {
break
} else if item.typ == itemError {
t.Fatal(item.val)
}
testf("%s\n", item)
}
}

19
vendor/github.com/BurntSushi/toml/out_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,19 @@
package toml
import (
"flag"
"fmt"
)
var flagOut = false
func init() {
flag.BoolVar(&flagOut, "out", flagOut, "Print debug output.")
flag.Parse()
}
func testf(format string, v ...interface{}) {
if flagOut {
fmt.Printf(format, v...)
}
}

417
vendor/github.com/BurntSushi/toml/parse.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,417 @@
package toml
import (
"fmt"
"log"
"strconv"
"strings"
"time"
"unicode/utf8"
)
type parser struct {
mapping map[string]interface{}
types map[string]tomlType
lx *lexer
// A list of keys in the order that they appear in the TOML data.
ordered []Key
// the full key for the current hash in scope
context Key
// the base key name for everything except hashes
currentKey string
// rough approximation of line number
approxLine int
// A map of 'key.group.names' to whether they were created implicitly.
implicits map[string]bool
}
type parseError string
func (pe parseError) Error() string {
return string(pe)
}
func parse(data string) (p *parser, err error) {
defer func() {
if r := recover(); r != nil {
var ok bool
if err, ok = r.(parseError); ok {
return
}
panic(r)
}
}()
p = &parser{
mapping: make(map[string]interface{}),
types: make(map[string]tomlType),
lx: lex(data),
ordered: make([]Key, 0),
implicits: make(map[string]bool),
}
for {
item := p.next()
if item.typ == itemEOF {
break
}
p.topLevel(item)
}
return p, nil
}
func (p *parser) panicf(format string, v ...interface{}) {
msg := fmt.Sprintf("Near line %d, key '%s': %s",
p.approxLine, p.current(), fmt.Sprintf(format, v...))
panic(parseError(msg))
}
func (p *parser) next() item {
it := p.lx.nextItem()
if it.typ == itemError {
p.panicf("Near line %d: %s", it.line, it.val)
}
return it
}
func (p *parser) bug(format string, v ...interface{}) {
log.Fatalf("BUG: %s\n\n", fmt.Sprintf(format, v...))
}
func (p *parser) expect(typ itemType) item {
it := p.next()
p.assertEqual(typ, it.typ)
return it
}
func (p *parser) assertEqual(expected, got itemType) {
if expected != got {
p.bug("Expected '%s' but got '%s'.", expected, got)
}
}
func (p *parser) topLevel(item item) {
switch item.typ {
case itemCommentStart:
p.approxLine = item.line
p.expect(itemText)
case itemTableStart:
kg := p.expect(itemText)
p.approxLine = kg.line
key := make(Key, 0)
for ; kg.typ == itemText; kg = p.next() {
key = append(key, kg.val)
}
p.assertEqual(itemTableEnd, kg.typ)
p.establishContext(key, false)
p.setType("", tomlHash)
p.ordered = append(p.ordered, key)
case itemArrayTableStart:
kg := p.expect(itemText)
p.approxLine = kg.line
key := make(Key, 0)
for ; kg.typ == itemText; kg = p.next() {
key = append(key, kg.val)
}
p.assertEqual(itemArrayTableEnd, kg.typ)
p.establishContext(key, true)
p.setType("", tomlArrayHash)
p.ordered = append(p.ordered, key)
case itemKeyStart:
kname := p.expect(itemText)
p.currentKey = kname.val
p.approxLine = kname.line
val, typ := p.value(p.next())
p.setValue(p.currentKey, val)
p.setType(p.currentKey, typ)
p.ordered = append(p.ordered, p.context.add(p.currentKey))
p.currentKey = ""
default:
p.bug("Unexpected type at top level: %s", item.typ)
}
}
// value translates an expected value from the lexer into a Go value wrapped
// as an empty interface.
func (p *parser) value(it item) (interface{}, tomlType) {
switch it.typ {
case itemString:
return p.replaceUnicode(replaceEscapes(it.val)), p.typeOfPrimitive(it)
case itemBool:
switch it.val {
case "true":
return true, p.typeOfPrimitive(it)
case "false":
return false, p.typeOfPrimitive(it)
}
p.bug("Expected boolean value, but got '%s'.", it.val)
case itemInteger:
num, err := strconv.ParseInt(it.val, 10, 64)
if err != nil {
// See comment below for floats describing why we make a
// distinction between a bug and a user error.
if e, ok := err.(*strconv.NumError); ok &&
e.Err == strconv.ErrRange {
p.panicf("Integer '%s' is out of the range of 64-bit "+
"signed integers.", it.val)
} else {
p.bug("Expected integer value, but got '%s'.", it.val)
}
}
return num, p.typeOfPrimitive(it)
case itemFloat:
num, err := strconv.ParseFloat(it.val, 64)
if err != nil {
// Distinguish float values. Normally, it'd be a bug if the lexer
// provides an invalid float, but it's possible that the float is
// out of range of valid values (which the lexer cannot determine).
// So mark the former as a bug but the latter as a legitimate user
// error.
//
// This is also true for integers.
if e, ok := err.(*strconv.NumError); ok &&
e.Err == strconv.ErrRange {
p.panicf("Float '%s' is out of the range of 64-bit "+
"IEEE-754 floating-point numbers.", it.val)
} else {
p.bug("Expected float value, but got '%s'.", it.val)
}
}
return num, p.typeOfPrimitive(it)
case itemDatetime:
t, err := time.Parse("2006-01-02T15:04:05Z", it.val)
if err != nil {
p.bug("Expected Zulu formatted DateTime, but got '%s'.", it.val)
}
return t, p.typeOfPrimitive(it)
case itemArray:
array := make([]interface{}, 0)
types := make([]tomlType, 0)
for it = p.next(); it.typ != itemArrayEnd; it = p.next() {
if it.typ == itemCommentStart {
p.expect(itemText)
continue
}
val, typ := p.value(it)
array = append(array, val)
types = append(types, typ)
}
return array, p.typeOfArray(types)
}
p.bug("Unexpected value type: %s", it.typ)
panic("unreachable")
}
// establishContext sets the current context of the parser,
// where the context is either a hash or an array of hashes. Which one is
// set depends on the value of the `array` parameter.
//
// Establishing the context also makes sure that the key isn't a duplicate, and
// will create implicit hashes automatically.
func (p *parser) establishContext(key Key, array bool) {
var ok bool
// Always start at the top level and drill down for our context.
hashContext := p.mapping
keyContext := make(Key, 0)
// We only need implicit hashes for key[0:-1]
for _, k := range key[0 : len(key)-1] {
_, ok = hashContext[k]
keyContext = append(keyContext, k)
// No key? Make an implicit hash and move on.
if !ok {
p.addImplicit(keyContext)
hashContext[k] = make(map[string]interface{})
}
// If the hash context is actually an array of tables, then set
// the hash context to the last element in that array.
//
// Otherwise, it better be a table, since this MUST be a key group (by
// virtue of it not being the last element in a key).
switch t := hashContext[k].(type) {
case []map[string]interface{}:
hashContext = t[len(t)-1]
case map[string]interface{}:
hashContext = t
default:
p.panicf("Key '%s' was already created as a hash.", keyContext)
}
}
p.context = keyContext
if array {
// If this is the first element for this array, then allocate a new
// list of tables for it.
k := key[len(key)-1]
if _, ok := hashContext[k]; !ok {
hashContext[k] = make([]map[string]interface{}, 0, 5)
}
// Add a new table. But make sure the key hasn't already been used
// for something else.
if hash, ok := hashContext[k].([]map[string]interface{}); ok {
hashContext[k] = append(hash, make(map[string]interface{}))
} else {
p.panicf("Key '%s' was already created and cannot be used as "+
"an array.", keyContext)
}
} else {
p.setValue(key[len(key)-1], make(map[string]interface{}))
}
p.context = append(p.context, key[len(key)-1])
}
// setValue sets the given key to the given value in the current context.
// It will make sure that the key hasn't already been defined, account for
// implicit key groups.
func (p *parser) setValue(key string, value interface{}) {
var tmpHash interface{}
var ok bool
hash := p.mapping
keyContext := make(Key, 0)
for _, k := range p.context {
keyContext = append(keyContext, k)
if tmpHash, ok = hash[k]; !ok {
p.bug("Context for key '%s' has not been established.", keyContext)
}
switch t := tmpHash.(type) {
case []map[string]interface{}:
// The context is a table of hashes. Pick the most recent table
// defined as the current hash.
hash = t[len(t)-1]
case map[string]interface{}:
hash = t
default:
p.bug("Expected hash to have type 'map[string]interface{}', but "+
"it has '%T' instead.", tmpHash)
}
}
keyContext = append(keyContext, key)
if _, ok := hash[key]; ok {
// Typically, if the given key has already been set, then we have
// to raise an error since duplicate keys are disallowed. However,
// it's possible that a key was previously defined implicitly. In this
// case, it is allowed to be redefined concretely. (See the
// `tests/valid/implicit-and-explicit-after.toml` test in `toml-test`.)
//
// But we have to make sure to stop marking it as an implicit. (So that
// another redefinition provokes an error.)
//
// Note that since it has already been defined (as a hash), we don't
// want to overwrite it. So our business is done.
if p.isImplicit(keyContext) {
p.removeImplicit(keyContext)
return
}
// Otherwise, we have a concrete key trying to override a previous
// key, which is *always* wrong.
p.panicf("Key '%s' has already been defined.", keyContext)
}
hash[key] = value
}
// setType sets the type of a particular value at a given key.
// It should be called immediately AFTER setValue.
//
// Note that if `key` is empty, then the type given will be applied to the
// current context (which is either a table or an array of tables).
func (p *parser) setType(key string, typ tomlType) {
keyContext := make(Key, 0, len(p.context)+1)
for _, k := range p.context {
keyContext = append(keyContext, k)
}
if len(key) > 0 { // allow type setting for hashes
keyContext = append(keyContext, key)
}
p.types[keyContext.String()] = typ
}
// addImplicit sets the given Key as having been created implicitly.
func (p *parser) addImplicit(key Key) {
p.implicits[key.String()] = true
}
// removeImplicit stops tagging the given key as having been implicitly created.
func (p *parser) removeImplicit(key Key) {
p.implicits[key.String()] = false
}
// isImplicit returns true if the key group pointed to by the key was created
// implicitly.
func (p *parser) isImplicit(key Key) bool {
return p.implicits[key.String()]
}
// current returns the full key name of the current context.
func (p *parser) current() string {
if len(p.currentKey) == 0 {
return p.context.String()
}
if len(p.context) == 0 {
return p.currentKey
}
return fmt.Sprintf("%s.%s", p.context, p.currentKey)
}
func replaceEscapes(s string) string {
return strings.NewReplacer(
"\\b", "\u0008",
"\\t", "\u0009",
"\\n", "\u000A",
"\\f", "\u000C",
"\\r", "\u000D",
"\\\"", "\u0022",
"\\/", "\u002F",
"\\\\", "\u005C",
).Replace(s)
}
func (p *parser) replaceUnicode(s string) string {
indexEsc := func() int {
return strings.Index(s, "\\u")
}
for i := indexEsc(); i != -1; i = indexEsc() {
asciiBytes := s[i+2 : i+6]
s = strings.Replace(s, s[i:i+6], p.asciiEscapeToUnicode(asciiBytes), -1)
}
return s
}
func (p *parser) asciiEscapeToUnicode(s string) string {
hex, err := strconv.ParseUint(strings.ToLower(s), 16, 32)
if err != nil {
p.bug("Could not parse '%s' as a hexadecimal number, but the "+
"lexer claims it's OK: %s", s, err)
}
// BUG(burntsushi)
// I honestly don't understand how this works. I can't seem
// to find a way to make this fail. I figured this would fail on invalid
// UTF-8 characters like U+DCFF, but it doesn't.
r := string(rune(hex))
if !utf8.ValidString(r) {
p.panicf("Escaped character '\\u%s' is not valid UTF-8.", s)
}
return string(r)
}

73
vendor/github.com/BurntSushi/toml/parse_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,73 @@
package toml
import (
"strings"
"testing"
)
var testParseSmall = `
# This is a TOML document. Boom.
wat = "chipper"
[owner.andrew.gallant]
hmm = "hi"
[owner] # Whoa there.
andreW = "gallant # poopy" # weeeee
predicate = false
num = -5192
f = -0.5192
zulu = 1979-05-27T07:32:00Z
whoop = "poop"
tests = [ [1, 2, 3], ["abc", "xyz"] ]
arrs = [ # hmm
# more comments are awesome.
1987-07-05T05:45:00Z,
# say wat?
1987-07-05T05:45:00Z,
1987-07-05T05:45:00Z,
# sweetness
] # more comments
# hehe
`
var testParseSmall2 = `
[a]
better = 43
[a.b.c]
answer = 42
`
func TestParse(t *testing.T) {
m, err := parse(testParseSmall)
if err != nil {
t.Fatal(err)
}
printMap(m.mapping, 0)
}
func printMap(m map[string]interface{}, depth int) {
for k, v := range m {
testf("%s%s\n", strings.Repeat(" ", depth), k)
switch subm := v.(type) {
case map[string]interface{}:
printMap(subm, depth+1)
default:
testf("%s%v\n", strings.Repeat(" ", depth+1), v)
}
}
}
var testParseSmall3 = `
foo = [1, 2,3]
`
func TestParseSmall3(t *testing.T) {
m, err := parse(testParseSmall3)
if err != nil {
t.Fatal(err)
}
printMap(m.mapping, 0)
}

1
vendor/github.com/BurntSushi/toml/session.vim сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1 @@
au BufWritePost *.go silent!make tags > /dev/null 2>&1

14
vendor/github.com/BurntSushi/toml/toml-test-encoder/COPYING сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,14 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

14
vendor/github.com/BurntSushi/toml/toml-test-encoder/README.md сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,14 @@
# Implements the TOML test suite interface for TOML encoders
This is an implementation of the interface expected by
[toml-test](https://github.com/BurntSushi/toml-test) for the
[TOML encoder](https://github.com/BurntSushi/toml).
In particular, it maps JSON data on `stdin` to a TOML format on `stdout`.
Compatible with TOML version
[v0.2.0](https://github.com/mojombo/toml/blob/master/versions/toml-v0.2.0.md)
Compatible with `toml-test` version
[v0.2.0](https://github.com/BurntSushi/toml-test/tree/v0.2.0)

129
vendor/github.com/BurntSushi/toml/toml-test-encoder/main.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,129 @@
package main
import (
"encoding/json"
"flag"
"log"
"os"
"path"
"strconv"
"time"
"github.com/BurntSushi/toml"
)
func init() {
log.SetFlags(0)
flag.Usage = usage
flag.Parse()
}
func usage() {
log.Printf("Usage: %s < json-file\n", path.Base(os.Args[0]))
flag.PrintDefaults()
os.Exit(1)
}
func main() {
if flag.NArg() != 0 {
flag.Usage()
}
var tmp interface{}
if err := json.NewDecoder(os.Stdin).Decode(&tmp); err != nil {
log.Fatalf("Error decoding JSON: %s", err)
}
tomlData := translate(tmp)
if err := toml.NewEncoder(os.Stdout).Encode(tomlData); err != nil {
log.Fatalf("Error encoding TOML: %s", err)
}
}
func translate(typedJson interface{}) interface{} {
switch v := typedJson.(type) {
case map[string]interface{}:
if len(v) == 2 && in("type", v) && in("value", v) {
return untag(v)
}
m := make(map[string]interface{}, len(v))
for k, v2 := range v {
m[k] = translate(v2)
}
return m
case []interface{}:
tabArray := make([]map[string]interface{}, len(v))
for i := range v {
if m, ok := translate(v[i]).(map[string]interface{}); ok {
tabArray[i] = m
} else {
log.Fatalf("JSON arrays may only contain objects. This " +
"corresponds to only tables being allowed in " +
"TOML table arrays.")
}
}
return tabArray
}
log.Fatalf("Unrecognized JSON format '%T'.", typedJson)
panic("unreachable")
}
func untag(typed map[string]interface{}) interface{} {
t := typed["type"].(string)
v := typed["value"]
switch t {
case "string":
return v.(string)
case "integer":
v := v.(string)
n, err := strconv.Atoi(v)
if err != nil {
log.Fatalf("Could not parse '%s' as integer: %s", v, err)
}
return n
case "float":
v := v.(string)
f, err := strconv.ParseFloat(v, 64)
if err != nil {
log.Fatalf("Could not parse '%s' as float64: %s", v, err)
}
return f
case "datetime":
v := v.(string)
t, err := time.Parse("2006-01-02T15:04:05Z", v)
if err != nil {
log.Fatalf("Could not parse '%s' as a datetime: %s", v, err)
}
return t
case "bool":
v := v.(string)
switch v {
case "true":
return true
case "false":
return false
}
log.Fatalf("Could not parse '%s' as a boolean.", v)
case "array":
v := v.([]interface{})
array := make([]interface{}, len(v))
for i := range v {
if m, ok := v[i].(map[string]interface{}); ok {
array[i] = untag(m)
} else {
log.Fatalf("Arrays may only contain other arrays or "+
"primitive values, but found a '%T'.", m)
}
}
return array
}
log.Fatalf("Unrecognized tag type '%s'.", t)
panic("unreachable")
}
func in(key string, m map[string]interface{}) bool {
_, ok := m[key]
return ok
}

14
vendor/github.com/BurntSushi/toml/toml-test-go/COPYING сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,14 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

14
vendor/github.com/BurntSushi/toml/toml-test-go/README.md сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,14 @@
# Implements the TOML test suite interface
This is an implementation of the interface expected by
[toml-test](https://github.com/BurntSushi/toml-test) for my
[toml parser written in Go](https://github.com/BurntSushi/toml).
In particular, it maps TOML data on `stdin` to a JSON format on `stdout`.
Compatible with TOML version
[v0.2.0](https://github.com/mojombo/toml/blob/master/versions/toml-v0.2.0.md)
Compatible with `toml-test` version
[v0.2.0](https://github.com/BurntSushi/toml-test/tree/v0.2.0)

88
vendor/github.com/BurntSushi/toml/toml-test-go/main.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,88 @@
package main
import (
"encoding/json"
"flag"
"fmt"
"log"
"os"
"path"
"time"
"github.com/BurntSushi/toml"
)
func init() {
log.SetFlags(0)
flag.Usage = usage
flag.Parse()
}
func usage() {
log.Printf("Usage: %s < toml-file\n", path.Base(os.Args[0]))
flag.PrintDefaults()
os.Exit(1)
}
func main() {
if flag.NArg() != 0 {
flag.Usage()
}
var tmp interface{}
if _, err := toml.DecodeReader(os.Stdin, &tmp); err != nil {
log.Fatalf("Error decoding TOML: %s", err)
}
typedTmp := translate(tmp)
if err := json.NewEncoder(os.Stdout).Encode(typedTmp); err != nil {
log.Fatalf("Error encoding JSON: %s", err)
}
}
func translate(tomlData interface{}) interface{} {
switch orig := tomlData.(type) {
case map[string]interface{}:
typed := make(map[string]interface{}, len(orig))
for k, v := range orig {
typed[k] = translate(v)
}
return typed
case []map[string]interface{}:
typed := make([]map[string]interface{}, len(orig))
for i, v := range orig {
typed[i] = translate(v).(map[string]interface{})
}
return typed
case []interface{}:
typed := make([]interface{}, len(orig))
for i, v := range orig {
typed[i] = translate(v)
}
// We don't really need to tag arrays, but let's be future proof.
// (If TOML ever supports tuples, we'll need this.)
return tag("array", typed)
case time.Time:
return tag("datetime", orig.Format("2006-01-02T15:04:05Z"))
case bool:
return tag("bool", fmt.Sprintf("%v", orig))
case int64:
return tag("integer", fmt.Sprintf("%d", orig))
case float64:
return tag("float", fmt.Sprintf("%v", orig))
case string:
return tag("string", orig)
}
panic(fmt.Sprintf("Unknown type: %T", tomlData))
}
func tag(typeName string, data interface{}) map[string]interface{} {
return map[string]interface{}{
"type": typeName,
"value": data,
}
}

14
vendor/github.com/BurntSushi/toml/tomlv/COPYING сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,14 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

22
vendor/github.com/BurntSushi/toml/tomlv/README.md сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,22 @@
# TOML Validator
If Go is installed, it's simple to try it out:
```bash
go get github.com/BurntSushi/toml/tomlv
tomlv some-toml-file.toml
```
You can see the types of every key in a TOML file with:
```bash
tomlv -types some-toml-file.toml
```
At the moment, only one error message is reported at a time. Error messages
include line numbers. No output means that the files given are valid TOML, or
there is a bug in `tomlv`.
Compatible with TOML version
[v0.1.0](https://github.com/mojombo/toml/blob/master/versions/toml-v0.1.0.md)

60
vendor/github.com/BurntSushi/toml/tomlv/main.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,60 @@
package main
import (
"flag"
"fmt"
"log"
"os"
"path"
"strings"
"text/tabwriter"
"github.com/BurntSushi/toml"
)
var (
flagTypes = false
)
func init() {
log.SetFlags(0)
flag.BoolVar(&flagTypes, "types", flagTypes,
"When set, the types of every defined key will be shown.")
flag.Usage = usage
flag.Parse()
}
func usage() {
log.Printf("Usage: %s toml-file [ toml-file ... ]\n",
path.Base(os.Args[0]))
flag.PrintDefaults()
os.Exit(1)
}
func main() {
if flag.NArg() < 1 {
flag.Usage()
}
for _, f := range flag.Args() {
var tmp interface{}
md, err := toml.DecodeFile(f, &tmp)
if err != nil {
log.Fatalf("Error in '%s': %s", f, err)
}
if flagTypes {
printTypes(md)
}
}
}
func printTypes(md toml.MetaData) {
tabw := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
for _, key := range md.Keys() {
fmt.Fprintf(tabw, "%s%s\t%s\n",
strings.Repeat(" ", len(key)-1), key, md.Type(key...))
}
tabw.Flush()
}

78
vendor/github.com/BurntSushi/toml/type_check.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,78 @@
package toml
// tomlType represents any Go type that corresponds to a TOML type.
// While the first draft of the TOML spec has a simplistic type system that
// probably doesn't need this level of sophistication, we seem to be militating
// toward adding real composite types.
type tomlType interface {
typeString() string
}
// typeEqual accepts any two types and returns true if they are equal.
func typeEqual(t1, t2 tomlType) bool {
return t1.typeString() == t2.typeString()
}
type tomlBaseType string
func (btype tomlBaseType) typeString() string {
return string(btype)
}
func (btype tomlBaseType) String() string {
return btype.typeString()
}
var (
tomlInteger tomlBaseType = "Integer"
tomlFloat tomlBaseType = "Float"
tomlDatetime tomlBaseType = "Datetime"
tomlString tomlBaseType = "String"
tomlBool tomlBaseType = "Bool"
tomlArray tomlBaseType = "Array"
tomlHash tomlBaseType = "Hash"
tomlArrayHash tomlBaseType = "ArrayHash"
)
// typeOfPrimitive returns a tomlType of any primitive value in TOML.
// Primitive values are: Integer, Float, Datetime, String and Bool.
//
// Passing a lexer item other than the following will cause a BUG message
// to occur: itemString, itemBool, itemInteger, itemFloat, itemDatetime.
func (p *parser) typeOfPrimitive(lexItem item) tomlType {
switch lexItem.typ {
case itemInteger:
return tomlInteger
case itemFloat:
return tomlFloat
case itemDatetime:
return tomlDatetime
case itemString:
return tomlString
case itemBool:
return tomlBool
}
p.bug("Cannot infer primitive type of lex item '%s'.", lexItem)
panic("unreachable")
}
// typeOfArray returns a tomlType for an array given a list of types of its
// values.
//
// In the current spec, if an array is homogeneous, then its type is always
// "Array". If the array is not homogeneous, an error is generated.
func (p *parser) typeOfArray(types []tomlType) tomlType {
// Empty arrays are cool.
if len(types) == 0 {
return tomlArray
}
theType := types[0]
for _, t := range types[1:] {
if !typeEqual(theType, t) {
p.panicf("Array contains values of type '%s' and '%s', but arrays "+
"must be homogeneous.", theType, t)
}
}
return tomlArray
}

241
vendor/github.com/BurntSushi/toml/type_fields.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,241 @@
package toml
// Struct field handling is adapted from code in encoding/json:
//
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
import (
"reflect"
"sort"
"sync"
)
// A field represents a single field found in a struct.
type field struct {
name string // the name of the field (`toml` tag included)
tag bool // whether field has a `toml` tag
index []int // represents the depth of an anonymous field
typ reflect.Type // the type of the field
}
// byName sorts field by name, breaking ties with depth,
// then breaking ties with "name came from toml tag", then
// breaking ties with index sequence.
type byName []field
func (x byName) Len() int { return len(x) }
func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x byName) Less(i, j int) bool {
if x[i].name != x[j].name {
return x[i].name < x[j].name
}
if len(x[i].index) != len(x[j].index) {
return len(x[i].index) < len(x[j].index)
}
if x[i].tag != x[j].tag {
return x[i].tag
}
return byIndex(x).Less(i, j)
}
// byIndex sorts field by index sequence.
type byIndex []field
func (x byIndex) Len() int { return len(x) }
func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x byIndex) Less(i, j int) bool {
for k, xik := range x[i].index {
if k >= len(x[j].index) {
return false
}
if xik != x[j].index[k] {
return xik < x[j].index[k]
}
}
return len(x[i].index) < len(x[j].index)
}
// typeFields returns a list of fields that TOML should recognize for the given
// type. The algorithm is breadth-first search over the set of structs to
// include - the top struct and then any reachable anonymous structs.
func typeFields(t reflect.Type) []field {
// Anonymous fields to explore at the current level and the next.
current := []field{}
next := []field{{typ: t}}
// Count of queued names for current level and the next.
count := map[reflect.Type]int{}
nextCount := map[reflect.Type]int{}
// Types already visited at an earlier level.
visited := map[reflect.Type]bool{}
// Fields found.
var fields []field
for len(next) > 0 {
current, next = next, current[:0]
count, nextCount = nextCount, map[reflect.Type]int{}
for _, f := range current {
if visited[f.typ] {
continue
}
visited[f.typ] = true
// Scan f.typ for fields to include.
for i := 0; i < f.typ.NumField(); i++ {
sf := f.typ.Field(i)
if sf.PkgPath != "" { // unexported
continue
}
name := sf.Tag.Get("toml")
if name == "-" {
continue
}
index := make([]int, len(f.index)+1)
copy(index, f.index)
index[len(f.index)] = i
ft := sf.Type
if ft.Name() == "" && ft.Kind() == reflect.Ptr {
// Follow pointer.
ft = ft.Elem()
}
// Record found field and index sequence.
if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
tagged := name != ""
if name == "" {
name = sf.Name
}
fields = append(fields, field{name, tagged, index, ft})
if count[f.typ] > 1 {
// If there were multiple instances, add a second,
// so that the annihilation code will see a duplicate.
// It only cares about the distinction between 1 or 2,
// so don't bother generating any more copies.
fields = append(fields, fields[len(fields)-1])
}
continue
}
// Record new anonymous struct to explore in next round.
nextCount[ft]++
if nextCount[ft] == 1 {
f := field{name: ft.Name(), index: index, typ: ft}
next = append(next, f)
}
}
}
}
sort.Sort(byName(fields))
// Delete all fields that are hidden by the Go rules for embedded fields,
// except that fields with TOML tags are promoted.
// The fields are sorted in primary order of name, secondary order
// of field index length. Loop over names; for each name, delete
// hidden fields by choosing the one dominant field that survives.
out := fields[:0]
for advance, i := 0, 0; i < len(fields); i += advance {
// One iteration per name.
// Find the sequence of fields with the name of this first field.
fi := fields[i]
name := fi.name
for advance = 1; i+advance < len(fields); advance++ {
fj := fields[i+advance]
if fj.name != name {
break
}
}
if advance == 1 { // Only one field with this name
out = append(out, fi)
continue
}
dominant, ok := dominantField(fields[i : i+advance])
if ok {
out = append(out, dominant)
}
}
fields = out
sort.Sort(byIndex(fields))
return fields
}
// dominantField looks through the fields, all of which are known to
// have the same name, to find the single field that dominates the
// others using Go's embedding rules, modified by the presence of
// TOML tags. If there are multiple top-level fields, the boolean
// will be false: This condition is an error in Go and we skip all
// the fields.
func dominantField(fields []field) (field, bool) {
// The fields are sorted in increasing index-length order. The winner
// must therefore be one with the shortest index length. Drop all
// longer entries, which is easy: just truncate the slice.
length := len(fields[0].index)
tagged := -1 // Index of first tagged field.
for i, f := range fields {
if len(f.index) > length {
fields = fields[:i]
break
}
if f.tag {
if tagged >= 0 {
// Multiple tagged fields at the same level: conflict.
// Return no field.
return field{}, false
}
tagged = i
}
}
if tagged >= 0 {
return fields[tagged], true
}
// All remaining fields have the same length. If there's more than one,
// we have a conflict (two fields named "X" at the same level) and we
// return no field.
if len(fields) > 1 {
return field{}, false
}
return fields[0], true
}
var fieldCache struct {
sync.RWMutex
m map[reflect.Type][]field
}
// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
func cachedTypeFields(t reflect.Type) []field {
fieldCache.RLock()
f := fieldCache.m[t]
fieldCache.RUnlock()
if f != nil {
return f
}
// Compute fields without lock.
// Might duplicate effort but won't hold other computations back.
f = typeFields(t)
if f == nil {
f = []field{}
}
fieldCache.Lock()
if fieldCache.m == nil {
fieldCache.m = map[reflect.Type][]field{}
}
fieldCache.m[t] = f
fieldCache.Unlock()
return f
}

21
vendor/github.com/codegangsta/cli/LICENSE сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,21 @@
Copyright (C) 2013 Jeremy Saenz
All Rights Reserved.
MIT LICENSE
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

315
vendor/github.com/codegangsta/cli/README.md сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,315 @@
[![Coverage](http://gocover.io/_badge/github.com/codegangsta/cli?0)](http://gocover.io/github.com/codegangsta/cli)
[![Build Status](https://travis-ci.org/codegangsta/cli.png?branch=master)](https://travis-ci.org/codegangsta/cli)
[![GoDoc](https://godoc.org/github.com/codegangsta/cli?status.svg)](https://godoc.org/github.com/codegangsta/cli)
# cli.go
`cli.go` is simple, fast, and fun package for building command line apps in Go. The goal is to enable developers to write fast and distributable command line applications in an expressive way.
## Overview
Command line apps are usually so tiny that there is absolutely no reason why your code should *not* be self-documenting. Things like generating help text and parsing command flags/options should not hinder productivity when writing a command line app.
**This is where `cli.go` comes into play.** `cli.go` makes command line programming fun, organized, and expressive!
## Installation
Make sure you have a working Go environment (go 1.1+ is *required*). [See the install instructions](http://golang.org/doc/install.html).
To install `cli.go`, simply run:
```
$ go get github.com/codegangsta/cli
```
Make sure your `PATH` includes to the `$GOPATH/bin` directory so your commands can be easily used:
```
export PATH=$PATH:$GOPATH/bin
```
## Getting Started
One of the philosophies behind `cli.go` is that an API should be playful and full of discovery. So a `cli.go` app can be as little as one line of code in `main()`.
``` go
package main
import (
"os"
"github.com/codegangsta/cli"
)
func main() {
cli.NewApp().Run(os.Args)
}
```
This app will run and show help text, but is not very useful. Let's give an action to execute and some help documentation:
``` go
package main
import (
"os"
"github.com/codegangsta/cli"
)
func main() {
app := cli.NewApp()
app.Name = "boom"
app.Usage = "make an explosive entrance"
app.Action = func(c *cli.Context) {
println("boom! I say!")
}
app.Run(os.Args)
}
```
Running this already gives you a ton of functionality, plus support for things like subcommands and flags, which are covered below.
## Example
Being a programmer can be a lonely job. Thankfully by the power of automation that is not the case! Let's create a greeter app to fend off our demons of loneliness!
Start by creating a directory named `greet`, and within it, add a file, `greet.go` with the following code in it:
``` go
package main
import (
"os"
"github.com/codegangsta/cli"
)
func main() {
app := cli.NewApp()
app.Name = "greet"
app.Usage = "fight the loneliness!"
app.Action = func(c *cli.Context) {
println("Hello friend!")
}
app.Run(os.Args)
}
```
Install our command to the `$GOPATH/bin` directory:
```
$ go install
```
Finally run our new command:
```
$ greet
Hello friend!
```
`cli.go` also generates neat help text:
```
$ greet help
NAME:
greet - fight the loneliness!
USAGE:
greet [global options] command [command options] [arguments...]
VERSION:
0.0.0
COMMANDS:
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS
--version Shows version information
```
### Arguments
You can lookup arguments by calling the `Args` function on `cli.Context`.
``` go
...
app.Action = func(c *cli.Context) {
println("Hello", c.Args()[0])
}
...
```
### Flags
Setting and querying flags is simple.
``` go
...
app.Flags = []cli.Flag {
cli.StringFlag{
Name: "lang",
Value: "english",
Usage: "language for the greeting",
},
}
app.Action = func(c *cli.Context) {
name := "someone"
if len(c.Args()) > 0 {
name = c.Args()[0]
}
if c.String("lang") == "spanish" {
println("Hola", name)
} else {
println("Hello", name)
}
}
...
```
See full list of flags at http://godoc.org/github.com/codegangsta/cli
#### Alternate Names
You can set alternate (or short) names for flags by providing a comma-delimited list for the `Name`. e.g.
``` go
app.Flags = []cli.Flag {
cli.StringFlag{
Name: "lang, l",
Value: "english",
Usage: "language for the greeting",
},
}
```
That flag can then be set with `--lang spanish` or `-l spanish`. Note that giving two different forms of the same flag in the same command invocation is an error.
#### Values from the Environment
You can also have the default value set from the environment via `EnvVar`. e.g.
``` go
app.Flags = []cli.Flag {
cli.StringFlag{
Name: "lang, l",
Value: "english",
Usage: "language for the greeting",
EnvVar: "APP_LANG",
},
}
```
The `EnvVar` may also be given as a comma-delimited "cascade", where the first environment variable that resolves is used as the default.
``` go
app.Flags = []cli.Flag {
cli.StringFlag{
Name: "lang, l",
Value: "english",
Usage: "language for the greeting",
EnvVar: "LEGACY_COMPAT_LANG,APP_LANG,LANG",
},
}
```
### Subcommands
Subcommands can be defined for a more git-like command line app.
```go
...
app.Commands = []cli.Command{
{
Name: "add",
Aliases: []string{"a"},
Usage: "add a task to the list",
Action: func(c *cli.Context) {
println("added task: ", c.Args().First())
},
},
{
Name: "complete",
Aliases: []string{"c"},
Usage: "complete a task on the list",
Action: func(c *cli.Context) {
println("completed task: ", c.Args().First())
},
},
{
Name: "template",
Aliases: []string{"r"},
Usage: "options for task templates",
Subcommands: []cli.Command{
{
Name: "add",
Usage: "add a new template",
Action: func(c *cli.Context) {
println("new task template: ", c.Args().First())
},
},
{
Name: "remove",
Usage: "remove an existing template",
Action: func(c *cli.Context) {
println("removed task template: ", c.Args().First())
},
},
},
},
}
...
```
### Bash Completion
You can enable completion commands by setting the `EnableBashCompletion`
flag on the `App` object. By default, this setting will only auto-complete to
show an app's subcommands, but you can write your own completion methods for
the App or its subcommands.
```go
...
var tasks = []string{"cook", "clean", "laundry", "eat", "sleep", "code"}
app := cli.NewApp()
app.EnableBashCompletion = true
app.Commands = []cli.Command{
{
Name: "complete",
Aliases: []string{"c"},
Usage: "complete a task on the list",
Action: func(c *cli.Context) {
println("completed task: ", c.Args().First())
},
BashComplete: func(c *cli.Context) {
// This will complete if no args are passed
if len(c.Args()) > 0 {
return
}
for _, t := range tasks {
fmt.Println(t)
}
},
}
}
...
```
#### To Enable
Source the `autocomplete/bash_autocomplete` file in your `.bashrc` file while
setting the `PROG` variable to the name of your program:
`PROG=myprogram source /.../cli/autocomplete/bash_autocomplete`
#### To Distribute
Copy `autocomplete/bash_autocomplete` into `/etc/bash_completion.d/` and rename
it to the name of the program you wish to add autocomplete support for (or
automatically install it there if you are distributing a package). Don't forget
to source the file to make it active in the current shell.
```
sudo cp src/bash_autocomplete /etc/bash_completion.d/<myprogram>
source /etc/bash_completion.d/<myprogram>
```
Alternatively, you can just document that users should source the generic
`autocomplete/bash_autocomplete` in their bash configuration with `$PROG` set
to the name of their program (as above).
## Contribution Guidelines
Feel free to put up a pull request to fix a bug or maybe add a feature. I will give it a code review and make sure that it does not break backwards compatibility. If I or any other collaborators agree that it is in line with the vision of the project, we will work with you to get the code into a mergeable state and merge it into the master branch.
If you have contributed something significant to the project, I will most likely add you as a collaborator. As a collaborator you are given the ability to merge others pull requests. It is very important that new code does not break existing code, so be careful about what code you do choose to merge. If you have any questions feel free to link @codegangsta to the issue in question and we can review it together.
If you feel like you have contributed to the project but have not yet been added as a collaborator, I probably forgot to add you. Hit @codegangsta up over email and we will get it figured out.

333
vendor/github.com/codegangsta/cli/app.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,333 @@
package cli
import (
"fmt"
"io"
"io/ioutil"
"os"
"time"
)
// App is the main structure of a cli application. It is recomended that
// an app be created with the cli.NewApp() function
type App struct {
// The name of the program. Defaults to os.Args[0]
Name string
// Full name of command for help, defaults to Name
HelpName string
// Description of the program.
Usage string
// Description of the program argument format.
ArgsUsage string
// Version of the program
Version string
// List of commands to execute
Commands []Command
// List of flags to parse
Flags []Flag
// Boolean to enable bash completion commands
EnableBashCompletion bool
// Boolean to hide built-in help command
HideHelp bool
// Boolean to hide built-in version flag
HideVersion bool
// An action to execute when the bash-completion flag is set
BashComplete func(context *Context)
// An action to execute before any subcommands are run, but after the context is ready
// If a non-nil error is returned, no subcommands are run
Before func(context *Context) error
// An action to execute after any subcommands are run, but after the subcommand has finished
// It is run even if Action() panics
After func(context *Context) error
// The action to execute when no subcommands are specified
Action func(context *Context)
// Execute this function if the proper command cannot be found
CommandNotFound func(context *Context, command string)
// Compilation date
Compiled time.Time
// List of all authors who contributed
Authors []Author
// Copyright of the binary if any
Copyright string
// Name of Author (Note: Use App.Authors, this is deprecated)
Author string
// Email of Author (Note: Use App.Authors, this is deprecated)
Email string
// Writer writer to write output to
Writer io.Writer
}
// Tries to find out when this binary was compiled.
// Returns the current time if it fails to find it.
func compileTime() time.Time {
info, err := os.Stat(os.Args[0])
if err != nil {
return time.Now()
}
return info.ModTime()
}
// Creates a new cli Application with some reasonable defaults for Name, Usage, Version and Action.
func NewApp() *App {
return &App{
Name: os.Args[0],
HelpName: os.Args[0],
Usage: "A new cli application",
Version: "0.0.0",
BashComplete: DefaultAppComplete,
Action: helpCommand.Action,
Compiled: compileTime(),
Writer: os.Stdout,
}
}
// Entry point to the cli app. Parses the arguments slice and routes to the proper flag/args combination
func (a *App) Run(arguments []string) (err error) {
if a.Author != "" || a.Email != "" {
a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email})
}
newCmds := []Command{}
for _, c := range a.Commands {
if c.HelpName == "" {
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
}
newCmds = append(newCmds, c)
}
a.Commands = newCmds
// append help to commands
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
a.Commands = append(a.Commands, helpCommand)
if (HelpFlag != BoolFlag{}) {
a.appendFlag(HelpFlag)
}
}
//append version/help flags
if a.EnableBashCompletion {
a.appendFlag(BashCompletionFlag)
}
if !a.HideVersion {
a.appendFlag(VersionFlag)
}
// parse flags
set := flagSet(a.Name, a.Flags)
set.SetOutput(ioutil.Discard)
err = set.Parse(arguments[1:])
nerr := normalizeFlags(a.Flags, set)
if nerr != nil {
fmt.Fprintln(a.Writer, nerr)
context := NewContext(a, set, nil)
ShowAppHelp(context)
return nerr
}
context := NewContext(a, set, nil)
if err != nil {
fmt.Fprintln(a.Writer, "Incorrect Usage.")
fmt.Fprintln(a.Writer)
ShowAppHelp(context)
return err
}
if checkCompletions(context) {
return nil
}
if !a.HideHelp && checkHelp(context) {
ShowAppHelp(context)
return nil
}
if !a.HideVersion && checkVersion(context) {
ShowVersion(context)
return nil
}
if a.After != nil {
defer func() {
afterErr := a.After(context)
if afterErr != nil {
if err != nil {
err = NewMultiError(err, afterErr)
} else {
err = afterErr
}
}
}()
}
if a.Before != nil {
err := a.Before(context)
if err != nil {
return err
}
}
args := context.Args()
if args.Present() {
name := args.First()
c := a.Command(name)
if c != nil {
return c.Run(context)
}
}
// Run default Action
a.Action(context)
return nil
}
// Another entry point to the cli app, takes care of passing arguments and error handling
func (a *App) RunAndExitOnError() {
if err := a.Run(os.Args); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
// Invokes the subcommand given the context, parses ctx.Args() to generate command-specific flags
func (a *App) RunAsSubcommand(ctx *Context) (err error) {
// append help to commands
if len(a.Commands) > 0 {
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
a.Commands = append(a.Commands, helpCommand)
if (HelpFlag != BoolFlag{}) {
a.appendFlag(HelpFlag)
}
}
}
newCmds := []Command{}
for _, c := range a.Commands {
if c.HelpName == "" {
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
}
newCmds = append(newCmds, c)
}
a.Commands = newCmds
// append flags
if a.EnableBashCompletion {
a.appendFlag(BashCompletionFlag)
}
// parse flags
set := flagSet(a.Name, a.Flags)
set.SetOutput(ioutil.Discard)
err = set.Parse(ctx.Args().Tail())
nerr := normalizeFlags(a.Flags, set)
context := NewContext(a, set, ctx)
if nerr != nil {
fmt.Fprintln(a.Writer, nerr)
fmt.Fprintln(a.Writer)
if len(a.Commands) > 0 {
ShowSubcommandHelp(context)
} else {
ShowCommandHelp(ctx, context.Args().First())
}
return nerr
}
if err != nil {
fmt.Fprintln(a.Writer, "Incorrect Usage.")
fmt.Fprintln(a.Writer)
ShowSubcommandHelp(context)
return err
}
if checkCompletions(context) {
return nil
}
if len(a.Commands) > 0 {
if checkSubcommandHelp(context) {
return nil
}
} else {
if checkCommandHelp(ctx, context.Args().First()) {
return nil
}
}
if a.After != nil {
defer func() {
afterErr := a.After(context)
if afterErr != nil {
if err != nil {
err = NewMultiError(err, afterErr)
} else {
err = afterErr
}
}
}()
}
if a.Before != nil {
err := a.Before(context)
if err != nil {
return err
}
}
args := context.Args()
if args.Present() {
name := args.First()
c := a.Command(name)
if c != nil {
return c.Run(context)
}
}
// Run default Action
a.Action(context)
return nil
}
// Returns the named command on App. Returns nil if the command does not exist
func (a *App) Command(name string) *Command {
for _, c := range a.Commands {
if c.HasName(name) {
return &c
}
}
return nil
}
func (a *App) hasFlag(flag Flag) bool {
for _, f := range a.Flags {
if flag == f {
return true
}
}
return false
}
func (a *App) appendFlag(flag Flag) {
if !a.hasFlag(flag) {
a.Flags = append(a.Flags, flag)
}
}
// Author represents someone who has contributed to a cli project.
type Author struct {
Name string // The Authors name
Email string // The Authors email
}
// String makes Author comply to the Stringer interface, to allow an easy print in the templating process
func (a Author) String() string {
e := ""
if a.Email != "" {
e = "<" + a.Email + "> "
}
return fmt.Sprintf("%v %v", a.Name, e)
}

960
vendor/github.com/codegangsta/cli/app_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,960 @@
package cli
import (
"bytes"
"flag"
"fmt"
"io"
"os"
"strings"
"testing"
)
func ExampleApp() {
// set args for examples sake
os.Args = []string{"greet", "--name", "Jeremy"}
app := NewApp()
app.Name = "greet"
app.Flags = []Flag{
StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
}
app.Action = func(c *Context) {
fmt.Printf("Hello %v\n", c.String("name"))
}
app.Author = "Harrison"
app.Email = "harrison@lolwut.com"
app.Authors = []Author{Author{Name: "Oliver Allen", Email: "oliver@toyshop.com"}}
app.Run(os.Args)
// Output:
// Hello Jeremy
}
func ExampleAppSubcommand() {
// set args for examples sake
os.Args = []string{"say", "hi", "english", "--name", "Jeremy"}
app := NewApp()
app.Name = "say"
app.Commands = []Command{
{
Name: "hello",
Aliases: []string{"hi"},
Usage: "use it to see a description",
Description: "This is how we describe hello the function",
Subcommands: []Command{
{
Name: "english",
Aliases: []string{"en"},
Usage: "sends a greeting in english",
Description: "greets someone in english",
Flags: []Flag{
StringFlag{
Name: "name",
Value: "Bob",
Usage: "Name of the person to greet",
},
},
Action: func(c *Context) {
fmt.Println("Hello,", c.String("name"))
},
},
},
},
}
app.Run(os.Args)
// Output:
// Hello, Jeremy
}
func ExampleAppHelp() {
// set args for examples sake
os.Args = []string{"greet", "h", "describeit"}
app := NewApp()
app.Name = "greet"
app.Flags = []Flag{
StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
}
app.Commands = []Command{
{
Name: "describeit",
Aliases: []string{"d"},
Usage: "use it to see a description",
Description: "This is how we describe describeit the function",
Action: func(c *Context) {
fmt.Printf("i like to describe things")
},
},
}
app.Run(os.Args)
// Output:
// NAME:
// greet describeit - use it to see a description
//
// USAGE:
// greet describeit [arguments...]
//
// DESCRIPTION:
// This is how we describe describeit the function
}
func ExampleAppBashComplete() {
// set args for examples sake
os.Args = []string{"greet", "--generate-bash-completion"}
app := NewApp()
app.Name = "greet"
app.EnableBashCompletion = true
app.Commands = []Command{
{
Name: "describeit",
Aliases: []string{"d"},
Usage: "use it to see a description",
Description: "This is how we describe describeit the function",
Action: func(c *Context) {
fmt.Printf("i like to describe things")
},
}, {
Name: "next",
Usage: "next example",
Description: "more stuff to see when generating bash completion",
Action: func(c *Context) {
fmt.Printf("the next example")
},
},
}
app.Run(os.Args)
// Output:
// describeit
// d
// next
// help
// h
}
func TestApp_Run(t *testing.T) {
s := ""
app := NewApp()
app.Action = func(c *Context) {
s = s + c.Args().First()
}
err := app.Run([]string{"command", "foo"})
expect(t, err, nil)
err = app.Run([]string{"command", "bar"})
expect(t, err, nil)
expect(t, s, "foobar")
}
var commandAppTests = []struct {
name string
expected bool
}{
{"foobar", true},
{"batbaz", true},
{"b", true},
{"f", true},
{"bat", false},
{"nothing", false},
}
func TestApp_Command(t *testing.T) {
app := NewApp()
fooCommand := Command{Name: "foobar", Aliases: []string{"f"}}
batCommand := Command{Name: "batbaz", Aliases: []string{"b"}}
app.Commands = []Command{
fooCommand,
batCommand,
}
for _, test := range commandAppTests {
expect(t, app.Command(test.name) != nil, test.expected)
}
}
func TestApp_CommandWithArgBeforeFlags(t *testing.T) {
var parsedOption, firstArg string
app := NewApp()
command := Command{
Name: "cmd",
Flags: []Flag{
StringFlag{Name: "option", Value: "", Usage: "some option"},
},
Action: func(c *Context) {
parsedOption = c.String("option")
firstArg = c.Args().First()
},
}
app.Commands = []Command{command}
app.Run([]string{"", "cmd", "my-arg", "--option", "my-option"})
expect(t, parsedOption, "my-option")
expect(t, firstArg, "my-arg")
}
func TestApp_RunAsSubcommandParseFlags(t *testing.T) {
var context *Context
a := NewApp()
a.Commands = []Command{
{
Name: "foo",
Action: func(c *Context) {
context = c
},
Flags: []Flag{
StringFlag{
Name: "lang",
Value: "english",
Usage: "language for the greeting",
},
},
Before: func(_ *Context) error { return nil },
},
}
a.Run([]string{"", "foo", "--lang", "spanish", "abcd"})
expect(t, context.Args().Get(0), "abcd")
expect(t, context.String("lang"), "spanish")
}
func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) {
var parsedOption string
var args []string
app := NewApp()
command := Command{
Name: "cmd",
Flags: []Flag{
StringFlag{Name: "option", Value: "", Usage: "some option"},
},
Action: func(c *Context) {
parsedOption = c.String("option")
args = c.Args()
},
}
app.Commands = []Command{command}
app.Run([]string{"", "cmd", "my-arg", "--option", "my-option", "--", "--notARealFlag"})
expect(t, parsedOption, "my-option")
expect(t, args[0], "my-arg")
expect(t, args[1], "--")
expect(t, args[2], "--notARealFlag")
}
func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) {
var args []string
app := NewApp()
command := Command{
Name: "cmd",
Action: func(c *Context) {
args = c.Args()
},
}
app.Commands = []Command{command}
app.Run([]string{"", "cmd", "my-arg", "--", "notAFlagAtAll"})
expect(t, args[0], "my-arg")
expect(t, args[1], "--")
expect(t, args[2], "notAFlagAtAll")
}
func TestApp_Float64Flag(t *testing.T) {
var meters float64
app := NewApp()
app.Flags = []Flag{
Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"},
}
app.Action = func(c *Context) {
meters = c.Float64("height")
}
app.Run([]string{"", "--height", "1.93"})
expect(t, meters, 1.93)
}
func TestApp_ParseSliceFlags(t *testing.T) {
var parsedOption, firstArg string
var parsedIntSlice []int
var parsedStringSlice []string
app := NewApp()
command := Command{
Name: "cmd",
Flags: []Flag{
IntSliceFlag{Name: "p", Value: &IntSlice{}, Usage: "set one or more ip addr"},
StringSliceFlag{Name: "ip", Value: &StringSlice{}, Usage: "set one or more ports to open"},
},
Action: func(c *Context) {
parsedIntSlice = c.IntSlice("p")
parsedStringSlice = c.StringSlice("ip")
parsedOption = c.String("option")
firstArg = c.Args().First()
},
}
app.Commands = []Command{command}
app.Run([]string{"", "cmd", "my-arg", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4"})
IntsEquals := func(a, b []int) bool {
if len(a) != len(b) {
return false
}
for i, v := range a {
if v != b[i] {
return false
}
}
return true
}
StrsEquals := func(a, b []string) bool {
if len(a) != len(b) {
return false
}
for i, v := range a {
if v != b[i] {
return false
}
}
return true
}
var expectedIntSlice = []int{22, 80}
var expectedStringSlice = []string{"8.8.8.8", "8.8.4.4"}
if !IntsEquals(parsedIntSlice, expectedIntSlice) {
t.Errorf("%v does not match %v", parsedIntSlice, expectedIntSlice)
}
if !StrsEquals(parsedStringSlice, expectedStringSlice) {
t.Errorf("%v does not match %v", parsedStringSlice, expectedStringSlice)
}
}
func TestApp_ParseSliceFlagsWithMissingValue(t *testing.T) {
var parsedIntSlice []int
var parsedStringSlice []string
app := NewApp()
command := Command{
Name: "cmd",
Flags: []Flag{
IntSliceFlag{Name: "a", Usage: "set numbers"},
StringSliceFlag{Name: "str", Usage: "set strings"},
},
Action: func(c *Context) {
parsedIntSlice = c.IntSlice("a")
parsedStringSlice = c.StringSlice("str")
},
}
app.Commands = []Command{command}
app.Run([]string{"", "cmd", "my-arg", "-a", "2", "-str", "A"})
var expectedIntSlice = []int{2}
var expectedStringSlice = []string{"A"}
if parsedIntSlice[0] != expectedIntSlice[0] {
t.Errorf("%v does not match %v", parsedIntSlice[0], expectedIntSlice[0])
}
if parsedStringSlice[0] != expectedStringSlice[0] {
t.Errorf("%v does not match %v", parsedIntSlice[0], expectedIntSlice[0])
}
}
func TestApp_DefaultStdout(t *testing.T) {
app := NewApp()
if app.Writer != os.Stdout {
t.Error("Default output writer not set.")
}
}
type mockWriter struct {
written []byte
}
func (fw *mockWriter) Write(p []byte) (n int, err error) {
if fw.written == nil {
fw.written = p
} else {
fw.written = append(fw.written, p...)
}
return len(p), nil
}
func (fw *mockWriter) GetWritten() (b []byte) {
return fw.written
}
func TestApp_SetStdout(t *testing.T) {
w := &mockWriter{}
app := NewApp()
app.Name = "test"
app.Writer = w
err := app.Run([]string{"help"})
if err != nil {
t.Fatalf("Run error: %s", err)
}
if len(w.written) == 0 {
t.Error("App did not write output to desired writer.")
}
}
func TestApp_BeforeFunc(t *testing.T) {
beforeRun, subcommandRun := false, false
beforeError := fmt.Errorf("fail")
var err error
app := NewApp()
app.Before = func(c *Context) error {
beforeRun = true
s := c.String("opt")
if s == "fail" {
return beforeError
}
return nil
}
app.Commands = []Command{
Command{
Name: "sub",
Action: func(c *Context) {
subcommandRun = true
},
},
}
app.Flags = []Flag{
StringFlag{Name: "opt"},
}
// run with the Before() func succeeding
err = app.Run([]string{"command", "--opt", "succeed", "sub"})
if err != nil {
t.Fatalf("Run error: %s", err)
}
if beforeRun == false {
t.Errorf("Before() not executed when expected")
}
if subcommandRun == false {
t.Errorf("Subcommand not executed when expected")
}
// reset
beforeRun, subcommandRun = false, false
// run with the Before() func failing
err = app.Run([]string{"command", "--opt", "fail", "sub"})
// should be the same error produced by the Before func
if err != beforeError {
t.Errorf("Run error expected, but not received")
}
if beforeRun == false {
t.Errorf("Before() not executed when expected")
}
if subcommandRun == true {
t.Errorf("Subcommand executed when NOT expected")
}
}
func TestApp_AfterFunc(t *testing.T) {
afterRun, subcommandRun := false, false
afterError := fmt.Errorf("fail")
var err error
app := NewApp()
app.After = func(c *Context) error {
afterRun = true
s := c.String("opt")
if s == "fail" {
return afterError
}
return nil
}
app.Commands = []Command{
Command{
Name: "sub",
Action: func(c *Context) {
subcommandRun = true
},
},
}
app.Flags = []Flag{
StringFlag{Name: "opt"},
}
// run with the After() func succeeding
err = app.Run([]string{"command", "--opt", "succeed", "sub"})
if err != nil {
t.Fatalf("Run error: %s", err)
}
if afterRun == false {
t.Errorf("After() not executed when expected")
}
if subcommandRun == false {
t.Errorf("Subcommand not executed when expected")
}
// reset
afterRun, subcommandRun = false, false
// run with the Before() func failing
err = app.Run([]string{"command", "--opt", "fail", "sub"})
// should be the same error produced by the Before func
if err != afterError {
t.Errorf("Run error expected, but not received")
}
if afterRun == false {
t.Errorf("After() not executed when expected")
}
if subcommandRun == false {
t.Errorf("Subcommand not executed when expected")
}
}
func TestAppNoHelpFlag(t *testing.T) {
oldFlag := HelpFlag
defer func() {
HelpFlag = oldFlag
}()
HelpFlag = BoolFlag{}
app := NewApp()
err := app.Run([]string{"test", "-h"})
if err != flag.ErrHelp {
t.Errorf("expected error about missing help flag, but got: %s (%T)", err, err)
}
}
func TestAppHelpPrinter(t *testing.T) {
oldPrinter := HelpPrinter
defer func() {
HelpPrinter = oldPrinter
}()
var wasCalled = false
HelpPrinter = func(w io.Writer, template string, data interface{}) {
wasCalled = true
}
app := NewApp()
app.Run([]string{"-h"})
if wasCalled == false {
t.Errorf("Help printer expected to be called, but was not")
}
}
func TestAppVersionPrinter(t *testing.T) {
oldPrinter := VersionPrinter
defer func() {
VersionPrinter = oldPrinter
}()
var wasCalled = false
VersionPrinter = func(c *Context) {
wasCalled = true
}
app := NewApp()
ctx := NewContext(app, nil, nil)
ShowVersion(ctx)
if wasCalled == false {
t.Errorf("Version printer expected to be called, but was not")
}
}
func TestAppCommandNotFound(t *testing.T) {
beforeRun, subcommandRun := false, false
app := NewApp()
app.CommandNotFound = func(c *Context, command string) {
beforeRun = true
}
app.Commands = []Command{
Command{
Name: "bar",
Action: func(c *Context) {
subcommandRun = true
},
},
}
app.Run([]string{"command", "foo"})
expect(t, beforeRun, true)
expect(t, subcommandRun, false)
}
func TestGlobalFlag(t *testing.T) {
var globalFlag string
var globalFlagSet bool
app := NewApp()
app.Flags = []Flag{
StringFlag{Name: "global, g", Usage: "global"},
}
app.Action = func(c *Context) {
globalFlag = c.GlobalString("global")
globalFlagSet = c.GlobalIsSet("global")
}
app.Run([]string{"command", "-g", "foo"})
expect(t, globalFlag, "foo")
expect(t, globalFlagSet, true)
}
func TestGlobalFlagsInSubcommands(t *testing.T) {
subcommandRun := false
parentFlag := false
app := NewApp()
app.Flags = []Flag{
BoolFlag{Name: "debug, d", Usage: "Enable debugging"},
}
app.Commands = []Command{
Command{
Name: "foo",
Flags: []Flag{
BoolFlag{Name: "parent, p", Usage: "Parent flag"},
},
Subcommands: []Command{
{
Name: "bar",
Action: func(c *Context) {
if c.GlobalBool("debug") {
subcommandRun = true
}
if c.GlobalBool("parent") {
parentFlag = true
}
},
},
},
},
}
app.Run([]string{"command", "-d", "foo", "-p", "bar"})
expect(t, subcommandRun, true)
expect(t, parentFlag, true)
}
func TestApp_Run_CommandWithSubcommandHasHelpTopic(t *testing.T) {
var subcommandHelpTopics = [][]string{
{"command", "foo", "--help"},
{"command", "foo", "-h"},
{"command", "foo", "help"},
}
for _, flagSet := range subcommandHelpTopics {
t.Logf("==> checking with flags %v", flagSet)
app := NewApp()
buf := new(bytes.Buffer)
app.Writer = buf
subCmdBar := Command{
Name: "bar",
Usage: "does bar things",
}
subCmdBaz := Command{
Name: "baz",
Usage: "does baz things",
}
cmd := Command{
Name: "foo",
Description: "descriptive wall of text about how it does foo things",
Subcommands: []Command{subCmdBar, subCmdBaz},
}
app.Commands = []Command{cmd}
err := app.Run(flagSet)
if err != nil {
t.Error(err)
}
output := buf.String()
t.Logf("output: %q\n", buf.Bytes())
if strings.Contains(output, "No help topic for") {
t.Errorf("expect a help topic, got none: \n%q", output)
}
for _, shouldContain := range []string{
cmd.Name, cmd.Description,
subCmdBar.Name, subCmdBar.Usage,
subCmdBaz.Name, subCmdBaz.Usage,
} {
if !strings.Contains(output, shouldContain) {
t.Errorf("want help to contain %q, did not: \n%q", shouldContain, output)
}
}
}
}
func TestApp_Run_SubcommandFullPath(t *testing.T) {
app := NewApp()
buf := new(bytes.Buffer)
app.Writer = buf
app.Name = "command"
subCmd := Command{
Name: "bar",
Usage: "does bar things",
}
cmd := Command{
Name: "foo",
Description: "foo commands",
Subcommands: []Command{subCmd},
}
app.Commands = []Command{cmd}
err := app.Run([]string{"command", "foo", "bar", "--help"})
if err != nil {
t.Error(err)
}
output := buf.String()
if !strings.Contains(output, "command foo bar - does bar things") {
t.Errorf("expected full path to subcommand: %s", output)
}
if !strings.Contains(output, "command foo bar [arguments...]") {
t.Errorf("expected full path to subcommand: %s", output)
}
}
func TestApp_Run_SubcommandHelpName(t *testing.T) {
app := NewApp()
buf := new(bytes.Buffer)
app.Writer = buf
app.Name = "command"
subCmd := Command{
Name: "bar",
HelpName: "custom",
Usage: "does bar things",
}
cmd := Command{
Name: "foo",
Description: "foo commands",
Subcommands: []Command{subCmd},
}
app.Commands = []Command{cmd}
err := app.Run([]string{"command", "foo", "bar", "--help"})
if err != nil {
t.Error(err)
}
output := buf.String()
if !strings.Contains(output, "custom - does bar things") {
t.Errorf("expected HelpName for subcommand: %s", output)
}
if !strings.Contains(output, "custom [arguments...]") {
t.Errorf("expected HelpName to subcommand: %s", output)
}
}
func TestApp_Run_CommandHelpName(t *testing.T) {
app := NewApp()
buf := new(bytes.Buffer)
app.Writer = buf
app.Name = "command"
subCmd := Command{
Name: "bar",
Usage: "does bar things",
}
cmd := Command{
Name: "foo",
HelpName: "custom",
Description: "foo commands",
Subcommands: []Command{subCmd},
}
app.Commands = []Command{cmd}
err := app.Run([]string{"command", "foo", "bar", "--help"})
if err != nil {
t.Error(err)
}
output := buf.String()
if !strings.Contains(output, "command foo bar - does bar things") {
t.Errorf("expected full path to subcommand: %s", output)
}
if !strings.Contains(output, "command foo bar [arguments...]") {
t.Errorf("expected full path to subcommand: %s", output)
}
}
func TestApp_Run_CommandSubcommandHelpName(t *testing.T) {
app := NewApp()
buf := new(bytes.Buffer)
app.Writer = buf
app.Name = "base"
subCmd := Command{
Name: "bar",
HelpName: "custom",
Usage: "does bar things",
}
cmd := Command{
Name: "foo",
Description: "foo commands",
Subcommands: []Command{subCmd},
}
app.Commands = []Command{cmd}
err := app.Run([]string{"command", "foo", "--help"})
if err != nil {
t.Error(err)
}
output := buf.String()
if !strings.Contains(output, "base foo - foo commands") {
t.Errorf("expected full path to subcommand: %s", output)
}
if !strings.Contains(output, "base foo command [command options] [arguments...]") {
t.Errorf("expected full path to subcommand: %s", output)
}
}
func TestApp_Run_Help(t *testing.T) {
var helpArguments = [][]string{{"boom", "--help"}, {"boom", "-h"}, {"boom", "help"}}
for _, args := range helpArguments {
buf := new(bytes.Buffer)
t.Logf("==> checking with arguments %v", args)
app := NewApp()
app.Name = "boom"
app.Usage = "make an explosive entrance"
app.Writer = buf
app.Action = func(c *Context) {
buf.WriteString("boom I say!")
}
err := app.Run(args)
if err != nil {
t.Error(err)
}
output := buf.String()
t.Logf("output: %q\n", buf.Bytes())
if !strings.Contains(output, "boom - make an explosive entrance") {
t.Errorf("want help to contain %q, did not: \n%q", "boom - make an explosive entrance", output)
}
}
}
func TestApp_Run_Version(t *testing.T) {
var versionArguments = [][]string{{"boom", "--version"}, {"boom", "-v"}}
for _, args := range versionArguments {
buf := new(bytes.Buffer)
t.Logf("==> checking with arguments %v", args)
app := NewApp()
app.Name = "boom"
app.Usage = "make an explosive entrance"
app.Version = "0.1.0"
app.Writer = buf
app.Action = func(c *Context) {
buf.WriteString("boom I say!")
}
err := app.Run(args)
if err != nil {
t.Error(err)
}
output := buf.String()
t.Logf("output: %q\n", buf.Bytes())
if !strings.Contains(output, "0.1.0") {
t.Errorf("want version to contain %q, did not: \n%q", "0.1.0", output)
}
}
}
func TestApp_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
app := NewApp()
app.Action = func(c *Context) {}
app.Before = func(c *Context) error { return fmt.Errorf("before error") }
app.After = func(c *Context) error { return fmt.Errorf("after error") }
err := app.Run([]string{"foo"})
if err == nil {
t.Fatalf("expected to recieve error from Run, got none")
}
if !strings.Contains(err.Error(), "before error") {
t.Errorf("expected text of error from Before method, but got none in \"%v\"", err)
}
if !strings.Contains(err.Error(), "after error") {
t.Errorf("expected text of error from After method, but got none in \"%v\"", err)
}
}
func TestApp_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) {
app := NewApp()
app.Commands = []Command{
Command{
Name: "bar",
Before: func(c *Context) error { return fmt.Errorf("before error") },
After: func(c *Context) error { return fmt.Errorf("after error") },
},
}
err := app.Run([]string{"foo", "bar"})
if err == nil {
t.Fatalf("expected to recieve error from Run, got none")
}
if !strings.Contains(err.Error(), "before error") {
t.Errorf("expected text of error from Before method, but got none in \"%v\"", err)
}
if !strings.Contains(err.Error(), "after error") {
t.Errorf("expected text of error from After method, but got none in \"%v\"", err)
}
}

14
vendor/github.com/codegangsta/cli/autocomplete/bash_autocomplete сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,14 @@
#! /bin/bash
: ${PROG:=$(basename ${BASH_SOURCE})}
_cli_bash_autocomplete() {
local cur opts base
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
}
complete -F _cli_bash_autocomplete $PROG

5
vendor/github.com/codegangsta/cli/autocomplete/zsh_autocomplete сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,5 @@
autoload -U compinit && compinit
autoload -U bashcompinit && bashcompinit
script_dir=$(dirname $0)
source ${script_dir}/bash_autocomplete

40
vendor/github.com/codegangsta/cli/cli.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,40 @@
// Package cli provides a minimal framework for creating and organizing command line
// Go applications. cli is designed to be easy to understand and write, the most simple
// cli application can be written as follows:
// func main() {
// cli.NewApp().Run(os.Args)
// }
//
// Of course this application does not do much, so let's make this an actual application:
// func main() {
// app := cli.NewApp()
// app.Name = "greet"
// app.Usage = "say a greeting"
// app.Action = func(c *cli.Context) {
// println("Greetings")
// }
//
// app.Run(os.Args)
// }
package cli
import (
"strings"
)
type MultiError struct {
Errors []error
}
func NewMultiError(err ...error) MultiError {
return MultiError{Errors: err}
}
func (m MultiError) Error() string {
errs := make([]string, len(m.Errors))
for i, err := range m.Errors {
errs[i] = err.Error()
}
return strings.Join(errs, "\n")
}

98
vendor/github.com/codegangsta/cli/cli_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,98 @@
package cli
import (
"os"
)
func Example() {
app := NewApp()
app.Name = "todo"
app.Usage = "task list on the command line"
app.Commands = []Command{
{
Name: "add",
Aliases: []string{"a"},
Usage: "add a task to the list",
Action: func(c *Context) {
println("added task: ", c.Args().First())
},
},
{
Name: "complete",
Aliases: []string{"c"},
Usage: "complete a task on the list",
Action: func(c *Context) {
println("completed task: ", c.Args().First())
},
},
}
app.Run(os.Args)
}
func ExampleSubcommand() {
app := NewApp()
app.Name = "say"
app.Commands = []Command{
{
Name: "hello",
Aliases: []string{"hi"},
Usage: "use it to see a description",
Description: "This is how we describe hello the function",
Subcommands: []Command{
{
Name: "english",
Aliases: []string{"en"},
Usage: "sends a greeting in english",
Description: "greets someone in english",
Flags: []Flag{
StringFlag{
Name: "name",
Value: "Bob",
Usage: "Name of the person to greet",
},
},
Action: func(c *Context) {
println("Hello, ", c.String("name"))
},
}, {
Name: "spanish",
Aliases: []string{"sp"},
Usage: "sends a greeting in spanish",
Flags: []Flag{
StringFlag{
Name: "surname",
Value: "Jones",
Usage: "Surname of the person to greet",
},
},
Action: func(c *Context) {
println("Hola, ", c.String("surname"))
},
}, {
Name: "french",
Aliases: []string{"fr"},
Usage: "sends a greeting in french",
Flags: []Flag{
StringFlag{
Name: "nickname",
Value: "Stevie",
Usage: "Nickname of the person to greet",
},
},
Action: func(c *Context) {
println("Bonjour, ", c.String("nickname"))
},
},
},
}, {
Name: "bye",
Usage: "says goodbye",
Action: func(c *Context) {
println("bye")
},
},
}
app.Run(os.Args)
}

210
vendor/github.com/codegangsta/cli/command.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,210 @@
package cli
import (
"fmt"
"io/ioutil"
"strings"
)
// Command is a subcommand for a cli.App.
type Command struct {
// The name of the command
Name string
// short name of the command. Typically one character (deprecated, use `Aliases`)
ShortName string
// A list of aliases for the command
Aliases []string
// A short description of the usage of this command
Usage string
// A longer explanation of how the command works
Description string
// A short description of the arguments of this command
ArgsUsage string
// The function to call when checking for bash command completions
BashComplete func(context *Context)
// An action to execute before any sub-subcommands are run, but after the context is ready
// If a non-nil error is returned, no sub-subcommands are run
Before func(context *Context) error
// An action to execute after any subcommands are run, but after the subcommand has finished
// It is run even if Action() panics
After func(context *Context) error
// The function to call when this command is invoked
Action func(context *Context)
// List of child commands
Subcommands []Command
// List of flags to parse
Flags []Flag
// Treat all flags as normal arguments if true
SkipFlagParsing bool
// Boolean to hide built-in help command
HideHelp bool
// Full name of command for help, defaults to full command name, including parent commands.
HelpName string
commandNamePath []string
}
// Returns the full name of the command.
// For subcommands this ensures that parent commands are part of the command path
func (c Command) FullName() string {
if c.commandNamePath == nil {
return c.Name
}
return strings.Join(c.commandNamePath, " ")
}
// Invokes the command given the context, parses ctx.Args() to generate command-specific flags
func (c Command) Run(ctx *Context) error {
if len(c.Subcommands) > 0 || c.Before != nil || c.After != nil {
return c.startApp(ctx)
}
if !c.HideHelp && (HelpFlag != BoolFlag{}) {
// append help to flags
c.Flags = append(
c.Flags,
HelpFlag,
)
}
if ctx.App.EnableBashCompletion {
c.Flags = append(c.Flags, BashCompletionFlag)
}
set := flagSet(c.Name, c.Flags)
set.SetOutput(ioutil.Discard)
firstFlagIndex := -1
terminatorIndex := -1
for index, arg := range ctx.Args() {
if arg == "--" {
terminatorIndex = index
break
} else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 {
firstFlagIndex = index
}
}
var err error
if firstFlagIndex > -1 && !c.SkipFlagParsing {
args := ctx.Args()
regularArgs := make([]string, len(args[1:firstFlagIndex]))
copy(regularArgs, args[1:firstFlagIndex])
var flagArgs []string
if terminatorIndex > -1 {
flagArgs = args[firstFlagIndex:terminatorIndex]
regularArgs = append(regularArgs, args[terminatorIndex:]...)
} else {
flagArgs = args[firstFlagIndex:]
}
err = set.Parse(append(flagArgs, regularArgs...))
} else {
err = set.Parse(ctx.Args().Tail())
}
if err != nil {
fmt.Fprintln(ctx.App.Writer, "Incorrect Usage.")
fmt.Fprintln(ctx.App.Writer)
ShowCommandHelp(ctx, c.Name)
return err
}
nerr := normalizeFlags(c.Flags, set)
if nerr != nil {
fmt.Fprintln(ctx.App.Writer, nerr)
fmt.Fprintln(ctx.App.Writer)
ShowCommandHelp(ctx, c.Name)
return nerr
}
context := NewContext(ctx.App, set, ctx)
if checkCommandCompletions(context, c.Name) {
return nil
}
if checkCommandHelp(context, c.Name) {
return nil
}
context.Command = c
c.Action(context)
return nil
}
func (c Command) Names() []string {
names := []string{c.Name}
if c.ShortName != "" {
names = append(names, c.ShortName)
}
return append(names, c.Aliases...)
}
// Returns true if Command.Name or Command.ShortName matches given name
func (c Command) HasName(name string) bool {
for _, n := range c.Names() {
if n == name {
return true
}
}
return false
}
func (c Command) startApp(ctx *Context) error {
app := NewApp()
// set the name and usage
app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
if c.HelpName == "" {
app.HelpName = c.HelpName
} else {
app.HelpName = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
}
if c.Description != "" {
app.Usage = c.Description
} else {
app.Usage = c.Usage
}
// set CommandNotFound
app.CommandNotFound = ctx.App.CommandNotFound
// set the flags and commands
app.Commands = c.Subcommands
app.Flags = c.Flags
app.HideHelp = c.HideHelp
app.Version = ctx.App.Version
app.HideVersion = ctx.App.HideVersion
app.Compiled = ctx.App.Compiled
app.Author = ctx.App.Author
app.Email = ctx.App.Email
app.Writer = ctx.App.Writer
// bash completion
app.EnableBashCompletion = ctx.App.EnableBashCompletion
if c.BashComplete != nil {
app.BashComplete = c.BashComplete
}
// set the actions
app.Before = c.Before
app.After = c.After
if c.Action != nil {
app.Action = c.Action
} else {
app.Action = helpSubcommand.Action
}
var newCmds []Command
for _, cc := range app.Commands {
cc.commandNamePath = []string{c.Name, cc.Name}
newCmds = append(newCmds, cc)
}
app.Commands = newCmds
return app.RunAsSubcommand(ctx)
}

47
vendor/github.com/codegangsta/cli/command_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,47 @@
package cli
import (
"flag"
"testing"
)
func TestCommandDoNotIgnoreFlags(t *testing.T) {
app := NewApp()
set := flag.NewFlagSet("test", 0)
test := []string{"blah", "blah", "-break"}
set.Parse(test)
c := NewContext(app, set, nil)
command := Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(_ *Context) {},
}
err := command.Run(c)
expect(t, err.Error(), "flag provided but not defined: -break")
}
func TestCommandIgnoreFlags(t *testing.T) {
app := NewApp()
set := flag.NewFlagSet("test", 0)
test := []string{"blah", "blah", "-break"}
set.Parse(test)
c := NewContext(app, set, nil)
command := Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(_ *Context) {},
SkipFlagParsing: true,
}
err := command.Run(c)
expect(t, err, nil)
}

388
vendor/github.com/codegangsta/cli/context.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,388 @@
package cli
import (
"errors"
"flag"
"strconv"
"strings"
"time"
)
// Context is a type that is passed through to
// each Handler action in a cli application. Context
// can be used to retrieve context-specific Args and
// parsed command-line options.
type Context struct {
App *App
Command Command
flagSet *flag.FlagSet
setFlags map[string]bool
globalSetFlags map[string]bool
parentContext *Context
}
// Creates a new context. For use in when invoking an App or Command action.
func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context {
return &Context{App: app, flagSet: set, parentContext: parentCtx}
}
// Looks up the value of a local int flag, returns 0 if no int flag exists
func (c *Context) Int(name string) int {
return lookupInt(name, c.flagSet)
}
// Looks up the value of a local time.Duration flag, returns 0 if no time.Duration flag exists
func (c *Context) Duration(name string) time.Duration {
return lookupDuration(name, c.flagSet)
}
// Looks up the value of a local float64 flag, returns 0 if no float64 flag exists
func (c *Context) Float64(name string) float64 {
return lookupFloat64(name, c.flagSet)
}
// Looks up the value of a local bool flag, returns false if no bool flag exists
func (c *Context) Bool(name string) bool {
return lookupBool(name, c.flagSet)
}
// Looks up the value of a local boolT flag, returns false if no bool flag exists
func (c *Context) BoolT(name string) bool {
return lookupBoolT(name, c.flagSet)
}
// Looks up the value of a local string flag, returns "" if no string flag exists
func (c *Context) String(name string) string {
return lookupString(name, c.flagSet)
}
// Looks up the value of a local string slice flag, returns nil if no string slice flag exists
func (c *Context) StringSlice(name string) []string {
return lookupStringSlice(name, c.flagSet)
}
// Looks up the value of a local int slice flag, returns nil if no int slice flag exists
func (c *Context) IntSlice(name string) []int {
return lookupIntSlice(name, c.flagSet)
}
// Looks up the value of a local generic flag, returns nil if no generic flag exists
func (c *Context) Generic(name string) interface{} {
return lookupGeneric(name, c.flagSet)
}
// Looks up the value of a global int flag, returns 0 if no int flag exists
func (c *Context) GlobalInt(name string) int {
if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupInt(name, fs)
}
return 0
}
// Looks up the value of a global time.Duration flag, returns 0 if no time.Duration flag exists
func (c *Context) GlobalDuration(name string) time.Duration {
if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupDuration(name, fs)
}
return 0
}
// Looks up the value of a global bool flag, returns false if no bool flag exists
func (c *Context) GlobalBool(name string) bool {
if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupBool(name, fs)
}
return false
}
// Looks up the value of a global string flag, returns "" if no string flag exists
func (c *Context) GlobalString(name string) string {
if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupString(name, fs)
}
return ""
}
// Looks up the value of a global string slice flag, returns nil if no string slice flag exists
func (c *Context) GlobalStringSlice(name string) []string {
if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupStringSlice(name, fs)
}
return nil
}
// Looks up the value of a global int slice flag, returns nil if no int slice flag exists
func (c *Context) GlobalIntSlice(name string) []int {
if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupIntSlice(name, fs)
}
return nil
}
// Looks up the value of a global generic flag, returns nil if no generic flag exists
func (c *Context) GlobalGeneric(name string) interface{} {
if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupGeneric(name, fs)
}
return nil
}
// Returns the number of flags set
func (c *Context) NumFlags() int {
return c.flagSet.NFlag()
}
// Determines if the flag was actually set
func (c *Context) IsSet(name string) bool {
if c.setFlags == nil {
c.setFlags = make(map[string]bool)
c.flagSet.Visit(func(f *flag.Flag) {
c.setFlags[f.Name] = true
})
}
return c.setFlags[name] == true
}
// Determines if the global flag was actually set
func (c *Context) GlobalIsSet(name string) bool {
if c.globalSetFlags == nil {
c.globalSetFlags = make(map[string]bool)
ctx := c
if ctx.parentContext != nil {
ctx = ctx.parentContext
}
for ; ctx != nil && c.globalSetFlags[name] == false; ctx = ctx.parentContext {
ctx.flagSet.Visit(func(f *flag.Flag) {
c.globalSetFlags[f.Name] = true
})
}
}
return c.globalSetFlags[name]
}
// Returns a slice of flag names used in this context.
func (c *Context) FlagNames() (names []string) {
for _, flag := range c.Command.Flags {
name := strings.Split(flag.getName(), ",")[0]
if name == "help" {
continue
}
names = append(names, name)
}
return
}
// Returns a slice of global flag names used by the app.
func (c *Context) GlobalFlagNames() (names []string) {
for _, flag := range c.App.Flags {
name := strings.Split(flag.getName(), ",")[0]
if name == "help" || name == "version" {
continue
}
names = append(names, name)
}
return
}
// Returns the parent context, if any
func (c *Context) Parent() *Context {
return c.parentContext
}
type Args []string
// Returns the command line arguments associated with the context.
func (c *Context) Args() Args {
args := Args(c.flagSet.Args())
return args
}
// Returns the nth argument, or else a blank string
func (a Args) Get(n int) string {
if len(a) > n {
return a[n]
}
return ""
}
// Returns the first argument, or else a blank string
func (a Args) First() string {
return a.Get(0)
}
// Return the rest of the arguments (not the first one)
// or else an empty string slice
func (a Args) Tail() []string {
if len(a) >= 2 {
return []string(a)[1:]
}
return []string{}
}
// Checks if there are any arguments present
func (a Args) Present() bool {
return len(a) != 0
}
// Swaps arguments at the given indexes
func (a Args) Swap(from, to int) error {
if from >= len(a) || to >= len(a) {
return errors.New("index out of range")
}
a[from], a[to] = a[to], a[from]
return nil
}
func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet {
if ctx.parentContext != nil {
ctx = ctx.parentContext
}
for ; ctx != nil; ctx = ctx.parentContext {
if f := ctx.flagSet.Lookup(name); f != nil {
return ctx.flagSet
}
}
return nil
}
func lookupInt(name string, set *flag.FlagSet) int {
f := set.Lookup(name)
if f != nil {
val, err := strconv.Atoi(f.Value.String())
if err != nil {
return 0
}
return val
}
return 0
}
func lookupDuration(name string, set *flag.FlagSet) time.Duration {
f := set.Lookup(name)
if f != nil {
val, err := time.ParseDuration(f.Value.String())
if err == nil {
return val
}
}
return 0
}
func lookupFloat64(name string, set *flag.FlagSet) float64 {
f := set.Lookup(name)
if f != nil {
val, err := strconv.ParseFloat(f.Value.String(), 64)
if err != nil {
return 0
}
return val
}
return 0
}
func lookupString(name string, set *flag.FlagSet) string {
f := set.Lookup(name)
if f != nil {
return f.Value.String()
}
return ""
}
func lookupStringSlice(name string, set *flag.FlagSet) []string {
f := set.Lookup(name)
if f != nil {
return (f.Value.(*StringSlice)).Value()
}
return nil
}
func lookupIntSlice(name string, set *flag.FlagSet) []int {
f := set.Lookup(name)
if f != nil {
return (f.Value.(*IntSlice)).Value()
}
return nil
}
func lookupGeneric(name string, set *flag.FlagSet) interface{} {
f := set.Lookup(name)
if f != nil {
return f.Value
}
return nil
}
func lookupBool(name string, set *flag.FlagSet) bool {
f := set.Lookup(name)
if f != nil {
val, err := strconv.ParseBool(f.Value.String())
if err != nil {
return false
}
return val
}
return false
}
func lookupBoolT(name string, set *flag.FlagSet) bool {
f := set.Lookup(name)
if f != nil {
val, err := strconv.ParseBool(f.Value.String())
if err != nil {
return true
}
return val
}
return false
}
func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) {
switch ff.Value.(type) {
case *StringSlice:
default:
set.Set(name, ff.Value.String())
}
}
func normalizeFlags(flags []Flag, set *flag.FlagSet) error {
visited := make(map[string]bool)
set.Visit(func(f *flag.Flag) {
visited[f.Name] = true
})
for _, f := range flags {
parts := strings.Split(f.getName(), ",")
if len(parts) == 1 {
continue
}
var ff *flag.Flag
for _, name := range parts {
name = strings.Trim(name, " ")
if visited[name] {
if ff != nil {
return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name)
}
ff = set.Lookup(name)
}
}
if ff == nil {
continue
}
for _, name := range parts {
name = strings.Trim(name, " ")
if !visited[name] {
copyFlag(name, ff, set)
}
}
}
return nil
}

113
vendor/github.com/codegangsta/cli/context_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,113 @@
package cli
import (
"flag"
"testing"
"time"
)
func TestNewContext(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Int("myflag", 12, "doc")
globalSet := flag.NewFlagSet("test", 0)
globalSet.Int("myflag", 42, "doc")
globalCtx := NewContext(nil, globalSet, nil)
command := Command{Name: "mycommand"}
c := NewContext(nil, set, globalCtx)
c.Command = command
expect(t, c.Int("myflag"), 12)
expect(t, c.GlobalInt("myflag"), 42)
expect(t, c.Command.Name, "mycommand")
}
func TestContext_Int(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Int("myflag", 12, "doc")
c := NewContext(nil, set, nil)
expect(t, c.Int("myflag"), 12)
}
func TestContext_Duration(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Duration("myflag", time.Duration(12*time.Second), "doc")
c := NewContext(nil, set, nil)
expect(t, c.Duration("myflag"), time.Duration(12*time.Second))
}
func TestContext_String(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.String("myflag", "hello world", "doc")
c := NewContext(nil, set, nil)
expect(t, c.String("myflag"), "hello world")
}
func TestContext_Bool(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", false, "doc")
c := NewContext(nil, set, nil)
expect(t, c.Bool("myflag"), false)
}
func TestContext_BoolT(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", true, "doc")
c := NewContext(nil, set, nil)
expect(t, c.BoolT("myflag"), true)
}
func TestContext_Args(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", false, "doc")
c := NewContext(nil, set, nil)
set.Parse([]string{"--myflag", "bat", "baz"})
expect(t, len(c.Args()), 2)
expect(t, c.Bool("myflag"), true)
}
func TestContext_IsSet(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", false, "doc")
set.String("otherflag", "hello world", "doc")
globalSet := flag.NewFlagSet("test", 0)
globalSet.Bool("myflagGlobal", true, "doc")
globalCtx := NewContext(nil, globalSet, nil)
c := NewContext(nil, set, globalCtx)
set.Parse([]string{"--myflag", "bat", "baz"})
globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"})
expect(t, c.IsSet("myflag"), true)
expect(t, c.IsSet("otherflag"), false)
expect(t, c.IsSet("bogusflag"), false)
expect(t, c.IsSet("myflagGlobal"), false)
}
func TestContext_GlobalIsSet(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", false, "doc")
set.String("otherflag", "hello world", "doc")
globalSet := flag.NewFlagSet("test", 0)
globalSet.Bool("myflagGlobal", true, "doc")
globalSet.Bool("myflagGlobalUnset", true, "doc")
globalCtx := NewContext(nil, globalSet, nil)
c := NewContext(nil, set, globalCtx)
set.Parse([]string{"--myflag", "bat", "baz"})
globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"})
expect(t, c.GlobalIsSet("myflag"), false)
expect(t, c.GlobalIsSet("otherflag"), false)
expect(t, c.GlobalIsSet("bogusflag"), false)
expect(t, c.GlobalIsSet("myflagGlobal"), true)
expect(t, c.GlobalIsSet("myflagGlobalUnset"), false)
expect(t, c.GlobalIsSet("bogusGlobal"), false)
}
func TestContext_NumFlags(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", false, "doc")
set.String("otherflag", "hello world", "doc")
globalSet := flag.NewFlagSet("test", 0)
globalSet.Bool("myflagGlobal", true, "doc")
globalCtx := NewContext(nil, globalSet, nil)
c := NewContext(nil, set, globalCtx)
set.Parse([]string{"--myflag", "--otherflag=foo"})
globalSet.Parse([]string{"--myflagGlobal"})
expect(t, c.NumFlags(), 2)
}

497
vendor/github.com/codegangsta/cli/flag.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,497 @@
package cli
import (
"flag"
"fmt"
"os"
"strconv"
"strings"
"time"
)
// This flag enables bash-completion for all commands and subcommands
var BashCompletionFlag = BoolFlag{
Name: "generate-bash-completion",
}
// This flag prints the version for the application
var VersionFlag = BoolFlag{
Name: "version, v",
Usage: "print the version",
}
// This flag prints the help for all commands and subcommands
// Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand
// unless HideHelp is set to true)
var HelpFlag = BoolFlag{
Name: "help, h",
Usage: "show help",
}
// Flag is a common interface related to parsing flags in cli.
// For more advanced flag parsing techniques, it is recomended that
// this interface be implemented.
type Flag interface {
fmt.Stringer
// Apply Flag settings to the given flag set
Apply(*flag.FlagSet)
getName() string
}
func flagSet(name string, flags []Flag) *flag.FlagSet {
set := flag.NewFlagSet(name, flag.ContinueOnError)
for _, f := range flags {
f.Apply(set)
}
return set
}
func eachName(longName string, fn func(string)) {
parts := strings.Split(longName, ",")
for _, name := range parts {
name = strings.Trim(name, " ")
fn(name)
}
}
// Generic is a generic parseable type identified by a specific flag
type Generic interface {
Set(value string) error
String() string
}
// GenericFlag is the flag type for types implementing Generic
type GenericFlag struct {
Name string
Value Generic
Usage string
EnvVar string
}
// String returns the string representation of the generic flag to display the
// help text to the user (uses the String() method of the generic flag to show
// the value)
func (f GenericFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s%s \"%v\"\t%v", prefixFor(f.Name), f.Name, f.Value, f.Usage))
}
// Apply takes the flagset and calls Set on the generic flag with the value
// provided by the user for parsing by the flag
func (f GenericFlag) Apply(set *flag.FlagSet) {
val := f.Value
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
val.Set(envVal)
break
}
}
}
eachName(f.Name, func(name string) {
set.Var(f.Value, name, f.Usage)
})
}
func (f GenericFlag) getName() string {
return f.Name
}
// StringSlice is an opaque type for []string to satisfy flag.Value
type StringSlice []string
// Set appends the string value to the list of values
func (f *StringSlice) Set(value string) error {
*f = append(*f, value)
return nil
}
// String returns a readable representation of this value (for usage defaults)
func (f *StringSlice) String() string {
return fmt.Sprintf("%s", *f)
}
// Value returns the slice of strings set by this flag
func (f *StringSlice) Value() []string {
return *f
}
// StringSlice is a string flag that can be specified multiple times on the
// command-line
type StringSliceFlag struct {
Name string
Value *StringSlice
Usage string
EnvVar string
}
// String returns the usage
func (f StringSliceFlag) String() string {
firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
pref := prefixFor(firstName)
return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage))
}
// Apply populates the flag given the flag set and environment
func (f StringSliceFlag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
newVal := &StringSlice{}
for _, s := range strings.Split(envVal, ",") {
s = strings.TrimSpace(s)
newVal.Set(s)
}
f.Value = newVal
break
}
}
}
eachName(f.Name, func(name string) {
if f.Value == nil {
f.Value = &StringSlice{}
}
set.Var(f.Value, name, f.Usage)
})
}
func (f StringSliceFlag) getName() string {
return f.Name
}
// StringSlice is an opaque type for []int to satisfy flag.Value
type IntSlice []int
// Set parses the value into an integer and appends it to the list of values
func (f *IntSlice) Set(value string) error {
tmp, err := strconv.Atoi(value)
if err != nil {
return err
} else {
*f = append(*f, tmp)
}
return nil
}
// String returns a readable representation of this value (for usage defaults)
func (f *IntSlice) String() string {
return fmt.Sprintf("%d", *f)
}
// Value returns the slice of ints set by this flag
func (f *IntSlice) Value() []int {
return *f
}
// IntSliceFlag is an int flag that can be specified multiple times on the
// command-line
type IntSliceFlag struct {
Name string
Value *IntSlice
Usage string
EnvVar string
}
// String returns the usage
func (f IntSliceFlag) String() string {
firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
pref := prefixFor(firstName)
return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage))
}
// Apply populates the flag given the flag set and environment
func (f IntSliceFlag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
newVal := &IntSlice{}
for _, s := range strings.Split(envVal, ",") {
s = strings.TrimSpace(s)
err := newVal.Set(s)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
}
}
f.Value = newVal
break
}
}
}
eachName(f.Name, func(name string) {
if f.Value == nil {
f.Value = &IntSlice{}
}
set.Var(f.Value, name, f.Usage)
})
}
func (f IntSliceFlag) getName() string {
return f.Name
}
// BoolFlag is a switch that defaults to false
type BoolFlag struct {
Name string
Usage string
EnvVar string
}
// String returns a readable representation of this value (for usage defaults)
func (f BoolFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage))
}
// Apply populates the flag given the flag set and environment
func (f BoolFlag) Apply(set *flag.FlagSet) {
val := false
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
envValBool, err := strconv.ParseBool(envVal)
if err == nil {
val = envValBool
}
break
}
}
}
eachName(f.Name, func(name string) {
set.Bool(name, val, f.Usage)
})
}
func (f BoolFlag) getName() string {
return f.Name
}
// BoolTFlag this represents a boolean flag that is true by default, but can
// still be set to false by --some-flag=false
type BoolTFlag struct {
Name string
Usage string
EnvVar string
}
// String returns a readable representation of this value (for usage defaults)
func (f BoolTFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage))
}
// Apply populates the flag given the flag set and environment
func (f BoolTFlag) Apply(set *flag.FlagSet) {
val := true
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
envValBool, err := strconv.ParseBool(envVal)
if err == nil {
val = envValBool
break
}
}
}
}
eachName(f.Name, func(name string) {
set.Bool(name, val, f.Usage)
})
}
func (f BoolTFlag) getName() string {
return f.Name
}
// StringFlag represents a flag that takes as string value
type StringFlag struct {
Name string
Value string
Usage string
EnvVar string
}
// String returns the usage
func (f StringFlag) String() string {
var fmtString string
fmtString = "%s %v\t%v"
if len(f.Value) > 0 {
fmtString = "%s \"%v\"\t%v"
} else {
fmtString = "%s %v\t%v"
}
return withEnvHint(f.EnvVar, fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value, f.Usage))
}
// Apply populates the flag given the flag set and environment
func (f StringFlag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
f.Value = envVal
break
}
}
}
eachName(f.Name, func(name string) {
set.String(name, f.Value, f.Usage)
})
}
func (f StringFlag) getName() string {
return f.Name
}
// IntFlag is a flag that takes an integer
// Errors if the value provided cannot be parsed
type IntFlag struct {
Name string
Value int
Usage string
EnvVar string
}
// String returns the usage
func (f IntFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
}
// Apply populates the flag given the flag set and environment
func (f IntFlag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
envValInt, err := strconv.ParseInt(envVal, 0, 64)
if err == nil {
f.Value = int(envValInt)
break
}
}
}
}
eachName(f.Name, func(name string) {
set.Int(name, f.Value, f.Usage)
})
}
func (f IntFlag) getName() string {
return f.Name
}
// DurationFlag is a flag that takes a duration specified in Go's duration
// format: https://golang.org/pkg/time/#ParseDuration
type DurationFlag struct {
Name string
Value time.Duration
Usage string
EnvVar string
}
// String returns a readable representation of this value (for usage defaults)
func (f DurationFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
}
// Apply populates the flag given the flag set and environment
func (f DurationFlag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
envValDuration, err := time.ParseDuration(envVal)
if err == nil {
f.Value = envValDuration
break
}
}
}
}
eachName(f.Name, func(name string) {
set.Duration(name, f.Value, f.Usage)
})
}
func (f DurationFlag) getName() string {
return f.Name
}
// Float64Flag is a flag that takes an float value
// Errors if the value provided cannot be parsed
type Float64Flag struct {
Name string
Value float64
Usage string
EnvVar string
}
// String returns the usage
func (f Float64Flag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
}
// Apply populates the flag given the flag set and environment
func (f Float64Flag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
envValFloat, err := strconv.ParseFloat(envVal, 10)
if err == nil {
f.Value = float64(envValFloat)
}
}
}
}
eachName(f.Name, func(name string) {
set.Float64(name, f.Value, f.Usage)
})
}
func (f Float64Flag) getName() string {
return f.Name
}
func prefixFor(name string) (prefix string) {
if len(name) == 1 {
prefix = "-"
} else {
prefix = "--"
}
return
}
func prefixedNames(fullName string) (prefixed string) {
parts := strings.Split(fullName, ",")
for i, name := range parts {
name = strings.Trim(name, " ")
prefixed += prefixFor(name) + name
if i < len(parts)-1 {
prefixed += ", "
}
}
return
}
func withEnvHint(envVar, str string) string {
envText := ""
if envVar != "" {
envText = fmt.Sprintf(" [$%s]", strings.Join(strings.Split(envVar, ","), ", $"))
}
return str + envText
}

740
vendor/github.com/codegangsta/cli/flag_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,740 @@
package cli
import (
"fmt"
"os"
"reflect"
"strings"
"testing"
)
var boolFlagTests = []struct {
name string
expected string
}{
{"help", "--help\t"},
{"h", "-h\t"},
}
func TestBoolFlagHelpOutput(t *testing.T) {
for _, test := range boolFlagTests {
flag := BoolFlag{Name: test.name}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
var stringFlagTests = []struct {
name string
value string
expected string
}{
{"help", "", "--help \t"},
{"h", "", "-h \t"},
{"h", "", "-h \t"},
{"test", "Something", "--test \"Something\"\t"},
}
func TestStringFlagHelpOutput(t *testing.T) {
for _, test := range stringFlagTests {
flag := StringFlag{Name: test.name, Value: test.value}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestStringFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_FOO", "derp")
for _, test := range stringFlagTests {
flag := StringFlag{Name: test.name, Value: test.value, EnvVar: "APP_FOO"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_FOO]") {
t.Errorf("%s does not end with [$APP_FOO]", output)
}
}
}
var stringSliceFlagTests = []struct {
name string
value *StringSlice
expected string
}{
{"help", func() *StringSlice {
s := &StringSlice{}
s.Set("")
return s
}(), "--help [--help option --help option]\t"},
{"h", func() *StringSlice {
s := &StringSlice{}
s.Set("")
return s
}(), "-h [-h option -h option]\t"},
{"h", func() *StringSlice {
s := &StringSlice{}
s.Set("")
return s
}(), "-h [-h option -h option]\t"},
{"test", func() *StringSlice {
s := &StringSlice{}
s.Set("Something")
return s
}(), "--test [--test option --test option]\t"},
}
func TestStringSliceFlagHelpOutput(t *testing.T) {
for _, test := range stringSliceFlagTests {
flag := StringSliceFlag{Name: test.name, Value: test.value}
output := flag.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestStringSliceFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_QWWX", "11,4")
for _, test := range stringSliceFlagTests {
flag := StringSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_QWWX"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_QWWX]") {
t.Errorf("%q does not end with [$APP_QWWX]", output)
}
}
}
var intFlagTests = []struct {
name string
expected string
}{
{"help", "--help \"0\"\t"},
{"h", "-h \"0\"\t"},
}
func TestIntFlagHelpOutput(t *testing.T) {
for _, test := range intFlagTests {
flag := IntFlag{Name: test.name}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestIntFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_BAR", "2")
for _, test := range intFlagTests {
flag := IntFlag{Name: test.name, EnvVar: "APP_BAR"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_BAR]") {
t.Errorf("%s does not end with [$APP_BAR]", output)
}
}
}
var durationFlagTests = []struct {
name string
expected string
}{
{"help", "--help \"0\"\t"},
{"h", "-h \"0\"\t"},
}
func TestDurationFlagHelpOutput(t *testing.T) {
for _, test := range durationFlagTests {
flag := DurationFlag{Name: test.name}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestDurationFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_BAR", "2h3m6s")
for _, test := range durationFlagTests {
flag := DurationFlag{Name: test.name, EnvVar: "APP_BAR"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_BAR]") {
t.Errorf("%s does not end with [$APP_BAR]", output)
}
}
}
var intSliceFlagTests = []struct {
name string
value *IntSlice
expected string
}{
{"help", &IntSlice{}, "--help [--help option --help option]\t"},
{"h", &IntSlice{}, "-h [-h option -h option]\t"},
{"h", &IntSlice{}, "-h [-h option -h option]\t"},
{"test", func() *IntSlice {
i := &IntSlice{}
i.Set("9")
return i
}(), "--test [--test option --test option]\t"},
}
func TestIntSliceFlagHelpOutput(t *testing.T) {
for _, test := range intSliceFlagTests {
flag := IntSliceFlag{Name: test.name, Value: test.value}
output := flag.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestIntSliceFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_SMURF", "42,3")
for _, test := range intSliceFlagTests {
flag := IntSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_SMURF"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_SMURF]") {
t.Errorf("%q does not end with [$APP_SMURF]", output)
}
}
}
var float64FlagTests = []struct {
name string
expected string
}{
{"help", "--help \"0\"\t"},
{"h", "-h \"0\"\t"},
}
func TestFloat64FlagHelpOutput(t *testing.T) {
for _, test := range float64FlagTests {
flag := Float64Flag{Name: test.name}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestFloat64FlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_BAZ", "99.4")
for _, test := range float64FlagTests {
flag := Float64Flag{Name: test.name, EnvVar: "APP_BAZ"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_BAZ]") {
t.Errorf("%s does not end with [$APP_BAZ]", output)
}
}
}
var genericFlagTests = []struct {
name string
value Generic
expected string
}{
{"test", &Parser{"abc", "def"}, "--test \"abc,def\"\ttest flag"},
{"t", &Parser{"abc", "def"}, "-t \"abc,def\"\ttest flag"},
}
func TestGenericFlagHelpOutput(t *testing.T) {
for _, test := range genericFlagTests {
flag := GenericFlag{Name: test.name, Value: test.value, Usage: "test flag"}
output := flag.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestGenericFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_ZAP", "3")
for _, test := range genericFlagTests {
flag := GenericFlag{Name: test.name, EnvVar: "APP_ZAP"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_ZAP]") {
t.Errorf("%s does not end with [$APP_ZAP]", output)
}
}
}
func TestParseMultiString(t *testing.T) {
(&App{
Flags: []Flag{
StringFlag{Name: "serve, s"},
},
Action: func(ctx *Context) {
if ctx.String("serve") != "10" {
t.Errorf("main name not set")
}
if ctx.String("s") != "10" {
t.Errorf("short name not set")
}
},
}).Run([]string{"run", "-s", "10"})
}
func TestParseMultiStringFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_COUNT", "20")
(&App{
Flags: []Flag{
StringFlag{Name: "count, c", EnvVar: "APP_COUNT"},
},
Action: func(ctx *Context) {
if ctx.String("count") != "20" {
t.Errorf("main name not set")
}
if ctx.String("c") != "20" {
t.Errorf("short name not set")
}
},
}).Run([]string{"run"})
}
func TestParseMultiStringFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_COUNT", "20")
(&App{
Flags: []Flag{
StringFlag{Name: "count, c", EnvVar: "COMPAT_COUNT,APP_COUNT"},
},
Action: func(ctx *Context) {
if ctx.String("count") != "20" {
t.Errorf("main name not set")
}
if ctx.String("c") != "20" {
t.Errorf("short name not set")
}
},
}).Run([]string{"run"})
}
func TestParseMultiStringSlice(t *testing.T) {
(&App{
Flags: []Flag{
StringSliceFlag{Name: "serve, s", Value: &StringSlice{}},
},
Action: func(ctx *Context) {
if !reflect.DeepEqual(ctx.StringSlice("serve"), []string{"10", "20"}) {
t.Errorf("main name not set")
}
if !reflect.DeepEqual(ctx.StringSlice("s"), []string{"10", "20"}) {
t.Errorf("short name not set")
}
},
}).Run([]string{"run", "-s", "10", "-s", "20"})
}
func TestParseMultiStringSliceFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&App{
Flags: []Flag{
StringSliceFlag{Name: "intervals, i", Value: &StringSlice{}, EnvVar: "APP_INTERVALS"},
},
Action: func(ctx *Context) {
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
t.Errorf("short name not set from env")
}
},
}).Run([]string{"run"})
}
func TestParseMultiStringSliceFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&App{
Flags: []Flag{
StringSliceFlag{Name: "intervals, i", Value: &StringSlice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
},
Action: func(ctx *Context) {
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
t.Errorf("short name not set from env")
}
},
}).Run([]string{"run"})
}
func TestParseMultiInt(t *testing.T) {
a := App{
Flags: []Flag{
IntFlag{Name: "serve, s"},
},
Action: func(ctx *Context) {
if ctx.Int("serve") != 10 {
t.Errorf("main name not set")
}
if ctx.Int("s") != 10 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run", "-s", "10"})
}
func TestParseMultiIntFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_TIMEOUT_SECONDS", "10")
a := App{
Flags: []Flag{
IntFlag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
},
Action: func(ctx *Context) {
if ctx.Int("timeout") != 10 {
t.Errorf("main name not set")
}
if ctx.Int("t") != 10 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiIntFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_TIMEOUT_SECONDS", "10")
a := App{
Flags: []Flag{
IntFlag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"},
},
Action: func(ctx *Context) {
if ctx.Int("timeout") != 10 {
t.Errorf("main name not set")
}
if ctx.Int("t") != 10 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiIntSlice(t *testing.T) {
(&App{
Flags: []Flag{
IntSliceFlag{Name: "serve, s", Value: &IntSlice{}},
},
Action: func(ctx *Context) {
if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) {
t.Errorf("main name not set")
}
if !reflect.DeepEqual(ctx.IntSlice("s"), []int{10, 20}) {
t.Errorf("short name not set")
}
},
}).Run([]string{"run", "-s", "10", "-s", "20"})
}
func TestParseMultiIntSliceFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&App{
Flags: []Flag{
IntSliceFlag{Name: "intervals, i", Value: &IntSlice{}, EnvVar: "APP_INTERVALS"},
},
Action: func(ctx *Context) {
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
t.Errorf("short name not set from env")
}
},
}).Run([]string{"run"})
}
func TestParseMultiIntSliceFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&App{
Flags: []Flag{
IntSliceFlag{Name: "intervals, i", Value: &IntSlice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
},
Action: func(ctx *Context) {
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
t.Errorf("short name not set from env")
}
},
}).Run([]string{"run"})
}
func TestParseMultiFloat64(t *testing.T) {
a := App{
Flags: []Flag{
Float64Flag{Name: "serve, s"},
},
Action: func(ctx *Context) {
if ctx.Float64("serve") != 10.2 {
t.Errorf("main name not set")
}
if ctx.Float64("s") != 10.2 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run", "-s", "10.2"})
}
func TestParseMultiFloat64FromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
a := App{
Flags: []Flag{
Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
},
Action: func(ctx *Context) {
if ctx.Float64("timeout") != 15.5 {
t.Errorf("main name not set")
}
if ctx.Float64("t") != 15.5 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiFloat64FromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
a := App{
Flags: []Flag{
Float64Flag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"},
},
Action: func(ctx *Context) {
if ctx.Float64("timeout") != 15.5 {
t.Errorf("main name not set")
}
if ctx.Float64("t") != 15.5 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiBool(t *testing.T) {
a := App{
Flags: []Flag{
BoolFlag{Name: "serve, s"},
},
Action: func(ctx *Context) {
if ctx.Bool("serve") != true {
t.Errorf("main name not set")
}
if ctx.Bool("s") != true {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run", "--serve"})
}
func TestParseMultiBoolFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_DEBUG", "1")
a := App{
Flags: []Flag{
BoolFlag{Name: "debug, d", EnvVar: "APP_DEBUG"},
},
Action: func(ctx *Context) {
if ctx.Bool("debug") != true {
t.Errorf("main name not set from env")
}
if ctx.Bool("d") != true {
t.Errorf("short name not set from env")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiBoolFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_DEBUG", "1")
a := App{
Flags: []Flag{
BoolFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"},
},
Action: func(ctx *Context) {
if ctx.Bool("debug") != true {
t.Errorf("main name not set from env")
}
if ctx.Bool("d") != true {
t.Errorf("short name not set from env")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiBoolT(t *testing.T) {
a := App{
Flags: []Flag{
BoolTFlag{Name: "serve, s"},
},
Action: func(ctx *Context) {
if ctx.BoolT("serve") != true {
t.Errorf("main name not set")
}
if ctx.BoolT("s") != true {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run", "--serve"})
}
func TestParseMultiBoolTFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_DEBUG", "0")
a := App{
Flags: []Flag{
BoolTFlag{Name: "debug, d", EnvVar: "APP_DEBUG"},
},
Action: func(ctx *Context) {
if ctx.BoolT("debug") != false {
t.Errorf("main name not set from env")
}
if ctx.BoolT("d") != false {
t.Errorf("short name not set from env")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiBoolTFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_DEBUG", "0")
a := App{
Flags: []Flag{
BoolTFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"},
},
Action: func(ctx *Context) {
if ctx.BoolT("debug") != false {
t.Errorf("main name not set from env")
}
if ctx.BoolT("d") != false {
t.Errorf("short name not set from env")
}
},
}
a.Run([]string{"run"})
}
type Parser [2]string
func (p *Parser) Set(value string) error {
parts := strings.Split(value, ",")
if len(parts) != 2 {
return fmt.Errorf("invalid format")
}
(*p)[0] = parts[0]
(*p)[1] = parts[1]
return nil
}
func (p *Parser) String() string {
return fmt.Sprintf("%s,%s", p[0], p[1])
}
func TestParseGeneric(t *testing.T) {
a := App{
Flags: []Flag{
GenericFlag{Name: "serve, s", Value: &Parser{}},
},
Action: func(ctx *Context) {
if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"10", "20"}) {
t.Errorf("main name not set")
}
if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"10", "20"}) {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run", "-s", "10,20"})
}
func TestParseGenericFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_SERVE", "20,30")
a := App{
Flags: []Flag{
GenericFlag{Name: "serve, s", Value: &Parser{}, EnvVar: "APP_SERVE"},
},
Action: func(ctx *Context) {
if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"20", "30"}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"20", "30"}) {
t.Errorf("short name not set from env")
}
},
}
a.Run([]string{"run"})
}
func TestParseGenericFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_FOO", "99,2000")
a := App{
Flags: []Flag{
GenericFlag{Name: "foos", Value: &Parser{}, EnvVar: "COMPAT_FOO,APP_FOO"},
},
Action: func(ctx *Context) {
if !reflect.DeepEqual(ctx.Generic("foos"), &Parser{"99", "2000"}) {
t.Errorf("value not set from env")
}
},
}
a.Run([]string{"run"})
}

246
vendor/github.com/codegangsta/cli/help.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,246 @@
package cli
import (
"fmt"
"io"
"strings"
"text/tabwriter"
"text/template"
)
// The text template for the Default help topic.
// cli.go uses text/template to render templates. You can
// render custom help text by setting this variable.
var AppHelpTemplate = `NAME:
{{.Name}} - {{.Usage}}
USAGE:
{{.HelpName}} {{if .Flags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
{{if .Version}}
VERSION:
{{.Version}}
{{end}}{{if len .Authors}}
AUTHOR(S):
{{range .Authors}}{{ . }}{{end}}
{{end}}{{if .Commands}}
COMMANDS:
{{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
{{end}}{{end}}{{if .Flags}}
GLOBAL OPTIONS:
{{range .Flags}}{{.}}
{{end}}{{end}}{{if .Copyright }}
COPYRIGHT:
{{.Copyright}}
{{end}}
`
// The text template for the command help topic.
// cli.go uses text/template to render templates. You can
// render custom help text by setting this variable.
var CommandHelpTemplate = `NAME:
{{.HelpName}} - {{.Usage}}
USAGE:
{{.HelpName}}{{if .Flags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{if .Description}}
DESCRIPTION:
{{.Description}}{{end}}{{if .Flags}}
OPTIONS:
{{range .Flags}}{{.}}
{{end}}{{ end }}
`
// The text template for the subcommand help topic.
// cli.go uses text/template to render templates. You can
// render custom help text by setting this variable.
var SubcommandHelpTemplate = `NAME:
{{.HelpName}} - {{.Usage}}
USAGE:
{{.HelpName}} command{{if .Flags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
COMMANDS:
{{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
{{end}}{{if .Flags}}
OPTIONS:
{{range .Flags}}{{.}}
{{end}}{{end}}
`
var helpCommand = Command{
Name: "help",
Aliases: []string{"h"},
Usage: "Shows a list of commands or help for one command",
ArgsUsage: "[command]",
Action: func(c *Context) {
args := c.Args()
if args.Present() {
ShowCommandHelp(c, args.First())
} else {
ShowAppHelp(c)
}
},
}
var helpSubcommand = Command{
Name: "help",
Aliases: []string{"h"},
Usage: "Shows a list of commands or help for one command",
ArgsUsage: "[command]",
Action: func(c *Context) {
args := c.Args()
if args.Present() {
ShowCommandHelp(c, args.First())
} else {
ShowSubcommandHelp(c)
}
},
}
// Prints help for the App or Command
type helpPrinter func(w io.Writer, templ string, data interface{})
var HelpPrinter helpPrinter = printHelp
// Prints version for the App
var VersionPrinter = printVersion
func ShowAppHelp(c *Context) {
HelpPrinter(c.App.Writer, AppHelpTemplate, c.App)
}
// Prints the list of subcommands as the default app completion method
func DefaultAppComplete(c *Context) {
for _, command := range c.App.Commands {
for _, name := range command.Names() {
fmt.Fprintln(c.App.Writer, name)
}
}
}
// Prints help for the given command
func ShowCommandHelp(ctx *Context, command string) {
// show the subcommand help for a command with subcommands
if command == "" {
HelpPrinter(ctx.App.Writer, SubcommandHelpTemplate, ctx.App)
return
}
for _, c := range ctx.App.Commands {
if c.HasName(command) {
HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c)
return
}
}
if ctx.App.CommandNotFound != nil {
ctx.App.CommandNotFound(ctx, command)
} else {
fmt.Fprintf(ctx.App.Writer, "No help topic for '%v'\n", command)
}
}
// Prints help for the given subcommand
func ShowSubcommandHelp(c *Context) {
ShowCommandHelp(c, c.Command.Name)
}
// Prints the version number of the App
func ShowVersion(c *Context) {
VersionPrinter(c)
}
func printVersion(c *Context) {
fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version)
}
// Prints the lists of commands within a given context
func ShowCompletions(c *Context) {
a := c.App
if a != nil && a.BashComplete != nil {
a.BashComplete(c)
}
}
// Prints the custom completions for a given command
func ShowCommandCompletions(ctx *Context, command string) {
c := ctx.App.Command(command)
if c != nil && c.BashComplete != nil {
c.BashComplete(ctx)
}
}
func printHelp(out io.Writer, templ string, data interface{}) {
funcMap := template.FuncMap{
"join": strings.Join,
}
w := tabwriter.NewWriter(out, 0, 8, 1, '\t', 0)
t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
err := t.Execute(w, data)
if err != nil {
panic(err)
}
w.Flush()
}
func checkVersion(c *Context) bool {
found := false
if VersionFlag.Name != "" {
eachName(VersionFlag.Name, func(name string) {
if c.GlobalBool(name) || c.Bool(name) {
found = true
}
})
}
return found
}
func checkHelp(c *Context) bool {
found := false
if HelpFlag.Name != "" {
eachName(HelpFlag.Name, func(name string) {
if c.GlobalBool(name) || c.Bool(name) {
found = true
}
})
}
return found
}
func checkCommandHelp(c *Context, name string) bool {
if c.Bool("h") || c.Bool("help") {
ShowCommandHelp(c, name)
return true
}
return false
}
func checkSubcommandHelp(c *Context) bool {
if c.GlobalBool("h") || c.GlobalBool("help") {
ShowSubcommandHelp(c)
return true
}
return false
}
func checkCompletions(c *Context) bool {
if (c.GlobalBool(BashCompletionFlag.Name) || c.Bool(BashCompletionFlag.Name)) && c.App.EnableBashCompletion {
ShowCompletions(c)
return true
}
return false
}
func checkCommandCompletions(c *Context, name string) bool {
if c.Bool(BashCompletionFlag.Name) && c.App.EnableBashCompletion {
ShowCommandCompletions(c, name)
return true
}
return false
}

94
vendor/github.com/codegangsta/cli/help_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,94 @@
package cli
import (
"bytes"
"testing"
)
func Test_ShowAppHelp_NoAuthor(t *testing.T) {
output := new(bytes.Buffer)
app := NewApp()
app.Writer = output
c := NewContext(app, nil, nil)
ShowAppHelp(c)
if bytes.Index(output.Bytes(), []byte("AUTHOR(S):")) != -1 {
t.Errorf("expected\n%snot to include %s", output.String(), "AUTHOR(S):")
}
}
func Test_ShowAppHelp_NoVersion(t *testing.T) {
output := new(bytes.Buffer)
app := NewApp()
app.Writer = output
app.Version = ""
c := NewContext(app, nil, nil)
ShowAppHelp(c)
if bytes.Index(output.Bytes(), []byte("VERSION:")) != -1 {
t.Errorf("expected\n%snot to include %s", output.String(), "VERSION:")
}
}
func Test_Help_Custom_Flags(t *testing.T) {
oldFlag := HelpFlag
defer func() {
HelpFlag = oldFlag
}()
HelpFlag = BoolFlag{
Name: "help, x",
Usage: "show help",
}
app := App{
Flags: []Flag{
BoolFlag{Name: "foo, h"},
},
Action: func(ctx *Context) {
if ctx.Bool("h") != true {
t.Errorf("custom help flag not set")
}
},
}
output := new(bytes.Buffer)
app.Writer = output
app.Run([]string{"test", "-h"})
if output.Len() > 0 {
t.Errorf("unexpected output: %s", output.String())
}
}
func Test_Version_Custom_Flags(t *testing.T) {
oldFlag := VersionFlag
defer func() {
VersionFlag = oldFlag
}()
VersionFlag = BoolFlag{
Name: "version, V",
Usage: "show version",
}
app := App{
Flags: []Flag{
BoolFlag{Name: "foo, v"},
},
Action: func(ctx *Context) {
if ctx.Bool("v") != true {
t.Errorf("custom version flag not set")
}
},
}
output := new(bytes.Buffer)
app.Writer = output
app.Run([]string{"test", "-v"})
if output.Len() > 0 {
t.Errorf("unexpected output: %s", output.String())
}
}

19
vendor/github.com/codegangsta/cli/helpers_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,19 @@
package cli
import (
"reflect"
"testing"
)
/* Test Helpers */
func expect(t *testing.T, a interface{}, b interface{}) {
if a != b {
t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
}
}
func refute(t *testing.T, a interface{}, b interface{}) {
if a == b {
t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
}
}

14
vendor/github.com/google/go-github/github/activity.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,14 @@
// 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
// ActivityService handles communication with the activity related
// methods of the GitHub API.
//
// GitHub API docs: http://developer.github.com/v3/activity/
type ActivityService struct {
client *Client
}

305
vendor/github.com/google/go-github/github/activity_events.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,305 @@
// 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 (
"encoding/json"
"fmt"
"time"
)
// Event represents a GitHub event.
type Event struct {
Type *string `json:"type,omitempty"`
Public *bool `json:"public"`
RawPayload *json.RawMessage `json:"payload,omitempty"`
Repo *Repository `json:"repo,omitempty"`
Actor *User `json:"actor,omitempty"`
Org *Organization `json:"org,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
ID *string `json:"id,omitempty"`
}
func (e Event) String() string {
return Stringify(e)
}
// Payload returns the parsed event payload. For recognized event types
// (PushEvent), a value of the corresponding struct type will be returned.
func (e *Event) Payload() (payload interface{}) {
switch *e.Type {
case "PushEvent":
payload = &PushEvent{}
}
if err := json.Unmarshal(*e.RawPayload, &payload); err != nil {
panic(err.Error())
}
return payload
}
// PushEvent represents a git push to a GitHub repository.
//
// GitHub API docs: http://developer.github.com/v3/activity/events/types/#pushevent
type PushEvent struct {
PushID *int `json:"push_id,omitempty"`
Head *string `json:"head,omitempty"`
Ref *string `json:"ref,omitempty"`
Size *int `json:"size,omitempty"`
Commits []PushEventCommit `json:"commits,omitempty"`
Repo *Repository `json:"repository,omitempty"`
}
func (p PushEvent) String() string {
return Stringify(p)
}
// PushEventCommit represents a git commit in a GitHub PushEvent.
type PushEventCommit struct {
SHA *string `json:"sha,omitempty"`
Message *string `json:"message,omitempty"`
Author *CommitAuthor `json:"author,omitempty"`
URL *string `json:"url,omitempty"`
Distinct *bool `json:"distinct,omitempty"`
Added []string `json:"added,omitempty"`
Removed []string `json:"removed,omitempty"`
Modified []string `json:"modified,omitempty"`
}
func (p PushEventCommit) String() string {
return Stringify(p)
}
//PullRequestEvent represents the payload delivered by PullRequestEvent webhook
type PullRequestEvent struct {
Action *string `json:"action,omitempty"`
Number *int `json:"number,omitempty"`
PullRequest *PullRequest `json:"pull_request,omitempty"`
Repo *Repository `json:"repository,omitempty"`
Sender *User `json:"sender,omitempty"`
}
// IssueActivityEvent represents the payload delivered by Issue webhook
type IssueActivityEvent struct {
Action *string `json:"action,omitempty"`
Issue *Issue `json:"issue,omitempty"`
Repo *Repository `json:"repository,omitempty"`
Sender *User `json:"sender,omitempty"`
}
// IssueCommentEvent represents the payload delivered by IssueComment webhook
//
// This webhook also gets fired for comments on pull requests
type IssueCommentEvent struct {
Action *string `json:"action,omitempty"`
Issue *Issue `json:"issue,omitempty"`
Comment *IssueComment `json:"comment,omitempty"`
Repo *Repository `json:"repository,omitempty"`
Sender *User `json:"sender,omitempty"`
}
// ListEvents drinks from the firehose of all public events across GitHub.
//
// GitHub API docs: http://developer.github.com/v3/activity/events/#list-public-events
func (s *ActivityService) ListEvents(opt *ListOptions) ([]Event, *Response, error) {
u, err := addOptions("events", opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
events := new([]Event)
resp, err := s.client.Do(req, events)
if err != nil {
return nil, resp, err
}
return *events, resp, err
}
// ListRepositoryEvents lists events for a repository.
//
// GitHub API docs: http://developer.github.com/v3/activity/events/#list-repository-events
func (s *ActivityService) ListRepositoryEvents(owner, repo string, opt *ListOptions) ([]Event, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/events", owner, repo)
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
}
events := new([]Event)
resp, err := s.client.Do(req, events)
if err != nil {
return nil, resp, err
}
return *events, resp, err
}
// ListIssueEventsForRepository lists issue events for a repository.
//
// GitHub API docs: http://developer.github.com/v3/activity/events/#list-issue-events-for-a-repository
func (s *ActivityService) ListIssueEventsForRepository(owner, repo string, opt *ListOptions) ([]Event, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/events", owner, repo)
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
}
events := new([]Event)
resp, err := s.client.Do(req, events)
if err != nil {
return nil, resp, err
}
return *events, resp, err
}
// ListEventsForRepoNetwork lists public events for a network of repositories.
//
// GitHub API docs: http://developer.github.com/v3/activity/events/#list-public-events-for-a-network-of-repositories
func (s *ActivityService) ListEventsForRepoNetwork(owner, repo string, opt *ListOptions) ([]Event, *Response, error) {
u := fmt.Sprintf("networks/%v/%v/events", owner, repo)
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
}
events := new([]Event)
resp, err := s.client.Do(req, events)
if err != nil {
return nil, resp, err
}
return *events, resp, err
}
// ListEventsForOrganization lists public events for an organization.
//
// GitHub API docs: http://developer.github.com/v3/activity/events/#list-public-events-for-an-organization
func (s *ActivityService) ListEventsForOrganization(org string, opt *ListOptions) ([]Event, *Response, error) {
u := fmt.Sprintf("orgs/%v/events", org)
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
}
events := new([]Event)
resp, err := s.client.Do(req, events)
if err != nil {
return nil, resp, err
}
return *events, resp, err
}
// ListEventsPerformedByUser lists the events performed 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-performed-by-a-user
func (s *ActivityService) ListEventsPerformedByUser(user string, publicOnly bool, opt *ListOptions) ([]Event, *Response, error) {
var u string
if publicOnly {
u = fmt.Sprintf("users/%v/events/public", user)
} else {
u = fmt.Sprintf("users/%v/events", user)
}
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
}
events := new([]Event)
resp, err := s.client.Do(req, events)
if err != nil {
return nil, resp, err
}
return *events, resp, err
}
// 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) ListEventsReceivedByUser(user string, publicOnly bool, opt *ListOptions) ([]Event, *Response, error) {
var u string
if publicOnly {
u = fmt.Sprintf("users/%v/received_events/public", user)
} else {
u = fmt.Sprintf("users/%v/received_events", user)
}
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
}
events := new([]Event)
resp, err := s.client.Do(req, events)
if err != nil {
return nil, resp, err
}
return *events, resp, err
}
// ListUserEventsForOrganization provides the users organization dashboard. You
// must be authenticated as the user to view this.
//
// GitHub API docs: http://developer.github.com/v3/activity/events/#list-events-for-an-organization
func (s *ActivityService) ListUserEventsForOrganization(org, user string, opt *ListOptions) ([]Event, *Response, error) {
u := fmt.Sprintf("users/%v/events/orgs/%v", user, org)
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
}
events := new([]Event)
resp, err := s.client.Do(req, events)
if err != nil {
return nil, resp, err
}
return *events, resp, err
}

305
vendor/github.com/google/go-github/github/activity_events_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,305 @@
// 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 (
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
)
func TestActivityService_ListEvents(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/events", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"page": "2",
})
fmt.Fprint(w, `[{"id":"1"},{"id":"2"}]`)
})
opt := &ListOptions{Page: 2}
events, _, err := client.Activity.ListEvents(opt)
if err != nil {
t.Errorf("Activities.ListEvents returned error: %v", err)
}
want := []Event{{ID: String("1")}, {ID: String("2")}}
if !reflect.DeepEqual(events, want) {
t.Errorf("Activities.ListEvents returned %+v, want %+v", events, want)
}
}
func TestActivityService_ListRepositoryEvents(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/events", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"page": "2",
})
fmt.Fprint(w, `[{"id":"1"},{"id":"2"}]`)
})
opt := &ListOptions{Page: 2}
events, _, err := client.Activity.ListRepositoryEvents("o", "r", opt)
if err != nil {
t.Errorf("Activities.ListRepositoryEvents returned error: %v", err)
}
want := []Event{{ID: String("1")}, {ID: String("2")}}
if !reflect.DeepEqual(events, want) {
t.Errorf("Activities.ListRepositoryEvents returned %+v, want %+v", events, want)
}
}
func TestActivityService_ListRepositoryEvents_invalidOwner(t *testing.T) {
_, _, err := client.Activity.ListRepositoryEvents("%", "%", nil)
testURLParseError(t, err)
}
func TestActivityService_ListIssueEventsForRepository(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/events", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"page": "2",
})
fmt.Fprint(w, `[{"id":"1"},{"id":"2"}]`)
})
opt := &ListOptions{Page: 2}
events, _, err := client.Activity.ListIssueEventsForRepository("o", "r", opt)
if err != nil {
t.Errorf("Activities.ListIssueEventsForRepository returned error: %v", err)
}
want := []Event{{ID: String("1")}, {ID: String("2")}}
if !reflect.DeepEqual(events, want) {
t.Errorf("Activities.ListIssueEventsForRepository returned %+v, want %+v", events, want)
}
}
func TestActivityService_ListIssueEventsForRepository_invalidOwner(t *testing.T) {
_, _, err := client.Activity.ListIssueEventsForRepository("%", "%", nil)
testURLParseError(t, err)
}
func TestActivityService_ListEventsForRepoNetwork(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/networks/o/r/events", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"page": "2",
})
fmt.Fprint(w, `[{"id":"1"},{"id":"2"}]`)
})
opt := &ListOptions{Page: 2}
events, _, err := client.Activity.ListEventsForRepoNetwork("o", "r", opt)
if err != nil {
t.Errorf("Activities.ListEventsForRepoNetwork returned error: %v", err)
}
want := []Event{{ID: String("1")}, {ID: String("2")}}
if !reflect.DeepEqual(events, want) {
t.Errorf("Activities.ListEventsForRepoNetwork returned %+v, want %+v", events, want)
}
}
func TestActivityService_ListEventsForRepoNetwork_invalidOwner(t *testing.T) {
_, _, err := client.Activity.ListEventsForRepoNetwork("%", "%", nil)
testURLParseError(t, err)
}
func TestActivityService_ListEventsForOrganization(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/events", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"page": "2",
})
fmt.Fprint(w, `[{"id":"1"},{"id":"2"}]`)
})
opt := &ListOptions{Page: 2}
events, _, err := client.Activity.ListEventsForOrganization("o", opt)
if err != nil {
t.Errorf("Activities.ListEventsForOrganization returned error: %v", err)
}
want := []Event{{ID: String("1")}, {ID: String("2")}}
if !reflect.DeepEqual(events, want) {
t.Errorf("Activities.ListEventsForOrganization returned %+v, want %+v", events, want)
}
}
func TestActivityService_ListEventsForOrganization_invalidOrg(t *testing.T) {
_, _, err := client.Activity.ListEventsForOrganization("%", nil)
testURLParseError(t, err)
}
func TestActivityService_ListEventsPerformedByUser_all(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/users/u/events", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"page": "2",
})
fmt.Fprint(w, `[{"id":"1"},{"id":"2"}]`)
})
opt := &ListOptions{Page: 2}
events, _, err := client.Activity.ListEventsPerformedByUser("u", false, opt)
if err != nil {
t.Errorf("Events.ListPerformedByUser returned error: %v", err)
}
want := []Event{{ID: String("1")}, {ID: String("2")}}
if !reflect.DeepEqual(events, want) {
t.Errorf("Events.ListPerformedByUser returned %+v, want %+v", events, want)
}
}
func TestActivityService_ListEventsPerformedByUser_publicOnly(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/users/u/events/public", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `[{"id":"1"},{"id":"2"}]`)
})
events, _, err := client.Activity.ListEventsPerformedByUser("u", true, nil)
if err != nil {
t.Errorf("Events.ListPerformedByUser returned error: %v", err)
}
want := []Event{{ID: String("1")}, {ID: String("2")}}
if !reflect.DeepEqual(events, want) {
t.Errorf("Events.ListPerformedByUser returned %+v, want %+v", events, want)
}
}
func TestActivityService_ListEventsPerformedByUser_invalidUser(t *testing.T) {
_, _, err := client.Activity.ListEventsPerformedByUser("%", false, nil)
testURLParseError(t, err)
}
func TestActivityService_ListEventsReceivedByUser_all(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/users/u/received_events", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"page": "2",
})
fmt.Fprint(w, `[{"id":"1"},{"id":"2"}]`)
})
opt := &ListOptions{Page: 2}
events, _, err := client.Activity.ListEventsReceivedByUser("u", false, opt)
if err != nil {
t.Errorf("Events.ListReceivedByUser returned error: %v", err)
}
want := []Event{{ID: String("1")}, {ID: String("2")}}
if !reflect.DeepEqual(events, want) {
t.Errorf("Events.ListReceivedUser returned %+v, want %+v", events, want)
}
}
func TestActivityService_ListEventsReceivedByUser_publicOnly(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/users/u/received_events/public", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `[{"id":"1"},{"id":"2"}]`)
})
events, _, err := client.Activity.ListEventsReceivedByUser("u", true, nil)
if err != nil {
t.Errorf("Events.ListReceivedByUser returned error: %v", err)
}
want := []Event{{ID: String("1")}, {ID: String("2")}}
if !reflect.DeepEqual(events, want) {
t.Errorf("Events.ListReceivedByUser returned %+v, want %+v", events, want)
}
}
func TestActivityService_ListEventsReceivedByUser_invalidUser(t *testing.T) {
_, _, err := client.Activity.ListEventsReceivedByUser("%", false, nil)
testURLParseError(t, err)
}
func TestActivityService_ListUserEventsForOrganization(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/users/u/events/orgs/o", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"page": "2",
})
fmt.Fprint(w, `[{"id":"1"},{"id":"2"}]`)
})
opt := &ListOptions{Page: 2}
events, _, err := client.Activity.ListUserEventsForOrganization("o", "u", opt)
if err != nil {
t.Errorf("Activities.ListUserEventsForOrganization returned error: %v", err)
}
want := []Event{{ID: String("1")}, {ID: String("2")}}
if !reflect.DeepEqual(events, want) {
t.Errorf("Activities.ListUserEventsForOrganization returned %+v, want %+v", events, want)
}
}
func TestActivity_EventPayload_typed(t *testing.T) {
raw := []byte(`{"type": "PushEvent","payload":{"push_id": 1}}`)
var event *Event
if err := json.Unmarshal(raw, &event); err != nil {
t.Fatalf("Unmarshal Event returned error: %v", err)
}
want := &PushEvent{PushID: Int(1)}
if !reflect.DeepEqual(event.Payload(), want) {
t.Errorf("Event Payload returned %+v, want %+v", event.Payload(), want)
}
}
// TestEvent_Payload_untyped checks that unrecognized events are parsed to an
// interface{} value (instead of being discarded or throwing an error), for
// forward compatibility with new event types.
func TestActivity_EventPayload_untyped(t *testing.T) {
raw := []byte(`{"type": "UnrecognizedEvent","payload":{"field": "val"}}`)
var event *Event
if err := json.Unmarshal(raw, &event); err != nil {
t.Fatalf("Unmarshal Event returned error: %v", err)
}
want := map[string]interface{}{"field": "val"}
if !reflect.DeepEqual(event.Payload(), want) {
t.Errorf("Event Payload returned %+v, want %+v", event.Payload(), want)
}
}

225
vendor/github.com/google/go-github/github/activity_notifications.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,225 @@
// Copyright 2014 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"
"time"
)
// Notification identifies a GitHub notification for a user.
type Notification struct {
ID *string `json:"id,omitempty"`
Repository *Repository `json:"repository,omitempty"`
Subject *NotificationSubject `json:"subject,omitempty"`
// Reason identifies the event that triggered the notification.
//
// GitHub API Docs: https://developer.github.com/v3/activity/notifications/#notification-reasons
Reason *string `json:"reason,omitempty"`
Unread *bool `json:"unread,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
LastReadAt *time.Time `json:"last_read_at,omitempty"`
URL *string `json:"url,omitempty"`
}
// NotificationSubject identifies the subject of a notification.
type NotificationSubject struct {
Title *string `json:"title,omitempty"`
URL *string `json:"url,omitempty"`
LatestCommentURL *string `json:"latest_comment_url,omitempty"`
Type *string `json:"type,omitempty"`
}
// NotificationListOptions specifies the optional parameters to the
// ActivityService.ListNotifications method.
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.
//
// GitHub API Docs: https://developer.github.com/v3/activity/notifications/#list-your-notifications
func (s *ActivityService) ListNotifications(opt *NotificationListOptions) ([]Notification, *Response, error) {
u := fmt.Sprintf("notifications")
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
}
var notifications []Notification
resp, err := s.client.Do(req, &notifications)
if err != nil {
return nil, resp, err
}
return notifications, resp, err
}
// ListRepositoryNotifications lists all notifications in a given repository
// for the authenticated user.
//
// GitHub API Docs: https://developer.github.com/v3/activity/notifications/#list-your-notifications-in-a-repository
func (s *ActivityService) ListRepositoryNotifications(owner, repo string, opt *NotificationListOptions) ([]Notification, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/notifications", owner, repo)
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
}
var notifications []Notification
resp, err := s.client.Do(req, &notifications)
if err != nil {
return nil, resp, err
}
return notifications, resp, err
}
type markReadOptions struct {
LastReadAt time.Time `url:"last_read_at,omitempty"`
}
// MarkNotificationsRead marks all notifications up to lastRead as read.
//
// GitHub API Docs: https://developer.github.com/v3/activity/notifications/#mark-as-read
func (s *ActivityService) MarkNotificationsRead(lastRead time.Time) (*Response, error) {
u := fmt.Sprintf("notifications")
u, err := addOptions(u, markReadOptions{lastRead})
if err != nil {
return nil, err
}
req, err := s.client.NewRequest("PUT", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}
// MarkRepositoryNotificationsRead marks all notifications up to lastRead in
// the specified repository as read.
//
// GitHub API Docs: https://developer.github.com/v3/activity/notifications/#mark-notifications-as-read-in-a-repository
func (s *ActivityService) MarkRepositoryNotificationsRead(owner, repo string, lastRead time.Time) (*Response, error) {
u := fmt.Sprintf("repos/%v/%v/notifications", owner, repo)
u, err := addOptions(u, markReadOptions{lastRead})
if err != nil {
return nil, err
}
req, err := s.client.NewRequest("PUT", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}
// GetThread gets the specified notification thread.
//
// GitHub API Docs: https://developer.github.com/v3/activity/notifications/#view-a-single-thread
func (s *ActivityService) GetThread(id string) (*Notification, *Response, error) {
u := fmt.Sprintf("notifications/threads/%v", id)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
notification := new(Notification)
resp, err := s.client.Do(req, notification)
if err != nil {
return nil, resp, err
}
return notification, resp, err
}
// MarkThreadRead marks the specified thread as read.
//
// GitHub API Docs: https://developer.github.com/v3/activity/notifications/#mark-a-thread-as-read
func (s *ActivityService) MarkThreadRead(id string) (*Response, error) {
u := fmt.Sprintf("notifications/threads/%v", id)
req, err := s.client.NewRequest("PATCH", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}
// GetThreadSubscription checks to see if the authenticated user is subscribed
// to a thread.
//
// GitHub API Docs: https://developer.github.com/v3/activity/notifications/#get-a-thread-subscription
func (s *ActivityService) GetThreadSubscription(id string) (*Subscription, *Response, error) {
u := fmt.Sprintf("notifications/threads/%v/subscription", id)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
sub := new(Subscription)
resp, err := s.client.Do(req, sub)
if err != nil {
return nil, resp, err
}
return sub, resp, err
}
// SetThreadSubscription sets the subscription for the specified thread for the
// authenticated user.
//
// GitHub API Docs: https://developer.github.com/v3/activity/notifications/#set-a-thread-subscription
func (s *ActivityService) SetThreadSubscription(id string, subscription *Subscription) (*Subscription, *Response, error) {
u := fmt.Sprintf("notifications/threads/%v/subscription", id)
req, err := s.client.NewRequest("PUT", u, subscription)
if err != nil {
return nil, nil, err
}
sub := new(Subscription)
resp, err := s.client.Do(req, sub)
if err != nil {
return nil, resp, err
}
return sub, resp, err
}
// DeleteThreadSubscription deletes the subscription for the specified thread
// for the authenticated user.
//
// GitHub API Docs: https://developer.github.com/v3/activity/notifications/#delete-a-thread-subscription
func (s *ActivityService) DeleteThreadSubscription(id string) (*Response, error) {
u := fmt.Sprintf("notifications/threads/%v/subscription", id)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}

205
vendor/github.com/google/go-github/github/activity_notifications_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,205 @@
// Copyright 2014 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 (
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
"time"
)
func TestActivityService_ListNotification(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/notifications", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"all": "true",
"participating": "true",
"since": "2006-01-02T15:04:05Z",
"before": "2007-03-04T15:04:05Z",
})
fmt.Fprint(w, `[{"id":"1", "subject":{"title":"t"}}]`)
})
opt := &NotificationListOptions{
All: true,
Participating: true,
Since: time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC),
Before: time.Date(2007, 03, 04, 15, 04, 05, 0, time.UTC),
}
notifications, _, err := client.Activity.ListNotifications(opt)
if err != nil {
t.Errorf("Activity.ListNotifications returned error: %v", err)
}
want := []Notification{{ID: String("1"), Subject: &NotificationSubject{Title: String("t")}}}
if !reflect.DeepEqual(notifications, want) {
t.Errorf("Activity.ListNotifications returned %+v, want %+v", notifications, want)
}
}
func TestActivityService_ListRepositoryNotification(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/notifications", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `[{"id":"1"}]`)
})
notifications, _, err := client.Activity.ListRepositoryNotifications("o", "r", nil)
if err != nil {
t.Errorf("Activity.ListRepositoryNotifications returned error: %v", err)
}
want := []Notification{{ID: String("1")}}
if !reflect.DeepEqual(notifications, want) {
t.Errorf("Activity.ListRepositoryNotifications returned %+v, want %+v", notifications, want)
}
}
func TestActivityService_MarkNotificationsRead(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/notifications", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "PUT")
testFormValues(t, r, values{
"last_read_at": "2006-01-02T15:04:05Z",
})
w.WriteHeader(http.StatusResetContent)
})
_, err := client.Activity.MarkNotificationsRead(time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC))
if err != nil {
t.Errorf("Activity.MarkNotificationsRead returned error: %v", err)
}
}
func TestActivityService_MarkRepositoryNotificationsRead(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/notifications", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "PUT")
testFormValues(t, r, values{
"last_read_at": "2006-01-02T15:04:05Z",
})
w.WriteHeader(http.StatusResetContent)
})
_, err := client.Activity.MarkRepositoryNotificationsRead("o", "r", time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC))
if err != nil {
t.Errorf("Activity.MarkRepositoryNotificationsRead returned error: %v", err)
}
}
func TestActivityService_GetThread(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/notifications/threads/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"id":"1"}`)
})
notification, _, err := client.Activity.GetThread("1")
if err != nil {
t.Errorf("Activity.GetThread returned error: %v", err)
}
want := &Notification{ID: String("1")}
if !reflect.DeepEqual(notification, want) {
t.Errorf("Activity.GetThread returned %+v, want %+v", notification, want)
}
}
func TestActivityService_MarkThreadRead(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/notifications/threads/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "PATCH")
w.WriteHeader(http.StatusResetContent)
})
_, err := client.Activity.MarkThreadRead("1")
if err != nil {
t.Errorf("Activity.MarkThreadRead returned error: %v", err)
}
}
func TestActivityService_GetThreadSubscription(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/notifications/threads/1/subscription", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"subscribed":true}`)
})
sub, _, err := client.Activity.GetThreadSubscription("1")
if err != nil {
t.Errorf("Activity.GetThreadSubscription returned error: %v", err)
}
want := &Subscription{Subscribed: Bool(true)}
if !reflect.DeepEqual(sub, want) {
t.Errorf("Activity.GetThreadSubscription returned %+v, want %+v", sub, want)
}
}
func TestActivityService_SetThreadSubscription(t *testing.T) {
setup()
defer teardown()
input := &Subscription{Subscribed: Bool(true)}
mux.HandleFunc("/notifications/threads/1/subscription", func(w http.ResponseWriter, r *http.Request) {
v := new(Subscription)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PUT")
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `{"ignored":true}`)
})
sub, _, err := client.Activity.SetThreadSubscription("1", input)
if err != nil {
t.Errorf("Activity.SetThreadSubscription returned error: %v", err)
}
want := &Subscription{Ignored: Bool(true)}
if !reflect.DeepEqual(sub, want) {
t.Errorf("Activity.SetThreadSubscription returned %+v, want %+v", sub, want)
}
}
func TestActivityService_DeleteThreadSubscription(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/notifications/threads/1/subscription", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
w.WriteHeader(http.StatusNoContent)
})
_, err := client.Activity.DeleteThreadSubscription("1")
if err != nil {
t.Errorf("Activity.DeleteThreadSubscription returned error: %v", err)
}
}

123
vendor/github.com/google/go-github/github/activity_star.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,123 @@
// 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"
// StarredRepository is returned by ListStarred.
type StarredRepository struct {
StarredAt *Timestamp `json:"starred_at,omitempty"`
Repository *Repository `json:"repo,omitempty"`
}
// ListStargazers lists people who have starred the specified repo.
//
// GitHub API Docs: https://developer.github.com/v3/activity/starring/#list-stargazers
func (s *ActivityService) ListStargazers(owner, repo string, opt *ListOptions) ([]User, *Response, error) {
u := fmt.Sprintf("repos/%s/%s/stargazers", owner, repo)
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
}
stargazers := new([]User)
resp, err := s.client.Do(req, stargazers)
if err != nil {
return nil, resp, err
}
return *stargazers, resp, err
}
// ActivityListStarredOptions specifies the optional parameters to the
// ActivityService.ListStarred method.
type ActivityListStarredOptions struct {
// How to sort the repository list. Possible values are: created, updated,
// pushed, full_name. Default is "full_name".
Sort string `url:"sort,omitempty"`
// Direction in which to sort repositories. Possible values are: asc, desc.
// Default is "asc" when sort is "full_name", otherwise default is "desc".
Direction string `url:"direction,omitempty"`
ListOptions
}
// ListStarred lists all the repos starred by a user. Passing the empty string
// will list the starred repositories for the authenticated user.
//
// GitHub API docs: http://developer.github.com/v3/activity/starring/#list-repositories-being-starred
func (s *ActivityService) ListStarred(user string, opt *ActivityListStarredOptions) ([]StarredRepository, *Response, error) {
var u string
if user != "" {
u = fmt.Sprintf("users/%v/starred", user)
} else {
u = "user/starred"
}
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
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeStarringPreview)
repos := new([]StarredRepository)
resp, err := s.client.Do(req, repos)
if err != nil {
return nil, resp, err
}
return *repos, resp, err
}
// IsStarred checks if a repository is starred by authenticated user.
//
// GitHub API docs: https://developer.github.com/v3/activity/starring/#check-if-you-are-starring-a-repository
func (s *ActivityService) IsStarred(owner, repo string) (bool, *Response, error) {
u := fmt.Sprintf("user/starred/%v/%v", owner, repo)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return false, nil, err
}
resp, err := s.client.Do(req, nil)
starred, err := parseBoolResponse(err)
return starred, resp, err
}
// Star a repository as the authenticated user.
//
// GitHub API docs: https://developer.github.com/v3/activity/starring/#star-a-repository
func (s *ActivityService) Star(owner, repo string) (*Response, error) {
u := fmt.Sprintf("user/starred/%v/%v", owner, repo)
req, err := s.client.NewRequest("PUT", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}
// Unstar a repository as the authenticated user.
//
// GitHub API docs: https://developer.github.com/v3/activity/starring/#unstar-a-repository
func (s *ActivityService) Unstar(owner, repo string) (*Response, error) {
u := fmt.Sprintf("user/starred/%v/%v", owner, repo)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}

170
vendor/github.com/google/go-github/github/activity_star_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,170 @@
// 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/http"
"reflect"
"testing"
"time"
)
func TestActivityService_ListStargazers(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/stargazers", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"page": "2",
})
fmt.Fprint(w, `[{"id":1}]`)
})
stargazers, _, err := client.Activity.ListStargazers("o", "r", &ListOptions{Page: 2})
if err != nil {
t.Errorf("Activity.ListStargazers returned error: %v", err)
}
want := []User{{ID: Int(1)}}
if !reflect.DeepEqual(stargazers, want) {
t.Errorf("Activity.ListStargazers returned %+v, want %+v", stargazers, want)
}
}
func TestActivityService_ListStarred_authenticatedUser(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/user/starred", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeStarringPreview)
fmt.Fprint(w, `[{"starred_at":"2002-02-10T15:30:00Z","repo":{"id":1}}]`)
})
repos, _, err := client.Activity.ListStarred("", nil)
if err != nil {
t.Errorf("Activity.ListStarred returned error: %v", err)
}
want := []StarredRepository{{StarredAt: &Timestamp{time.Date(2002, time.February, 10, 15, 30, 0, 0, time.UTC)}, Repository: &Repository{ID: Int(1)}}}
if !reflect.DeepEqual(repos, want) {
t.Errorf("Activity.ListStarred returned %+v, want %+v", repos, want)
}
}
func TestActivityService_ListStarred_specifiedUser(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/users/u/starred", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeStarringPreview)
testFormValues(t, r, values{
"sort": "created",
"direction": "asc",
"page": "2",
})
fmt.Fprint(w, `[{"starred_at":"2002-02-10T15:30:00Z","repo":{"id":2}}]`)
})
opt := &ActivityListStarredOptions{"created", "asc", ListOptions{Page: 2}}
repos, _, err := client.Activity.ListStarred("u", opt)
if err != nil {
t.Errorf("Activity.ListStarred returned error: %v", err)
}
want := []StarredRepository{{StarredAt: &Timestamp{time.Date(2002, time.February, 10, 15, 30, 0, 0, time.UTC)}, Repository: &Repository{ID: Int(2)}}}
if !reflect.DeepEqual(repos, want) {
t.Errorf("Activity.ListStarred returned %+v, want %+v", repos, want)
}
}
func TestActivityService_ListStarred_invalidUser(t *testing.T) {
_, _, err := client.Activity.ListStarred("%", nil)
testURLParseError(t, err)
}
func TestActivityService_IsStarred_hasStar(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/user/starred/o/r", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.WriteHeader(http.StatusNoContent)
})
star, _, err := client.Activity.IsStarred("o", "r")
if err != nil {
t.Errorf("Activity.IsStarred returned error: %v", err)
}
if want := true; star != want {
t.Errorf("Activity.IsStarred returned %+v, want %+v", star, want)
}
}
func TestActivityService_IsStarred_noStar(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/user/starred/o/r", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.WriteHeader(http.StatusNotFound)
})
star, _, err := client.Activity.IsStarred("o", "r")
if err != nil {
t.Errorf("Activity.IsStarred returned error: %v", err)
}
if want := false; star != want {
t.Errorf("Activity.IsStarred returned %+v, want %+v", star, want)
}
}
func TestActivityService_IsStarred_invalidID(t *testing.T) {
_, _, err := client.Activity.IsStarred("%", "%")
testURLParseError(t, err)
}
func TestActivityService_Star(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/user/starred/o/r", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "PUT")
})
_, err := client.Activity.Star("o", "r")
if err != nil {
t.Errorf("Activity.Star returned error: %v", err)
}
}
func TestActivityService_Star_invalidID(t *testing.T) {
_, err := client.Activity.Star("%", "%")
testURLParseError(t, err)
}
func TestActivityService_Unstar(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/user/starred/o/r", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
})
_, err := client.Activity.Unstar("o", "r")
if err != nil {
t.Errorf("Activity.Unstar returned error: %v", err)
}
}
func TestActivityService_Unstar_invalidID(t *testing.T) {
_, err := client.Activity.Unstar("%", "%")
testURLParseError(t, err)
}

131
vendor/github.com/google/go-github/github/activity_watching.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,131 @@
// Copyright 2014 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"
// Subscription identifies a repository or thread subscription.
type Subscription struct {
Subscribed *bool `json:"subscribed,omitempty"`
Ignored *bool `json:"ignored,omitempty"`
Reason *string `json:"reason,omitempty"`
CreatedAt *Timestamp `json:"created_at,omitempty"`
URL *string `json:"url,omitempty"`
// only populated for repository subscriptions
RepositoryURL *string `json:"repository_url,omitempty"`
// only populated for thread subscriptions
ThreadURL *string `json:"thread_url,omitempty"`
}
// ListWatchers lists watchers of a particular repo.
//
// GitHub API Docs: http://developer.github.com/v3/activity/watching/#list-watchers
func (s *ActivityService) ListWatchers(owner, repo string, opt *ListOptions) ([]User, *Response, error) {
u := fmt.Sprintf("repos/%s/%s/subscribers", owner, repo)
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
}
watchers := new([]User)
resp, err := s.client.Do(req, watchers)
if err != nil {
return nil, resp, err
}
return *watchers, resp, err
}
// ListWatched lists the repositories the specified user is watching. Passing
// 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) {
var u string
if user != "" {
u = fmt.Sprintf("users/%v/subscriptions", user)
} else {
u = "user/subscriptions"
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
watched := new([]Repository)
resp, err := s.client.Do(req, watched)
if err != nil {
return nil, resp, err
}
return *watched, resp, err
}
// GetRepositorySubscription returns the subscription for the specified
// repository for the authenticated user. If the authenticated user is not
// watching the repository, a nil Subscription is returned.
//
// GitHub API Docs: https://developer.github.com/v3/activity/watching/#get-a-repository-subscription
func (s *ActivityService) GetRepositorySubscription(owner, repo string) (*Subscription, *Response, error) {
u := fmt.Sprintf("repos/%s/%s/subscription", owner, repo)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
sub := new(Subscription)
resp, err := s.client.Do(req, sub)
if err != nil {
// if it's just a 404, don't return that as an error
_, err = parseBoolResponse(err)
return nil, resp, err
}
return sub, resp, err
}
// SetRepositorySubscription sets the subscription for the specified repository
// for the authenticated user.
//
// GitHub API Docs: https://developer.github.com/v3/activity/watching/#set-a-repository-subscription
func (s *ActivityService) SetRepositorySubscription(owner, repo string, subscription *Subscription) (*Subscription, *Response, error) {
u := fmt.Sprintf("repos/%s/%s/subscription", owner, repo)
req, err := s.client.NewRequest("PUT", u, subscription)
if err != nil {
return nil, nil, err
}
sub := new(Subscription)
resp, err := s.client.Do(req, sub)
if err != nil {
return nil, resp, err
}
return sub, resp, err
}
// DeleteRepositorySubscription deletes the subscription for the specified
// repository for the authenticated user.
//
// GitHub API Docs: https://developer.github.com/v3/activity/watching/#delete-a-repository-subscription
func (s *ActivityService) DeleteRepositorySubscription(owner, repo string) (*Response, error) {
u := fmt.Sprintf("repos/%s/%s/subscription", owner, repo)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}

177
vendor/github.com/google/go-github/github/activity_watching_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,177 @@
// Copyright 2014 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 (
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
)
func TestActivityService_ListWatchers(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/subscribers", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"page": "2",
})
fmt.Fprint(w, `[{"id":1}]`)
})
watchers, _, err := client.Activity.ListWatchers("o", "r", &ListOptions{Page: 2})
if err != nil {
t.Errorf("Activity.ListWatchers returned error: %v", err)
}
want := []User{{ID: Int(1)}}
if !reflect.DeepEqual(watchers, want) {
t.Errorf("Activity.ListWatchers returned %+v, want %+v", watchers, want)
}
}
func TestActivityService_ListWatched_authenticatedUser(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/user/subscriptions", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `[{"id":1}]`)
})
watched, _, err := client.Activity.ListWatched("")
if err != nil {
t.Errorf("Activity.ListWatched returned error: %v", err)
}
want := []Repository{{ID: Int(1)}}
if !reflect.DeepEqual(watched, want) {
t.Errorf("Activity.ListWatched returned %+v, want %+v", watched, want)
}
}
func TestActivityService_ListWatched_specifiedUser(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/users/u/subscriptions", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `[{"id":1}]`)
})
watched, _, err := client.Activity.ListWatched("u")
if err != nil {
t.Errorf("Activity.ListWatched returned error: %v", err)
}
want := []Repository{{ID: Int(1)}}
if !reflect.DeepEqual(watched, want) {
t.Errorf("Activity.ListWatched returned %+v, want %+v", watched, want)
}
}
func TestActivityService_GetRepositorySubscription_true(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/subscription", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"subscribed":true}`)
})
sub, _, err := client.Activity.GetRepositorySubscription("o", "r")
if err != nil {
t.Errorf("Activity.GetRepositorySubscription returned error: %v", err)
}
want := &Subscription{Subscribed: Bool(true)}
if !reflect.DeepEqual(sub, want) {
t.Errorf("Activity.GetRepositorySubscription returned %+v, want %+v", sub, want)
}
}
func TestActivityService_GetRepositorySubscription_false(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/subscription", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.WriteHeader(http.StatusNotFound)
})
sub, _, err := client.Activity.GetRepositorySubscription("o", "r")
if err != nil {
t.Errorf("Activity.GetRepositorySubscription returned error: %v", err)
}
var want *Subscription
if !reflect.DeepEqual(sub, want) {
t.Errorf("Activity.GetRepositorySubscription returned %+v, want %+v", sub, want)
}
}
func TestActivityService_GetRepositorySubscription_error(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/subscription", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.WriteHeader(http.StatusBadRequest)
})
_, _, err := client.Activity.GetRepositorySubscription("o", "r")
if err == nil {
t.Errorf("Expected HTTP 400 response")
}
}
func TestActivityService_SetRepositorySubscription(t *testing.T) {
setup()
defer teardown()
input := &Subscription{Subscribed: Bool(true)}
mux.HandleFunc("/repos/o/r/subscription", func(w http.ResponseWriter, r *http.Request) {
v := new(Subscription)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PUT")
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `{"ignored":true}`)
})
sub, _, err := client.Activity.SetRepositorySubscription("o", "r", input)
if err != nil {
t.Errorf("Activity.SetRepositorySubscription returned error: %v", err)
}
want := &Subscription{Ignored: Bool(true)}
if !reflect.DeepEqual(sub, want) {
t.Errorf("Activity.SetRepositorySubscription returned %+v, want %+v", sub, want)
}
}
func TestActivityService_DeleteRepositorySubscription(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/subscription", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
w.WriteHeader(http.StatusNoContent)
})
_, err := client.Activity.DeleteRepositorySubscription("o", "r")
if err != nil {
t.Errorf("Activity.DeleteRepositorySubscription returned error: %v", err)
}
}

126
vendor/github.com/google/go-github/github/doc.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,126 @@
// 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 provides a client for using the GitHub API.
Construct a new GitHub client, then use the various services on the client to
access different parts of the GitHub API. For example:
client := github.NewClient(nil)
// list all organizations for user "willnorris"
orgs, _, err := client.Organizations.List("willnorris", nil)
Set optional parameters for an API method by passing an Options object.
// list recently updated repositories for org "github"
opt := &github.RepositoryListByOrgOptions{Sort: "updated"}
repos, _, err := client.Repositories.ListByOrg("github", opt)
The services of a client divide the API into logical chunks and correspond to
the structure of the GitHub API documentation at
http://developer.github.com/v3/.
Authentication
The go-github library does not directly handle authentication. Instead, when
creating a new client, pass an http.Client that can handle authentication for
you. The easiest and recommended way to do this is using the golang.org/x/oauth2
library, but you can always use any other library that provides an http.Client.
If you have an OAuth2 access token (for example, a personal API token), you can
use it with the oauth2 library using:
import "golang.org/x/oauth2"
func main() {
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: "... your access token ..."},
)
tc := oauth2.NewClient(oauth2.NoContext, ts)
client := github.NewClient(tc)
// list all repositories for the authenticated user
repos, _, err := client.Repositories.List("", nil)
}
Note that when using an authenticated Client, all calls made by the client will
include the specified OAuth token. Therefore, authenticated clients should
almost never be shared between different users.
Rate Limiting
GitHub imposes a rate limit on all API clients. Unauthenticated clients are
limited to 60 requests per hour, while authenticated clients can make up to
5,000 requests per hour. To receive the higher rate limit when making calls
that are not issued on behalf of a user, use the
UnauthenticatedRateLimitedTransport.
The Rate field on a client tracks the rate limit information based on the most
recent API call. This is updated on every call, but may be out of date if it's
been some time since the last API call and other clients have made subsequent
requests since then. You can always call RateLimit() directly to get the most
up-to-date rate limit data for the client.
Learn more about GitHub rate limiting at
http://developer.github.com/v3/#rate-limiting.
Conditional Requests
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/sourcegraph/apiproxy to provide additional flexibility and
control of caching rules.
Learn more about GitHub conditional requests at
https://developer.github.com/v3/#conditional-requests.
Creating and Updating Resources
All structs for GitHub resources use pointer values for all non-repeated fields.
This allows distinguishing between unset fields and those set to a zero-value.
Helper functions have been provided to easily create these pointers for string,
bool, and int values. For example:
// create a new private repository named "foo"
repo := &github.Repository{
Name: github.String("foo"),
Private: github.Bool(true),
}
client.Repositories.Create("", repo)
Users who have worked with protocol buffers should find this pattern familiar.
Pagination
All requests for resource collections (repos, pull requests, issues, etc)
support pagination. Pagination options are described in the
ListOptions struct and passed to the list methods directly or as an
embedded type of a more specific list options struct (for example
PullRequestListOptions). Pages information is available via Response struct.
opt := &github.RepositoryListByOrgOptions{
ListOptions: github.ListOptions{PerPage: 10},
}
// get all pages of results
var allRepos []github.Repository
for {
repos, resp, err := client.Repositories.ListByOrg("github", opt)
if err != nil {
return err
}
allRepos = append(allRepos, repos...)
if resp.NextPage == 0 {
break
}
opt.ListOptions.Page = resp.NextPage
}
*/
package github

281
vendor/github.com/google/go-github/github/gists.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,281 @@
// Copyright 2013 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by BSD-style
// license that can be found in the LICENSE file.
package github
import (
"fmt"
"time"
)
// GistsService handles communication with the Gist related
// methods of the GitHub API.
//
// GitHub API docs: http://developer.github.com/v3/gists/
type GistsService struct {
client *Client
}
// Gist represents a GitHub's gist.
type Gist struct {
ID *string `json:"id,omitempty"`
Description *string `json:"description,omitempty"`
Public *bool `json:"public,omitempty"`
Owner *User `json:"owner,omitempty"`
Files map[GistFilename]GistFile `json:"files,omitempty"`
Comments *int `json:"comments,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
GitPullURL *string `json:"git_pull_url,omitempty"`
GitPushURL *string `json:"git_push_url,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
}
func (g Gist) String() string {
return Stringify(g)
}
// GistFilename represents filename on a gist.
type GistFilename string
// GistFile represents a file on a gist.
type GistFile struct {
Size *int `json:"size,omitempty"`
Filename *string `json:"filename,omitempty"`
RawURL *string `json:"raw_url,omitempty"`
Content *string `json:"content,omitempty"`
}
func (g GistFile) String() string {
return Stringify(g)
}
// GistListOptions specifies the optional parameters to the
// GistsService.List, GistsService.ListAll, and GistsService.ListStarred methods.
type GistListOptions struct {
// Since filters Gists by time.
Since time.Time `url:"since,omitempty"`
ListOptions
}
// List gists for a user. Passing the empty string will list
// all public gists if called anonymously. However, if the call
// is authenticated, it will returns all gists for the authenticated
// user.
//
// GitHub API docs: http://developer.github.com/v3/gists/#list-gists
func (s *GistsService) List(user string, opt *GistListOptions) ([]Gist, *Response, error) {
var u string
if user != "" {
u = fmt.Sprintf("users/%v/gists", user)
} else {
u = "gists"
}
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
}
gists := new([]Gist)
resp, err := s.client.Do(req, gists)
if err != nil {
return nil, resp, err
}
return *gists, resp, err
}
// ListAll lists all public gists.
//
// GitHub API docs: http://developer.github.com/v3/gists/#list-gists
func (s *GistsService) ListAll(opt *GistListOptions) ([]Gist, *Response, error) {
u, err := addOptions("gists/public", opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
gists := new([]Gist)
resp, err := s.client.Do(req, gists)
if err != nil {
return nil, resp, err
}
return *gists, resp, err
}
// ListStarred lists starred gists of authenticated user.
//
// GitHub API docs: http://developer.github.com/v3/gists/#list-gists
func (s *GistsService) ListStarred(opt *GistListOptions) ([]Gist, *Response, error) {
u, err := addOptions("gists/starred", opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
gists := new([]Gist)
resp, err := s.client.Do(req, gists)
if err != nil {
return nil, resp, err
}
return *gists, resp, err
}
// Get a single gist.
//
// GitHub API docs: http://developer.github.com/v3/gists/#get-a-single-gist
func (s *GistsService) Get(id string) (*Gist, *Response, error) {
u := fmt.Sprintf("gists/%v", id)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
gist := new(Gist)
resp, err := s.client.Do(req, gist)
if err != nil {
return nil, resp, err
}
return gist, resp, err
}
// GetRevision gets a specific revision of a gist.
//
// GitHub API docs: https://developer.github.com/v3/gists/#get-a-specific-revision-of-a-gist
func (s *GistsService) GetRevision(id, sha string) (*Gist, *Response, error) {
u := fmt.Sprintf("gists/%v/%v", id, sha)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
gist := new(Gist)
resp, err := s.client.Do(req, gist)
if err != nil {
return nil, resp, err
}
return gist, resp, err
}
// Create a gist for authenticated user.
//
// GitHub API docs: http://developer.github.com/v3/gists/#create-a-gist
func (s *GistsService) Create(gist *Gist) (*Gist, *Response, error) {
u := "gists"
req, err := s.client.NewRequest("POST", u, gist)
if err != nil {
return nil, nil, err
}
g := new(Gist)
resp, err := s.client.Do(req, g)
if err != nil {
return nil, resp, err
}
return g, resp, err
}
// Edit a gist.
//
// GitHub API docs: http://developer.github.com/v3/gists/#edit-a-gist
func (s *GistsService) Edit(id string, gist *Gist) (*Gist, *Response, error) {
u := fmt.Sprintf("gists/%v", id)
req, err := s.client.NewRequest("PATCH", u, gist)
if err != nil {
return nil, nil, err
}
g := new(Gist)
resp, err := s.client.Do(req, g)
if err != nil {
return nil, resp, err
}
return g, resp, err
}
// Delete a gist.
//
// GitHub API docs: http://developer.github.com/v3/gists/#delete-a-gist
func (s *GistsService) Delete(id string) (*Response, error) {
u := fmt.Sprintf("gists/%v", id)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}
// Star a gist on behalf of authenticated user.
//
// GitHub API docs: http://developer.github.com/v3/gists/#star-a-gist
func (s *GistsService) Star(id string) (*Response, error) {
u := fmt.Sprintf("gists/%v/star", id)
req, err := s.client.NewRequest("PUT", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}
// Unstar a gist on a behalf of authenticated user.
//
// Github API docs: http://developer.github.com/v3/gists/#unstar-a-gist
func (s *GistsService) Unstar(id string) (*Response, error) {
u := fmt.Sprintf("gists/%v/star", id)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}
// IsStarred checks if a gist is starred by authenticated user.
//
// GitHub API docs: http://developer.github.com/v3/gists/#check-if-a-gist-is-starred
func (s *GistsService) IsStarred(id string) (bool, *Response, error) {
u := fmt.Sprintf("gists/%v/star", id)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return false, nil, err
}
resp, err := s.client.Do(req, nil)
starred, err := parseBoolResponse(err)
return starred, resp, err
}
// Fork a gist.
//
// GitHub API docs: http://developer.github.com/v3/gists/#fork-a-gist
func (s *GistsService) Fork(id string) (*Gist, *Response, error) {
u := fmt.Sprintf("gists/%v/forks", id)
req, err := s.client.NewRequest("POST", u, nil)
if err != nil {
return nil, nil, err
}
g := new(Gist)
resp, err := s.client.Do(req, g)
if err != nil {
return nil, resp, err
}
return g, resp, err
}

118
vendor/github.com/google/go-github/github/gists_comments.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,118 @@
// 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"
"time"
)
// GistComment represents a Gist comment.
type GistComment struct {
ID *int `json:"id,omitempty"`
URL *string `json:"url,omitempty"`
Body *string `json:"body,omitempty"`
User *User `json:"user,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
}
func (g GistComment) String() string {
return Stringify(g)
}
// ListComments lists all comments for a gist.
//
// GitHub API docs: http://developer.github.com/v3/gists/comments/#list-comments-on-a-gist
func (s *GistsService) ListComments(gistID string, opt *ListOptions) ([]GistComment, *Response, error) {
u := fmt.Sprintf("gists/%v/comments", gistID)
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
}
comments := new([]GistComment)
resp, err := s.client.Do(req, comments)
if err != nil {
return nil, resp, err
}
return *comments, resp, err
}
// GetComment retrieves a single comment from a gist.
//
// GitHub API docs: http://developer.github.com/v3/gists/comments/#get-a-single-comment
func (s *GistsService) GetComment(gistID string, commentID int) (*GistComment, *Response, error) {
u := fmt.Sprintf("gists/%v/comments/%v", gistID, commentID)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
c := new(GistComment)
resp, err := s.client.Do(req, c)
if err != nil {
return nil, resp, err
}
return c, resp, err
}
// CreateComment creates a comment for a gist.
//
// GitHub API docs: http://developer.github.com/v3/gists/comments/#create-a-comment
func (s *GistsService) CreateComment(gistID string, comment *GistComment) (*GistComment, *Response, error) {
u := fmt.Sprintf("gists/%v/comments", gistID)
req, err := s.client.NewRequest("POST", u, comment)
if err != nil {
return nil, nil, err
}
c := new(GistComment)
resp, err := s.client.Do(req, c)
if err != nil {
return nil, resp, err
}
return c, resp, err
}
// EditComment edits an existing gist comment.
//
// GitHub API docs: http://developer.github.com/v3/gists/comments/#edit-a-comment
func (s *GistsService) EditComment(gistID string, commentID int, comment *GistComment) (*GistComment, *Response, error) {
u := fmt.Sprintf("gists/%v/comments/%v", gistID, commentID)
req, err := s.client.NewRequest("PATCH", u, comment)
if err != nil {
return nil, nil, err
}
c := new(GistComment)
resp, err := s.client.Do(req, c)
if err != nil {
return nil, resp, err
}
return c, resp, err
}
// DeleteComment deletes a gist comment.
//
// GitHub API docs: http://developer.github.com/v3/gists/comments/#delete-a-comment
func (s *GistsService) DeleteComment(gistID string, commentID int) (*Response, error) {
u := fmt.Sprintf("gists/%v/comments/%v", gistID, commentID)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}

155
vendor/github.com/google/go-github/github/gists_comments_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,155 @@
// 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 (
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
)
func TestGistsService_ListComments(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/gists/1/comments", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{"page": "2"})
fmt.Fprint(w, `[{"id": 1}]`)
})
opt := &ListOptions{Page: 2}
comments, _, err := client.Gists.ListComments("1", opt)
if err != nil {
t.Errorf("Gists.Comments returned error: %v", err)
}
want := []GistComment{{ID: Int(1)}}
if !reflect.DeepEqual(comments, want) {
t.Errorf("Gists.ListComments returned %+v, want %+v", comments, want)
}
}
func TestGistsService_ListComments_invalidID(t *testing.T) {
_, _, err := client.Gists.ListComments("%", nil)
testURLParseError(t, err)
}
func TestGistsService_GetComment(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/gists/1/comments/2", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"id": 1}`)
})
comment, _, err := client.Gists.GetComment("1", 2)
if err != nil {
t.Errorf("Gists.GetComment returned error: %v", err)
}
want := &GistComment{ID: Int(1)}
if !reflect.DeepEqual(comment, want) {
t.Errorf("Gists.GetComment returned %+v, want %+v", comment, want)
}
}
func TestGistsService_GetComment_invalidID(t *testing.T) {
_, _, err := client.Gists.GetComment("%", 1)
testURLParseError(t, err)
}
func TestGistsService_CreateComment(t *testing.T) {
setup()
defer teardown()
input := &GistComment{ID: Int(1), Body: String("b")}
mux.HandleFunc("/gists/1/comments", func(w http.ResponseWriter, r *http.Request) {
v := new(GistComment)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "POST")
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `{"id":1}`)
})
comment, _, err := client.Gists.CreateComment("1", input)
if err != nil {
t.Errorf("Gists.CreateComment returned error: %v", err)
}
want := &GistComment{ID: Int(1)}
if !reflect.DeepEqual(comment, want) {
t.Errorf("Gists.CreateComment returned %+v, want %+v", comment, want)
}
}
func TestGistsService_CreateComment_invalidID(t *testing.T) {
_, _, err := client.Gists.CreateComment("%", nil)
testURLParseError(t, err)
}
func TestGistsService_EditComment(t *testing.T) {
setup()
defer teardown()
input := &GistComment{ID: Int(1), Body: String("b")}
mux.HandleFunc("/gists/1/comments/2", func(w http.ResponseWriter, r *http.Request) {
v := new(GistComment)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PATCH")
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `{"id":1}`)
})
comment, _, err := client.Gists.EditComment("1", 2, input)
if err != nil {
t.Errorf("Gists.EditComment returned error: %v", err)
}
want := &GistComment{ID: Int(1)}
if !reflect.DeepEqual(comment, want) {
t.Errorf("Gists.EditComment returned %+v, want %+v", comment, want)
}
}
func TestGistsService_EditComment_invalidID(t *testing.T) {
_, _, err := client.Gists.EditComment("%", 1, nil)
testURLParseError(t, err)
}
func TestGistsService_DeleteComment(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/gists/1/comments/2", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
})
_, err := client.Gists.DeleteComment("1", 2)
if err != nil {
t.Errorf("Gists.Delete returned error: %v", err)
}
}
func TestGistsService_DeleteComment_invalidID(t *testing.T) {
_, err := client.Gists.DeleteComment("%", 1)
testURLParseError(t, err)
}

411
vendor/github.com/google/go-github/github/gists_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,411 @@
// 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 (
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
"time"
)
func TestGistsService_List_specifiedUser(t *testing.T) {
setup()
defer teardown()
since := "2013-01-01T00:00:00Z"
mux.HandleFunc("/users/u/gists", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"since": since,
})
fmt.Fprint(w, `[{"id": "1"}]`)
})
opt := &GistListOptions{Since: time.Date(2013, time.January, 1, 0, 0, 0, 0, time.UTC)}
gists, _, err := client.Gists.List("u", opt)
if err != nil {
t.Errorf("Gists.List returned error: %v", err)
}
want := []Gist{{ID: String("1")}}
if !reflect.DeepEqual(gists, want) {
t.Errorf("Gists.List returned %+v, want %+v", gists, want)
}
}
func TestGistsService_List_authenticatedUser(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/gists", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `[{"id": "1"}]`)
})
gists, _, err := client.Gists.List("", nil)
if err != nil {
t.Errorf("Gists.List returned error: %v", err)
}
want := []Gist{{ID: String("1")}}
if !reflect.DeepEqual(gists, want) {
t.Errorf("Gists.List returned %+v, want %+v", gists, want)
}
}
func TestGistsService_List_invalidUser(t *testing.T) {
_, _, err := client.Gists.List("%", nil)
testURLParseError(t, err)
}
func TestGistsService_ListAll(t *testing.T) {
setup()
defer teardown()
since := "2013-01-01T00:00:00Z"
mux.HandleFunc("/gists/public", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"since": since,
})
fmt.Fprint(w, `[{"id": "1"}]`)
})
opt := &GistListOptions{Since: time.Date(2013, time.January, 1, 0, 0, 0, 0, time.UTC)}
gists, _, err := client.Gists.ListAll(opt)
if err != nil {
t.Errorf("Gists.ListAll returned error: %v", err)
}
want := []Gist{{ID: String("1")}}
if !reflect.DeepEqual(gists, want) {
t.Errorf("Gists.ListAll returned %+v, want %+v", gists, want)
}
}
func TestGistsService_ListStarred(t *testing.T) {
setup()
defer teardown()
since := "2013-01-01T00:00:00Z"
mux.HandleFunc("/gists/starred", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"since": since,
})
fmt.Fprint(w, `[{"id": "1"}]`)
})
opt := &GistListOptions{Since: time.Date(2013, time.January, 1, 0, 0, 0, 0, time.UTC)}
gists, _, err := client.Gists.ListStarred(opt)
if err != nil {
t.Errorf("Gists.ListStarred returned error: %v", err)
}
want := []Gist{{ID: String("1")}}
if !reflect.DeepEqual(gists, want) {
t.Errorf("Gists.ListStarred returned %+v, want %+v", gists, want)
}
}
func TestGistsService_Get(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/gists/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"id": "1"}`)
})
gist, _, err := client.Gists.Get("1")
if err != nil {
t.Errorf("Gists.Get returned error: %v", err)
}
want := &Gist{ID: String("1")}
if !reflect.DeepEqual(gist, want) {
t.Errorf("Gists.Get returned %+v, want %+v", gist, want)
}
}
func TestGistsService_Get_invalidID(t *testing.T) {
_, _, err := client.Gists.Get("%")
testURLParseError(t, err)
}
func TestGistsService_GetRevision(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/gists/1/s", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"id": "1"}`)
})
gist, _, err := client.Gists.GetRevision("1", "s")
if err != nil {
t.Errorf("Gists.Get returned error: %v", err)
}
want := &Gist{ID: String("1")}
if !reflect.DeepEqual(gist, want) {
t.Errorf("Gists.Get returned %+v, want %+v", gist, want)
}
}
func TestGistsService_GetRevision_invalidID(t *testing.T) {
_, _, err := client.Gists.GetRevision("%", "%")
testURLParseError(t, err)
}
func TestGistsService_Create(t *testing.T) {
setup()
defer teardown()
input := &Gist{
Description: String("Gist description"),
Public: Bool(false),
Files: map[GistFilename]GistFile{
"test.txt": {Content: String("Gist file content")},
},
}
mux.HandleFunc("/gists", func(w http.ResponseWriter, r *http.Request) {
v := new(Gist)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "POST")
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w,
`
{
"id": "1",
"description": "Gist description",
"public": false,
"files": {
"test.txt": {
"filename": "test.txt"
}
}
}`)
})
gist, _, err := client.Gists.Create(input)
if err != nil {
t.Errorf("Gists.Create returned error: %v", err)
}
want := &Gist{
ID: String("1"),
Description: String("Gist description"),
Public: Bool(false),
Files: map[GistFilename]GistFile{
"test.txt": {Filename: String("test.txt")},
},
}
if !reflect.DeepEqual(gist, want) {
t.Errorf("Gists.Create returned %+v, want %+v", gist, want)
}
}
func TestGistsService_Edit(t *testing.T) {
setup()
defer teardown()
input := &Gist{
Description: String("New description"),
Files: map[GistFilename]GistFile{
"new.txt": {Content: String("new file content")},
},
}
mux.HandleFunc("/gists/1", func(w http.ResponseWriter, r *http.Request) {
v := new(Gist)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PATCH")
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w,
`
{
"id": "1",
"description": "new description",
"public": false,
"files": {
"test.txt": {
"filename": "test.txt"
},
"new.txt": {
"filename": "new.txt"
}
}
}`)
})
gist, _, err := client.Gists.Edit("1", input)
if err != nil {
t.Errorf("Gists.Edit returned error: %v", err)
}
want := &Gist{
ID: String("1"),
Description: String("new description"),
Public: Bool(false),
Files: map[GistFilename]GistFile{
"test.txt": {Filename: String("test.txt")},
"new.txt": {Filename: String("new.txt")},
},
}
if !reflect.DeepEqual(gist, want) {
t.Errorf("Gists.Edit returned %+v, want %+v", gist, want)
}
}
func TestGistsService_Edit_invalidID(t *testing.T) {
_, _, err := client.Gists.Edit("%", nil)
testURLParseError(t, err)
}
func TestGistsService_Delete(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/gists/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
})
_, err := client.Gists.Delete("1")
if err != nil {
t.Errorf("Gists.Delete returned error: %v", err)
}
}
func TestGistsService_Delete_invalidID(t *testing.T) {
_, err := client.Gists.Delete("%")
testURLParseError(t, err)
}
func TestGistsService_Star(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/gists/1/star", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "PUT")
})
_, err := client.Gists.Star("1")
if err != nil {
t.Errorf("Gists.Star returned error: %v", err)
}
}
func TestGistsService_Star_invalidID(t *testing.T) {
_, err := client.Gists.Star("%")
testURLParseError(t, err)
}
func TestGistsService_Unstar(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/gists/1/star", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
})
_, err := client.Gists.Unstar("1")
if err != nil {
t.Errorf("Gists.Unstar returned error: %v", err)
}
}
func TestGistsService_Unstar_invalidID(t *testing.T) {
_, err := client.Gists.Unstar("%")
testURLParseError(t, err)
}
func TestGistsService_IsStarred_hasStar(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/gists/1/star", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.WriteHeader(http.StatusNoContent)
})
star, _, err := client.Gists.IsStarred("1")
if err != nil {
t.Errorf("Gists.Starred returned error: %v", err)
}
if want := true; star != want {
t.Errorf("Gists.Starred returned %+v, want %+v", star, want)
}
}
func TestGistsService_IsStarred_noStar(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/gists/1/star", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.WriteHeader(http.StatusNotFound)
})
star, _, err := client.Gists.IsStarred("1")
if err != nil {
t.Errorf("Gists.Starred returned error: %v", err)
}
if want := false; star != want {
t.Errorf("Gists.Starred returned %+v, want %+v", star, want)
}
}
func TestGistsService_IsStarred_invalidID(t *testing.T) {
_, _, err := client.Gists.IsStarred("%")
testURLParseError(t, err)
}
func TestGistsService_Fork(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/gists/1/forks", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "POST")
fmt.Fprint(w, `{"id": "2"}`)
})
gist, _, err := client.Gists.Fork("1")
if err != nil {
t.Errorf("Gists.Fork returned error: %v", err)
}
want := &Gist{ID: String("2")}
if !reflect.DeepEqual(gist, want) {
t.Errorf("Gists.Fork returned %+v, want %+v", gist, want)
}
}
func TestGistsService_Fork_invalidID(t *testing.T) {
_, _, err := client.Gists.Fork("%")
testURLParseError(t, err)
}

14
vendor/github.com/google/go-github/github/git.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,14 @@
// 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
// GitService handles communication with the git data related
// methods of the GitHub API.
//
// GitHub API docs: http://developer.github.com/v3/git/
type GitService struct {
client *Client
}

47
vendor/github.com/google/go-github/github/git_blobs.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,47 @@
// 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"
// Blob represents a blob object.
type Blob struct {
Content *string `json:"content,omitempty"`
Encoding *string `json:"encoding,omitempty"`
SHA *string `json:"sha,omitempty"`
Size *int `json:"size,omitempty"`
URL *string `json:"url,omitempty"`
}
// GetBlob fetchs a blob from a repo given a SHA.
//
// GitHub API docs: http://developer.github.com/v3/git/blobs/#get-a-blob
func (s *GitService) GetBlob(owner string, repo string, sha string) (*Blob, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/git/blobs/%v", owner, repo, sha)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
blob := new(Blob)
resp, err := s.client.Do(req, blob)
return blob, resp, err
}
// CreateBlob creates a blob object.
//
// GitHub API docs: http://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)
if err != nil {
return nil, nil, err
}
t := new(Blob)
resp, err := s.client.Do(req, t)
return t, resp, err
}

92
vendor/github.com/google/go-github/github/git_blobs_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,92 @@
package github
import (
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
)
func TestGitService_GetBlob(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/git/blobs/s", func(w http.ResponseWriter, r *http.Request) {
if m := "GET"; m != r.Method {
t.Errorf("Request method = %v, want %v", r.Method, m)
}
fmt.Fprint(w, `{
"sha": "s",
"content": "blob content"
}`)
})
blob, _, err := client.Git.GetBlob("o", "r", "s")
if err != nil {
t.Errorf("Git.GetBlob returned error: %v", err)
}
want := Blob{
SHA: String("s"),
Content: String("blob content"),
}
if !reflect.DeepEqual(*blob, want) {
t.Errorf("Blob.Get returned %+v, want %+v", *blob, want)
}
}
func TestGitService_GetBlob_invalidOwner(t *testing.T) {
_, _, err := client.Git.GetBlob("%", "%", "%")
testURLParseError(t, err)
}
func TestGitService_CreateBlob(t *testing.T) {
setup()
defer teardown()
input := &Blob{
SHA: String("s"),
Content: String("blob content"),
Encoding: String("utf-8"),
Size: Int(12),
}
mux.HandleFunc("/repos/o/r/git/blobs", func(w http.ResponseWriter, r *http.Request) {
v := new(Blob)
json.NewDecoder(r.Body).Decode(v)
if m := "POST"; m != r.Method {
t.Errorf("Request method = %v, want %v", r.Method, m)
}
want := input
if !reflect.DeepEqual(v, want) {
t.Errorf("Git.CreateBlob request body: %+v, want %+v", v, want)
}
fmt.Fprint(w, `{
"sha": "s",
"content": "blob content",
"encoding": "utf-8",
"size": 12
}`)
})
blob, _, err := client.Git.CreateBlob("o", "r", input)
if err != nil {
t.Errorf("Git.CreateBlob returned error: %v", err)
}
want := input
if !reflect.DeepEqual(*blob, *want) {
t.Errorf("Git.CreateBlob returned %+v, want %+v", *blob, *want)
}
}
func TestGitService_CreateBlob_invalidOwner(t *testing.T) {
_, _, err := client.Git.CreateBlob("%", "%", &Blob{})
testURLParseError(t, err)
}

112
vendor/github.com/google/go-github/github/git_commits.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,112 @@
// 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"
"time"
)
// Commit represents a GitHub commit.
type Commit struct {
SHA *string `json:"sha,omitempty"`
Author *CommitAuthor `json:"author,omitempty"`
Committer *CommitAuthor `json:"committer,omitempty"`
Message *string `json:"message,omitempty"`
Tree *Tree `json:"tree,omitempty"`
Parents []Commit `json:"parents,omitempty"`
Stats *CommitStats `json:"stats,omitempty"`
URL *string `json:"url,omitempty"`
// CommentCount is the number of GitHub comments on the commit. This
// is only populated for requests that fetch GitHub data like
// Pulls.ListCommits, Repositories.ListCommits, etc.
CommentCount *int `json:"comment_count,omitempty"`
}
func (c Commit) String() string {
return Stringify(c)
}
// CommitAuthor represents the author or committer of a commit. The commit
// author may not correspond to a GitHub User.
type CommitAuthor struct {
Date *time.Time `json:"date,omitempty"`
Name *string `json:"name,omitempty"`
Email *string `json:"email,omitempty"`
}
func (c CommitAuthor) String() string {
return Stringify(c)
}
// GetCommit fetchs the Commit object for a given SHA.
//
// GitHub API docs: http://developer.github.com/v3/git/commits/#get-a-commit
func (s *GitService) GetCommit(owner string, repo string, sha string) (*Commit, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/git/commits/%v", owner, repo, sha)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
c := new(Commit)
resp, err := s.client.Do(req, c)
if err != nil {
return nil, resp, err
}
return c, resp, err
}
// createCommit represents the body of a CreateCommit request.
type createCommit struct {
Author *CommitAuthor `json:"author,omitempty"`
Committer *CommitAuthor `json:"committer,omitempty"`
Message *string `json:"message,omitempty"`
Tree *string `json:"tree,omitempty"`
Parents []string `json:"parents,omitempty"`
}
// CreateCommit creates a new commit in a repository.
//
// The commit.Committer is optional and will be filled with the commit.Author
// data if omitted. If the commit.Author is omitted, it will be filled in with
// the authenticated users information and the current date.
//
// GitHub API docs: http://developer.github.com/v3/git/commits/#create-a-commit
func (s *GitService) CreateCommit(owner string, repo string, commit *Commit) (*Commit, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/git/commits", owner, repo)
body := &createCommit{}
if commit != nil {
parents := make([]string, len(commit.Parents))
for i, parent := range commit.Parents {
parents[i] = *parent.SHA
}
body = &createCommit{
Author: commit.Author,
Committer: commit.Committer,
Message: commit.Message,
Tree: commit.Tree.SHA,
Parents: parents,
}
}
req, err := s.client.NewRequest("POST", u, body)
if err != nil {
return nil, nil, err
}
c := new(Commit)
resp, err := s.client.Do(req, c)
if err != nil {
return nil, resp, err
}
return c, resp, err
}

82
vendor/github.com/google/go-github/github/git_commits_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,82 @@
// 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 (
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
)
func TestGitService_GetCommit(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/git/commits/s", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"sha":"s","message":"m","author":{"name":"n"}}`)
})
commit, _, err := client.Git.GetCommit("o", "r", "s")
if err != nil {
t.Errorf("Git.GetCommit returned error: %v", err)
}
want := &Commit{SHA: String("s"), Message: String("m"), Author: &CommitAuthor{Name: String("n")}}
if !reflect.DeepEqual(commit, want) {
t.Errorf("Git.GetCommit returned %+v, want %+v", commit, want)
}
}
func TestGitService_GetCommit_invalidOwner(t *testing.T) {
_, _, err := client.Git.GetCommit("%", "%", "%")
testURLParseError(t, err)
}
func TestGitService_CreateCommit(t *testing.T) {
setup()
defer teardown()
input := &Commit{
Message: String("m"),
Tree: &Tree{SHA: String("t")},
Parents: []Commit{{SHA: String("p")}},
}
mux.HandleFunc("/repos/o/r/git/commits", func(w http.ResponseWriter, r *http.Request) {
v := new(createCommit)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "POST")
want := &createCommit{
Message: input.Message,
Tree: String("t"),
Parents: []string{"p"},
}
if !reflect.DeepEqual(v, want) {
t.Errorf("Request body = %+v, want %+v", v, want)
}
fmt.Fprint(w, `{"sha":"s"}`)
})
commit, _, err := client.Git.CreateCommit("o", "r", input)
if err != nil {
t.Errorf("Git.CreateCommit returned error: %v", err)
}
want := &Commit{SHA: String("s")}
if !reflect.DeepEqual(commit, want) {
t.Errorf("Git.CreateCommit returned %+v, want %+v", commit, want)
}
}
func TestGitService_CreateCommit_invalidOwner(t *testing.T) {
_, _, err := client.Git.CreateCommit("%", "%", nil)
testURLParseError(t, err)
}

162
vendor/github.com/google/go-github/github/git_refs.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,162 @@
// 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"
"strings"
)
// Reference represents a GitHub reference.
type Reference struct {
Ref *string `json:"ref"`
URL *string `json:"url"`
Object *GitObject `json:"object"`
}
func (r Reference) String() string {
return Stringify(r)
}
// GitObject represents a Git object.
type GitObject struct {
Type *string `json:"type"`
SHA *string `json:"sha"`
URL *string `json:"url"`
}
func (o GitObject) String() string {
return Stringify(o)
}
// createRefRequest represents the payload for creating a reference.
type createRefRequest struct {
Ref *string `json:"ref"`
SHA *string `json:"sha"`
}
// updateRefRequest represents the payload for updating a reference.
type updateRefRequest struct {
SHA *string `json:"sha"`
Force *bool `json:"force"`
}
// GetRef fetches the Reference object for a given Git ref.
//
// GitHub API docs: http://developer.github.com/v3/git/refs/#get-a-reference
func (s *GitService) GetRef(owner string, repo string, ref string) (*Reference, *Response, error) {
ref = strings.TrimPrefix(ref, "refs/")
u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, ref)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
r := new(Reference)
resp, err := s.client.Do(req, r)
if err != nil {
return nil, resp, err
}
return r, resp, err
}
// ReferenceListOptions specifies optional parameters to the
// GitService.ListRefs method.
type ReferenceListOptions struct {
Type string `url:"-"`
ListOptions
}
// ListRefs lists all refs in a repository.
//
// GitHub API docs: http://developer.github.com/v3/git/refs/#get-all-references
func (s *GitService) ListRefs(owner, repo string, opt *ReferenceListOptions) ([]Reference, *Response, error) {
var u string
if opt != nil && opt.Type != "" {
u = fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, opt.Type)
} else {
u = fmt.Sprintf("repos/%v/%v/git/refs", owner, repo)
}
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
}
var rs []Reference
resp, err := s.client.Do(req, &rs)
if err != nil {
return nil, resp, err
}
return rs, resp, err
}
// CreateRef creates a new ref in a repository.
//
// GitHub API docs: http://developer.github.com/v3/git/refs/#create-a-reference
func (s *GitService) CreateRef(owner string, repo string, ref *Reference) (*Reference, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/git/refs", owner, repo)
req, err := s.client.NewRequest("POST", u, &createRefRequest{
// back-compat with previous behavior that didn't require 'refs/' prefix
Ref: String("refs/" + strings.TrimPrefix(*ref.Ref, "refs/")),
SHA: ref.Object.SHA,
})
if err != nil {
return nil, nil, err
}
r := new(Reference)
resp, err := s.client.Do(req, r)
if err != nil {
return nil, resp, err
}
return r, resp, err
}
// UpdateRef updates an existing ref in a repository.
//
// GitHub API docs: http://developer.github.com/v3/git/refs/#update-a-reference
func (s *GitService) UpdateRef(owner string, repo string, ref *Reference, force bool) (*Reference, *Response, error) {
refPath := strings.TrimPrefix(*ref.Ref, "refs/")
u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, refPath)
req, err := s.client.NewRequest("PATCH", u, &updateRefRequest{
SHA: ref.Object.SHA,
Force: &force,
})
if err != nil {
return nil, nil, err
}
r := new(Reference)
resp, err := s.client.Do(req, r)
if err != nil {
return nil, resp, err
}
return r, resp, err
}
// DeleteRef deletes a ref from a repository.
//
// GitHub API docs: http://developer.github.com/v3/git/refs/#delete-a-reference
func (s *GitService) DeleteRef(owner string, repo string, ref string) (*Response, error) {
ref = strings.TrimPrefix(ref, "refs/")
u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, ref)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}

280
vendor/github.com/google/go-github/github/git_refs_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,280 @@
// 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 (
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
)
func TestGitService_GetRef(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/git/refs/heads/b", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `
{
"ref": "refs/heads/b",
"url": "https://api.github.com/repos/o/r/git/refs/heads/b",
"object": {
"type": "commit",
"sha": "aa218f56b14c9653891f9e74264a383fa43fefbd",
"url": "https://api.github.com/repos/o/r/git/commits/aa218f56b14c9653891f9e74264a383fa43fefbd"
}
}`)
})
ref, _, err := client.Git.GetRef("o", "r", "refs/heads/b")
if err != nil {
t.Errorf("Git.GetRef returned error: %v", err)
}
want := &Reference{
Ref: String("refs/heads/b"),
URL: String("https://api.github.com/repos/o/r/git/refs/heads/b"),
Object: &GitObject{
Type: String("commit"),
SHA: String("aa218f56b14c9653891f9e74264a383fa43fefbd"),
URL: String("https://api.github.com/repos/o/r/git/commits/aa218f56b14c9653891f9e74264a383fa43fefbd"),
},
}
if !reflect.DeepEqual(ref, want) {
t.Errorf("Git.GetRef returned %+v, want %+v", ref, want)
}
// without 'refs/' prefix
if _, _, err := client.Git.GetRef("o", "r", "heads/b"); err != nil {
t.Errorf("Git.GetRef returned error: %v", err)
}
}
func TestGitService_ListRefs(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/git/refs", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `
[
{
"ref": "refs/heads/branchA",
"url": "https://api.github.com/repos/o/r/git/refs/heads/branchA",
"object": {
"type": "commit",
"sha": "aa218f56b14c9653891f9e74264a383fa43fefbd",
"url": "https://api.github.com/repos/o/r/git/commits/aa218f56b14c9653891f9e74264a383fa43fefbd"
}
},
{
"ref": "refs/heads/branchB",
"url": "https://api.github.com/repos/o/r/git/refs/heads/branchB",
"object": {
"type": "commit",
"sha": "aa218f56b14c9653891f9e74264a383fa43fefbd",
"url": "https://api.github.com/repos/o/r/git/commits/aa218f56b14c9653891f9e74264a383fa43fefbd"
}
}
]`)
})
refs, _, err := client.Git.ListRefs("o", "r", nil)
if err != nil {
t.Errorf("Git.ListRefs returned error: %v", err)
}
want := []Reference{
{
Ref: String("refs/heads/branchA"),
URL: String("https://api.github.com/repos/o/r/git/refs/heads/branchA"),
Object: &GitObject{
Type: String("commit"),
SHA: String("aa218f56b14c9653891f9e74264a383fa43fefbd"),
URL: String("https://api.github.com/repos/o/r/git/commits/aa218f56b14c9653891f9e74264a383fa43fefbd"),
},
},
{
Ref: String("refs/heads/branchB"),
URL: String("https://api.github.com/repos/o/r/git/refs/heads/branchB"),
Object: &GitObject{
Type: String("commit"),
SHA: String("aa218f56b14c9653891f9e74264a383fa43fefbd"),
URL: String("https://api.github.com/repos/o/r/git/commits/aa218f56b14c9653891f9e74264a383fa43fefbd"),
},
},
}
if !reflect.DeepEqual(refs, want) {
t.Errorf("Git.ListRefs returned %+v, want %+v", refs, want)
}
}
func TestGitService_ListRefs_options(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/git/refs/t", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{"page": "2"})
fmt.Fprint(w, `[{"ref": "r"}]`)
})
opt := &ReferenceListOptions{Type: "t", ListOptions: ListOptions{Page: 2}}
refs, _, err := client.Git.ListRefs("o", "r", opt)
if err != nil {
t.Errorf("Git.ListRefs returned error: %v", err)
}
want := []Reference{{Ref: String("r")}}
if !reflect.DeepEqual(refs, want) {
t.Errorf("Git.ListRefs returned %+v, want %+v", refs, want)
}
}
func TestGitService_CreateRef(t *testing.T) {
setup()
defer teardown()
args := &createRefRequest{
Ref: String("refs/heads/b"),
SHA: String("aa218f56b14c9653891f9e74264a383fa43fefbd"),
}
mux.HandleFunc("/repos/o/r/git/refs", func(w http.ResponseWriter, r *http.Request) {
v := new(createRefRequest)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "POST")
if !reflect.DeepEqual(v, args) {
t.Errorf("Request body = %+v, want %+v", v, args)
}
fmt.Fprint(w, `
{
"ref": "refs/heads/b",
"url": "https://api.github.com/repos/o/r/git/refs/heads/b",
"object": {
"type": "commit",
"sha": "aa218f56b14c9653891f9e74264a383fa43fefbd",
"url": "https://api.github.com/repos/o/r/git/commits/aa218f56b14c9653891f9e74264a383fa43fefbd"
}
}`)
})
ref, _, err := client.Git.CreateRef("o", "r", &Reference{
Ref: String("refs/heads/b"),
Object: &GitObject{
SHA: String("aa218f56b14c9653891f9e74264a383fa43fefbd"),
},
})
if err != nil {
t.Errorf("Git.CreateRef returned error: %v", err)
}
want := &Reference{
Ref: String("refs/heads/b"),
URL: String("https://api.github.com/repos/o/r/git/refs/heads/b"),
Object: &GitObject{
Type: String("commit"),
SHA: String("aa218f56b14c9653891f9e74264a383fa43fefbd"),
URL: String("https://api.github.com/repos/o/r/git/commits/aa218f56b14c9653891f9e74264a383fa43fefbd"),
},
}
if !reflect.DeepEqual(ref, want) {
t.Errorf("Git.CreateRef returned %+v, want %+v", ref, want)
}
// without 'refs/' prefix
_, _, err = client.Git.CreateRef("o", "r", &Reference{
Ref: String("heads/b"),
Object: &GitObject{
SHA: String("aa218f56b14c9653891f9e74264a383fa43fefbd"),
},
})
if err != nil {
t.Errorf("Git.CreateRef returned error: %v", err)
}
}
func TestGitService_UpdateRef(t *testing.T) {
setup()
defer teardown()
args := &updateRefRequest{
SHA: String("aa218f56b14c9653891f9e74264a383fa43fefbd"),
Force: Bool(true),
}
mux.HandleFunc("/repos/o/r/git/refs/heads/b", func(w http.ResponseWriter, r *http.Request) {
v := new(updateRefRequest)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PATCH")
if !reflect.DeepEqual(v, args) {
t.Errorf("Request body = %+v, want %+v", v, args)
}
fmt.Fprint(w, `
{
"ref": "refs/heads/b",
"url": "https://api.github.com/repos/o/r/git/refs/heads/b",
"object": {
"type": "commit",
"sha": "aa218f56b14c9653891f9e74264a383fa43fefbd",
"url": "https://api.github.com/repos/o/r/git/commits/aa218f56b14c9653891f9e74264a383fa43fefbd"
}
}`)
})
ref, _, err := client.Git.UpdateRef("o", "r", &Reference{
Ref: String("refs/heads/b"),
Object: &GitObject{SHA: String("aa218f56b14c9653891f9e74264a383fa43fefbd")},
}, true)
if err != nil {
t.Errorf("Git.UpdateRef returned error: %v", err)
}
want := &Reference{
Ref: String("refs/heads/b"),
URL: String("https://api.github.com/repos/o/r/git/refs/heads/b"),
Object: &GitObject{
Type: String("commit"),
SHA: String("aa218f56b14c9653891f9e74264a383fa43fefbd"),
URL: String("https://api.github.com/repos/o/r/git/commits/aa218f56b14c9653891f9e74264a383fa43fefbd"),
},
}
if !reflect.DeepEqual(ref, want) {
t.Errorf("Git.UpdateRef returned %+v, want %+v", ref, want)
}
// without 'refs/' prefix
_, _, err = client.Git.UpdateRef("o", "r", &Reference{
Ref: String("heads/b"),
Object: &GitObject{SHA: String("aa218f56b14c9653891f9e74264a383fa43fefbd")},
}, true)
if err != nil {
t.Errorf("Git.UpdateRef returned error: %v", err)
}
}
func TestGitService_DeleteRef(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/git/refs/heads/b", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
})
_, err := client.Git.DeleteRef("o", "r", "refs/heads/b")
if err != nil {
t.Errorf("Git.DeleteRef returned error: %v", err)
}
// without 'refs/' prefix
if _, err := client.Git.DeleteRef("o", "r", "heads/b"); err != nil {
t.Errorf("Git.DeleteRef returned error: %v", err)
}
}

73
vendor/github.com/google/go-github/github/git_tags.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,73 @@
// 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"
)
// Tag represents a tag object.
type Tag struct {
Tag *string `json:"tag,omitempty"`
SHA *string `json:"sha,omitempty"`
URL *string `json:"url,omitempty"`
Message *string `json:"message,omitempty"`
Tagger *CommitAuthor `json:"tagger,omitempty"`
Object *GitObject `json:"object,omitempty"`
}
// createTagRequest represents the body of a CreateTag request. This is mostly
// identical to Tag with the exception that the object SHA and Type are
// top-level fields, rather than being nested inside a JSON object.
type createTagRequest struct {
Tag *string `json:"tag,omitempty"`
Message *string `json:"message,omitempty"`
Object *string `json:"object,omitempty"`
Type *string `json:"type,omitempty"`
Tagger *CommitAuthor `json:"tagger,omitempty"`
}
// GetTag fetchs a tag from a repo given a SHA.
//
// GitHub API docs: http://developer.github.com/v3/git/tags/#get-a-tag
func (s *GitService) GetTag(owner string, repo string, sha string) (*Tag, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/git/tags/%v", owner, repo, sha)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
tag := new(Tag)
resp, err := s.client.Do(req, tag)
return tag, resp, err
}
// CreateTag creates a tag object.
//
// GitHub API docs: http://developer.github.com/v3/git/tags/#create-a-tag-object
func (s *GitService) CreateTag(owner string, repo string, tag *Tag) (*Tag, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/git/tags", owner, repo)
// convert Tag into a createTagRequest
tagRequest := &createTagRequest{
Tag: tag.Tag,
Message: tag.Message,
Tagger: tag.Tagger,
}
if tag.Object != nil {
tagRequest.Object = tag.Object.SHA
tagRequest.Type = tag.Object.Type
}
req, err := s.client.NewRequest("POST", u, tagRequest)
if err != nil {
return nil, nil, err
}
t := new(Tag)
resp, err := s.client.Do(req, t)
return t, resp, err
}

68
vendor/github.com/google/go-github/github/git_tags_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,68 @@
// 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 (
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
)
func TestGitService_GetTag(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/git/tags/s", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"tag": "t"}`)
})
tag, _, err := client.Git.GetTag("o", "r", "s")
if err != nil {
t.Errorf("Git.GetTag returned error: %v", err)
}
want := &Tag{Tag: String("t")}
if !reflect.DeepEqual(tag, want) {
t.Errorf("Git.GetTag returned %+v, want %+v", tag, want)
}
}
func TestGitService_CreateTag(t *testing.T) {
setup()
defer teardown()
input := &createTagRequest{Tag: String("t"), Object: String("s")}
mux.HandleFunc("/repos/o/r/git/tags", func(w http.ResponseWriter, r *http.Request) {
v := new(createTagRequest)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "POST")
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `{"tag": "t"}`)
})
tag, _, err := client.Git.CreateTag("o", "r", &Tag{
Tag: input.Tag,
Object: &GitObject{SHA: input.Object},
})
if err != nil {
t.Errorf("Git.CreateTag returned error: %v", err)
}
want := &Tag{Tag: String("t")}
if !reflect.DeepEqual(tag, want) {
t.Errorf("Git.GetTag returned %+v, want %+v", tag, want)
}
}

89
vendor/github.com/google/go-github/github/git_trees.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,89 @@
// 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"
// Tree represents a GitHub tree.
type Tree struct {
SHA *string `json:"sha,omitempty"`
Entries []TreeEntry `json:"tree,omitempty"`
}
func (t Tree) String() string {
return Stringify(t)
}
// TreeEntry represents the contents of a tree structure. TreeEntry can
// represent either a blob, a commit (in the case of a submodule), or another
// tree.
type TreeEntry struct {
SHA *string `json:"sha,omitempty"`
Path *string `json:"path,omitempty"`
Mode *string `json:"mode,omitempty"`
Type *string `json:"type,omitempty"`
Size *int `json:"size,omitempty"`
Content *string `json:"content,omitempty"`
}
func (t TreeEntry) String() string {
return Stringify(t)
}
// GetTree fetches the Tree object for a given sha hash from a repository.
//
// GitHub API docs: http://developer.github.com/v3/git/trees/#get-a-tree
func (s *GitService) GetTree(owner string, repo string, sha string, recursive bool) (*Tree, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/git/trees/%v", owner, repo, sha)
if recursive {
u += "?recursive=1"
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
t := new(Tree)
resp, err := s.client.Do(req, t)
if err != nil {
return nil, resp, err
}
return t, resp, err
}
// createTree represents the body of a CreateTree request.
type createTree struct {
BaseTree string `json:"base_tree,omitempty"`
Entries []TreeEntry `json:"tree"`
}
// CreateTree creates a new tree in a repository. If both a tree and a nested
// path modifying that tree are specified, it will overwrite the contents of
// that tree with the new path contents and write a new tree out.
//
// GitHub API docs: http://developer.github.com/v3/git/trees/#create-a-tree
func (s *GitService) CreateTree(owner string, repo string, baseTree string, entries []TreeEntry) (*Tree, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/git/trees", owner, repo)
body := &createTree{
BaseTree: baseTree,
Entries: entries,
}
req, err := s.client.NewRequest("POST", u, body)
if err != nil {
return nil, nil, err
}
t := new(Tree)
resp, err := s.client.Do(req, t)
if err != nil {
return nil, resp, err
}
return t, resp, err
}

189
vendor/github.com/google/go-github/github/git_trees_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,189 @@
// 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 (
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
)
func TestGitService_GetTree(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/git/trees/s", func(w http.ResponseWriter, r *http.Request) {
if m := "GET"; m != r.Method {
t.Errorf("Request method = %v, want %v", r.Method, m)
}
fmt.Fprint(w, `{
"sha": "s",
"tree": [ { "type": "blob" } ]
}`)
})
tree, _, err := client.Git.GetTree("o", "r", "s", true)
if err != nil {
t.Errorf("Git.GetTree returned error: %v", err)
}
want := Tree{
SHA: String("s"),
Entries: []TreeEntry{
{
Type: String("blob"),
},
},
}
if !reflect.DeepEqual(*tree, want) {
t.Errorf("Tree.Get returned %+v, want %+v", *tree, want)
}
}
func TestGitService_GetTree_invalidOwner(t *testing.T) {
_, _, err := client.Git.GetTree("%", "%", "%", false)
testURLParseError(t, err)
}
func TestGitService_CreateTree(t *testing.T) {
setup()
defer teardown()
input := []TreeEntry{
{
Path: String("file.rb"),
Mode: String("100644"),
Type: String("blob"),
SHA: String("7c258a9869f33c1e1e1f74fbb32f07c86cb5a75b"),
},
}
mux.HandleFunc("/repos/o/r/git/trees", func(w http.ResponseWriter, r *http.Request) {
v := new(createTree)
json.NewDecoder(r.Body).Decode(v)
if m := "POST"; m != r.Method {
t.Errorf("Request method = %v, want %v", r.Method, m)
}
want := &createTree{
BaseTree: "b",
Entries: input,
}
if !reflect.DeepEqual(v, want) {
t.Errorf("Git.CreateTree request body: %+v, want %+v", v, want)
}
fmt.Fprint(w, `{
"sha": "cd8274d15fa3ae2ab983129fb037999f264ba9a7",
"tree": [
{
"path": "file.rb",
"mode": "100644",
"type": "blob",
"size": 132,
"sha": "7c258a9869f33c1e1e1f74fbb32f07c86cb5a75b"
}
]
}`)
})
tree, _, err := client.Git.CreateTree("o", "r", "b", input)
if err != nil {
t.Errorf("Git.CreateTree returned error: %v", err)
}
want := Tree{
String("cd8274d15fa3ae2ab983129fb037999f264ba9a7"),
[]TreeEntry{
{
Path: String("file.rb"),
Mode: String("100644"),
Type: String("blob"),
Size: Int(132),
SHA: String("7c258a9869f33c1e1e1f74fbb32f07c86cb5a75b"),
},
},
}
if !reflect.DeepEqual(*tree, want) {
t.Errorf("Git.CreateTree returned %+v, want %+v", *tree, want)
}
}
func TestGitService_CreateTree_Content(t *testing.T) {
setup()
defer teardown()
input := []TreeEntry{
{
Path: String("content.md"),
Mode: String("100644"),
Content: String("file content"),
},
}
mux.HandleFunc("/repos/o/r/git/trees", func(w http.ResponseWriter, r *http.Request) {
v := new(createTree)
json.NewDecoder(r.Body).Decode(v)
if m := "POST"; m != r.Method {
t.Errorf("Request method = %v, want %v", r.Method, m)
}
want := &createTree{
BaseTree: "b",
Entries: input,
}
if !reflect.DeepEqual(v, want) {
t.Errorf("Git.CreateTree request body: %+v, want %+v", v, want)
}
fmt.Fprint(w, `{
"sha": "5c6780ad2c68743383b740fd1dab6f6a33202b11",
"url": "https://api.github.com/repos/o/r/git/trees/5c6780ad2c68743383b740fd1dab6f6a33202b11",
"tree": [
{
"mode": "100644",
"type": "blob",
"sha": "aad8feacf6f8063150476a7b2bd9770f2794c08b",
"path": "content.md",
"size": 12,
"url": "https://api.github.com/repos/o/r/git/blobs/aad8feacf6f8063150476a7b2bd9770f2794c08b"
}
]
}`)
})
tree, _, err := client.Git.CreateTree("o", "r", "b", input)
if err != nil {
t.Errorf("Git.CreateTree returned error: %v", err)
}
want := Tree{
String("5c6780ad2c68743383b740fd1dab6f6a33202b11"),
[]TreeEntry{
{
Path: String("content.md"),
Mode: String("100644"),
Type: String("blob"),
Size: Int(12),
SHA: String("aad8feacf6f8063150476a7b2bd9770f2794c08b"),
},
},
}
if !reflect.DeepEqual(*tree, want) {
t.Errorf("Git.CreateTree returned %+v, want %+v", *tree, want)
}
}
func TestGitService_CreateTree_invalidOwner(t *testing.T) {
_, _, err := client.Git.CreateTree("%", "%", "", nil)
testURLParseError(t, err)
}

588
vendor/github.com/google/go-github/github/github.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,588 @@
// 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 (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"reflect"
"strconv"
"strings"
"time"
"github.com/google/go-querystring/query"
)
const (
libraryVersion = "0.1"
defaultBaseURL = "https://api.github.com/"
uploadBaseURL = "https://uploads.github.com/"
userAgent = "go-github/" + libraryVersion
headerRateLimit = "X-RateLimit-Limit"
headerRateRemaining = "X-RateLimit-Remaining"
headerRateReset = "X-RateLimit-Reset"
mediaTypeV3 = "application/vnd.github.v3+json"
defaultMediaType = "application/octet-stream"
// Media Type values to access preview APIs
// https://developer.github.com/changes/2015-03-09-licenses-api/
mediaTypeLicensesPreview = "application/vnd.github.drax-preview+json"
// https://developer.github.com/changes/2014-12-09-new-attributes-for-stars-api/
mediaTypeStarringPreview = "application/vnd.github.v3.star+json"
// 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"
)
// A Client manages communication with the GitHub API.
type Client struct {
// HTTP client used to communicate with the API.
client *http.Client
// Base URL for API requests. Defaults to the public GitHub API, but can be
// set to a domain endpoint to use with GitHub Enterprise. BaseURL should
// always be specified with a trailing slash.
BaseURL *url.URL
// Base URL for uploading files.
UploadURL *url.URL
// 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 RateLimits() to check the
// current rate.
Rate Rate
// Services used for talking to different parts of the GitHub API.
Activity *ActivityService
Gists *GistsService
Git *GitService
Gitignores *GitignoresService
Issues *IssuesService
Organizations *OrganizationsService
PullRequests *PullRequestsService
Repositories *RepositoriesService
Search *SearchService
Users *UsersService
Licenses *LicensesService
}
// ListOptions specifies the optional parameters to various List methods that
// support pagination.
type ListOptions struct {
// For paginated result sets, page of results to retrieve.
Page int `url:"page,omitempty"`
// For paginated result sets, the number of results to include per page.
PerPage int `url:"per_page,omitempty"`
}
// UploadOptions specifies the parameters to methods that support uploads.
type UploadOptions struct {
Name string `url:"name,omitempty"`
}
// 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) {
v := reflect.ValueOf(opt)
if v.Kind() == reflect.Ptr && v.IsNil() {
return s, nil
}
u, err := url.Parse(s)
if err != nil {
return s, err
}
qs, err := query.Values(opt)
if err != nil {
return s, err
}
u.RawQuery = qs.Encode()
return u.String(), nil
}
// NewClient returns a new GitHub API client. If a nil httpClient is
// provided, http.DefaultClient will be used. To use API methods which require
// authentication, provide an http.Client that will perform the authentication
// for you (such as that provided by the golang.org/x/oauth2 library).
func NewClient(httpClient *http.Client) *Client {
if httpClient == nil {
httpClient = http.DefaultClient
}
baseURL, _ := url.Parse(defaultBaseURL)
uploadURL, _ := url.Parse(uploadBaseURL)
c := &Client{client: httpClient, BaseURL: baseURL, UserAgent: userAgent, UploadURL: uploadURL}
c.Activity = &ActivityService{client: c}
c.Gists = &GistsService{client: c}
c.Git = &GitService{client: c}
c.Gitignores = &GitignoresService{client: c}
c.Issues = &IssuesService{client: c}
c.Organizations = &OrganizationsService{client: c}
c.PullRequests = &PullRequestsService{client: c}
c.Repositories = &RepositoriesService{client: c}
c.Search = &SearchService{client: c}
c.Users = &UsersService{client: c}
c.Licenses = &LicensesService{client: c}
return c
}
// NewRequest creates an API request. A relative URL can be provided in urlStr,
// in which case it is resolved relative to the BaseURL of the Client.
// Relative URLs should always be specified without a preceding slash. If
// specified, the value pointed to by body is JSON encoded and included as the
// request body.
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) {
rel, err := url.Parse(urlStr)
if err != nil {
return nil, err
}
u := c.BaseURL.ResolveReference(rel)
var buf io.ReadWriter
if body != nil {
buf = new(bytes.Buffer)
err := json.NewEncoder(buf).Encode(body)
if err != nil {
return nil, err
}
}
req, err := http.NewRequest(method, u.String(), buf)
if err != nil {
return nil, err
}
req.Header.Add("Accept", mediaTypeV3)
if c.UserAgent != "" {
req.Header.Add("User-Agent", c.UserAgent)
}
return req, nil
}
// NewUploadRequest creates an upload request. A relative URL can be provided in
// urlStr, in which case it is resolved relative to the UploadURL of the Client.
// Relative URLs should always be specified without a preceding slash.
func (c *Client) NewUploadRequest(urlStr string, reader io.Reader, size int64, mediaType string) (*http.Request, error) {
rel, err := url.Parse(urlStr)
if err != nil {
return nil, err
}
u := c.UploadURL.ResolveReference(rel)
req, err := http.NewRequest("POST", u.String(), reader)
if err != nil {
return nil, err
}
req.ContentLength = size
if len(mediaType) == 0 {
mediaType = defaultMediaType
}
req.Header.Add("Content-Type", mediaType)
req.Header.Add("Accept", mediaTypeV3)
req.Header.Add("User-Agent", c.UserAgent)
return req, nil
}
// Response is a GitHub API response. This wraps the standard http.Response
// returned from GitHub and provides convenient access to things like
// pagination links.
type Response struct {
*http.Response
// These fields provide the page values for paginating through a set of
// results. Any or all of these may be set to the zero value for
// responses that are not part of a paginated set, or for which there
// are no additional pages.
NextPage int
PrevPage int
FirstPage int
LastPage int
Rate
}
// newResponse creates a new Response for the provided http.Response.
func newResponse(r *http.Response) *Response {
response := &Response{Response: r}
response.populatePageValues()
response.populateRate()
return response
}
// populatePageValues parses the HTTP Link response headers and populates the
// various pagination link values in the Reponse.
func (r *Response) populatePageValues() {
if links, ok := r.Response.Header["Link"]; ok && len(links) > 0 {
for _, link := range strings.Split(links[0], ",") {
segments := strings.Split(strings.TrimSpace(link), ";")
// link must at least have href and rel
if len(segments) < 2 {
continue
}
// ensure href is properly formatted
if !strings.HasPrefix(segments[0], "<") || !strings.HasSuffix(segments[0], ">") {
continue
}
// try to pull out page parameter
url, err := url.Parse(segments[0][1 : len(segments[0])-1])
if err != nil {
continue
}
page := url.Query().Get("page")
if page == "" {
continue
}
for _, segment := range segments[1:] {
switch strings.TrimSpace(segment) {
case `rel="next"`:
r.NextPage, _ = strconv.Atoi(page)
case `rel="prev"`:
r.PrevPage, _ = strconv.Atoi(page)
case `rel="first"`:
r.FirstPage, _ = strconv.Atoi(page)
case `rel="last"`:
r.LastPage, _ = strconv.Atoi(page)
}
}
}
}
}
// populateRate parses the rate related headers and populates the response Rate.
func (r *Response) populateRate() {
if limit := r.Header.Get(headerRateLimit); limit != "" {
r.Rate.Limit, _ = strconv.Atoi(limit)
}
if remaining := r.Header.Get(headerRateRemaining); remaining != "" {
r.Rate.Remaining, _ = strconv.Atoi(remaining)
}
if reset := r.Header.Get(headerRateReset); reset != "" {
if v, _ := strconv.ParseInt(reset, 10, 64); v != 0 {
r.Rate.Reset = Timestamp{time.Unix(v, 0)}
}
}
}
// 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
// interface, the raw response body will be written to v, without attempting to
// first decode it.
func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
resp, err := c.client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
response := newResponse(resp)
c.Rate = response.Rate
err = CheckResponse(resp)
if err != nil {
// even though there was an error, we still return the response
// in case the caller wants to inspect it further
return response, err
}
if v != nil {
if w, ok := v.(io.Writer); ok {
io.Copy(w, resp.Body)
} else {
err = json.NewDecoder(resp.Body).Decode(v)
}
}
return response, err
}
/*
An ErrorResponse reports one or more errors caused by an API request.
GitHub API docs: http://developer.github.com/v3/#client-errors
*/
type ErrorResponse struct {
Response *http.Response // HTTP response that caused this error
Message string `json:"message"` // error message
Errors []Error `json:"errors"` // more detail on individual errors
}
func (r *ErrorResponse) Error() string {
return fmt.Sprintf("%v %v: %d %v %+v",
r.Response.Request.Method, sanitizeURL(r.Response.Request.URL),
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.
func sanitizeURL(uri *url.URL) *url.URL {
if uri == nil {
return nil
}
params := uri.Query()
if len(params.Get("client_secret")) > 0 {
params.Set("client_secret", "REDACTED")
uri.RawQuery = params.Encode()
}
return uri
}
/*
An Error reports more details on an individual error in an ErrorResponse.
These are the possible validation error codes:
missing:
resource does not exist
missing_field:
a required field on a resource has not been set
invalid:
the formatting of a field is invalid
already_exists:
another resource has the same valid as this field
GitHub API docs: http://developer.github.com/v3/#client-errors
*/
type Error struct {
Resource string `json:"resource"` // resource on which the error occurred
Field string `json:"field"` // field on which the error occurred
Code string `json:"code"` // validation error code
}
func (e *Error) Error() string {
return fmt.Sprintf("%v error caused by %v field on %v resource",
e.Code, e.Field, e.Resource)
}
// CheckResponse checks the API response for errors, and returns them if
// present. A response is considered an error if it has a status code outside
// the 200 range. API error responses are expected to have either no response
// body, or a JSON response body that maps to ErrorResponse. Any other
// response body will be silently ignored.
func CheckResponse(r *http.Response) error {
if c := r.StatusCode; 200 <= c && c <= 299 {
return nil
}
errorResponse := &ErrorResponse{Response: r}
data, err := ioutil.ReadAll(r.Body)
if err == nil && data != nil {
json.Unmarshal(data, errorResponse)
}
return errorResponse
}
// parseBoolResponse determines the boolean result from a GitHub API response.
// Several GitHub API methods return boolean responses indicated by the HTTP
// status code in the response (true indicated by a 204, false indicated by a
// 404). This helper function will determine that result and hide the 404
// error if present. Any other error will be returned through as-is.
func parseBoolResponse(err error) (bool, error) {
if err == nil {
return true, nil
}
if err, ok := err.(*ErrorResponse); ok && err.Response.StatusCode == http.StatusNotFound {
// Simply false. In this one case, we do not pass the error through.
return false, nil
}
// some other real error occurred
return false, err
}
// Rate represents the rate limit for the current client.
type Rate struct {
// The number of requests per hour the client is currently limited to.
Limit int `json:"limit"`
// The number of remaining requests the client can make this hour.
Remaining int `json:"remaining"`
// The time at which the current rate limit will reset.
Reset Timestamp `json:"reset"`
}
func (r Rate) String() string {
return Stringify(r)
}
// RateLimits represents the rate limits for the current client.
type RateLimits struct {
// The rate limit for non-search API requests. Unauthenticated
// requests are limited to 60 per hour. Authenticated requests are
// limited to 5,000 per hour.
Core *Rate `json:"core"`
// The rate limit for search API requests. Unauthenticated requests
// are limited to 5 requests per minutes. Authenticated requests are
// limited to 20 per minute.
//
// GitHub API docs: https://developer.github.com/v3/search/#rate-limit
Search *Rate `json:"search"`
}
func (r RateLimits) String() string {
return Stringify(r)
}
// RateLimit is deprecated. Use RateLimits instead.
func (c *Client) RateLimit() (*Rate, *Response, error) {
limits, resp, err := c.RateLimits()
if limits == nil {
return nil, nil, err
}
return limits.Core, resp, err
}
// RateLimits returns the rate limits for the current client.
func (c *Client) RateLimits() (*RateLimits, *Response, error) {
req, err := c.NewRequest("GET", "rate_limit", nil)
if err != nil {
return nil, nil, err
}
response := new(struct {
Resources *RateLimits `json:"resources"`
})
resp, err := c.Do(req, response)
if err != nil {
return nil, nil, err
}
return response.Resources, resp, err
}
/*
UnauthenticatedRateLimitedTransport allows you to make unauthenticated calls
that need to use a higher rate limit associated with your OAuth application.
t := &github.UnauthenticatedRateLimitedTransport{
ClientID: "your app's client ID",
ClientSecret: "your app's client secret",
}
client := github.NewClient(t.Client())
This will append the querystring params client_id=xxx&client_secret=yyy to all
requests.
See http://developer.github.com/v3/#unauthenticated-rate-limited-requests for
more information.
*/
type UnauthenticatedRateLimitedTransport struct {
// ClientID is the GitHub OAuth client ID of the current application, which
// can be found by selecting its entry in the list at
// https://github.com/settings/applications.
ClientID string
// ClientSecret is the GitHub OAuth client secret of the current
// application.
ClientSecret string
// 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 *UnauthenticatedRateLimitedTransport) RoundTrip(req *http.Request) (*http.Response, error) {
if t.ClientID == "" {
return nil, errors.New("t.ClientID is empty")
}
if t.ClientSecret == "" {
return nil, errors.New("t.ClientSecret is empty")
}
// To set extra querystring params, we must make a copy of the Request so
// that we don't modify the Request we were given. This is required by the
// specification of http.RoundTripper.
req = cloneRequest(req)
q := req.URL.Query()
q.Set("client_id", t.ClientID)
q.Set("client_secret", t.ClientSecret)
req.URL.RawQuery = q.Encode()
// Make the HTTP request.
return t.transport().RoundTrip(req)
}
// Client returns an *http.Client that makes requests which are subject to the
// rate limit of your OAuth application.
func (t *UnauthenticatedRateLimitedTransport) Client() *http.Client {
return &http.Client{Transport: t}
}
func (t *UnauthenticatedRateLimitedTransport) 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 {
// shallow copy of the struct
r2 := new(http.Request)
*r2 = *r
// deep copy of the Header
r2.Header = make(http.Header)
for k, s := range r.Header {
r2.Header[k] = s
}
return r2
}
// Bool is a helper routine that allocates a new bool value
// to store v and returns a pointer to it.
func Bool(v bool) *bool {
p := new(bool)
*p = v
return p
}
// Int is a helper routine that allocates a new int32 value
// to store v and returns a pointer to it, but unlike Int32
// its argument value is an int.
func Int(v int) *int {
p := new(int)
*p = v
return p
}
// String is a helper routine that allocates a new string value
// to store v and returns a pointer to it.
func String(v string) *string {
p := new(string)
*p = v
return p
}

679
vendor/github.com/google/go-github/github/github_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,679 @@
// 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 (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"os"
"path"
"reflect"
"strings"
"testing"
"time"
)
var (
// mux is the HTTP request multiplexer used with the test server.
mux *http.ServeMux
// client is the GitHub client being tested.
client *Client
// server is a test HTTP server used to provide mock API responses.
server *httptest.Server
)
// setup sets up a test HTTP server along with a github.Client that is
// configured to talk to that test server. Tests should register handlers on
// mux which provide mock responses for the API method being tested.
func setup() {
// test server
mux = http.NewServeMux()
server = httptest.NewServer(mux)
// github client configured to use test server
client = NewClient(nil)
url, _ := url.Parse(server.URL)
client.BaseURL = url
client.UploadURL = url
}
// teardown closes the test HTTP server.
func teardown() {
server.Close()
}
// openTestFile creates a new file with the given name and content for testing.
// In order to ensure the exact file name, this function will create a new temp
// directory, and create the file in that directory. It is the caller's
// responsibility to remove the directy and its contents when no longer needed.
func openTestFile(name, content string) (file *os.File, dir string, err error) {
dir, err = ioutil.TempDir("", "go-github")
if err != nil {
return nil, dir, err
}
file, err = os.OpenFile(path.Join(dir, name), os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
if err != nil {
return nil, dir, err
}
fmt.Fprint(file, content)
// close and re-open the file to keep file.Stat() happy
file.Close()
file, err = os.Open(file.Name())
if err != nil {
return nil, dir, err
}
return file, dir, err
}
func testMethod(t *testing.T, r *http.Request, want string) {
if got := r.Method; got != want {
t.Errorf("Request method: %v, want %v", got, want)
}
}
type values map[string]string
func testFormValues(t *testing.T, r *http.Request, values values) {
want := url.Values{}
for k, v := range values {
want.Add(k, v)
}
r.ParseForm()
if got := r.Form; !reflect.DeepEqual(got, want) {
t.Errorf("Request parameters: %v, want %v", got, want)
}
}
func testHeader(t *testing.T, r *http.Request, header string, want string) {
if got := r.Header.Get(header); got != want {
t.Errorf("Header.Get(%q) returned %s, want %s", header, got, want)
}
}
func testURLParseError(t *testing.T, err error) {
if err == nil {
t.Errorf("Expected error to be returned")
}
if err, ok := err.(*url.Error); !ok || err.Op != "parse" {
t.Errorf("Expected URL parse error, got %+v", err)
}
}
func testBody(t *testing.T, r *http.Request, want string) {
b, err := ioutil.ReadAll(r.Body)
if err != nil {
t.Errorf("Error reading request body: %v", err)
}
if got := string(b); got != want {
t.Errorf("request Body is %s, want %s", got, want)
}
}
// Helper function to test that a value is marshalled to JSON as expected.
func testJSONMarshal(t *testing.T, v interface{}, want string) {
j, err := json.Marshal(v)
if err != nil {
t.Errorf("Unable to marshal JSON for %v", v)
}
w := new(bytes.Buffer)
err = json.Compact(w, []byte(want))
if err != nil {
t.Errorf("String is not valid json: %s", want)
}
if w.String() != string(j) {
t.Errorf("json.Marshal(%q) returned %s, want %s", v, j, w)
}
// now go the other direction and make sure things unmarshal as expected
u := reflect.ValueOf(v).Interface()
if err := json.Unmarshal([]byte(want), u); err != nil {
t.Errorf("Unable to unmarshal JSON for %v", want)
}
if !reflect.DeepEqual(v, u) {
t.Errorf("json.Unmarshal(%q) returned %s, want %s", want, u, v)
}
}
func TestNewClient(t *testing.T) {
c := NewClient(nil)
if got, want := c.BaseURL.String(), defaultBaseURL; got != want {
t.Errorf("NewClient BaseURL is %v, want %v", got, want)
}
if got, want := c.UserAgent, userAgent; got != want {
t.Errorf("NewClient UserAgent is %v, want %v", got, want)
}
}
func TestNewRequest(t *testing.T) {
c := NewClient(nil)
inURL, outURL := "/foo", defaultBaseURL+"foo"
inBody, outBody := &User{Login: String("l")}, `{"login":"l"}`+"\n"
req, _ := c.NewRequest("GET", inURL, inBody)
// test that relative URL was expanded
if got, want := req.URL.String(), outURL; got != want {
t.Errorf("NewRequest(%q) URL is %v, want %v", inURL, got, want)
}
// test that body was JSON encoded
body, _ := ioutil.ReadAll(req.Body)
if got, want := string(body), outBody; got != want {
t.Errorf("NewRequest(%q) Body is %v, want %v", inBody, got, want)
}
// test that default user-agent is attached to the request
if got, want := req.Header.Get("User-Agent"), c.UserAgent; got != want {
t.Errorf("NewRequest() User-Agent is %v, want %v", got, want)
}
}
func TestNewRequest_invalidJSON(t *testing.T) {
c := NewClient(nil)
type T struct {
A map[int]interface{}
}
_, err := c.NewRequest("GET", "/", &T{})
if err == nil {
t.Error("Expected error to be returned.")
}
if err, ok := err.(*json.UnsupportedTypeError); !ok {
t.Errorf("Expected a JSON error; got %#v.", err)
}
}
func TestNewRequest_badURL(t *testing.T) {
c := NewClient(nil)
_, err := c.NewRequest("GET", ":", nil)
testURLParseError(t, err)
}
// ensure that no User-Agent header is set if the client's UserAgent is empty.
// This caused a problem with Google's internal http client.
func TestNewRequest_emptyUserAgent(t *testing.T) {
c := NewClient(nil)
c.UserAgent = ""
req, err := c.NewRequest("GET", "/", nil)
if err != nil {
t.Fatalf("NewRequest returned unexpected error: %v", err)
}
if _, ok := req.Header["User-Agent"]; ok {
t.Fatal("constructed request contains unexpected User-Agent header")
}
}
// If a nil body is passed to github.NewRequest, make sure that nil is also
// passed to http.NewRequest. In most cases, passing an io.Reader that returns
// no content is fine, since there is no difference between an HTTP request
// body that is an empty string versus one that is not set at all. However in
// certain cases, intermediate systems may treat these differently resulting in
// subtle errors.
func TestNewRequest_emptyBody(t *testing.T) {
c := NewClient(nil)
req, err := c.NewRequest("GET", "/", nil)
if err != nil {
t.Fatalf("NewRequest returned unexpected error: %v", err)
}
if req.Body != nil {
t.Fatalf("constructed request contains a non-nil Body")
}
}
func TestResponse_populatePageValues(t *testing.T) {
r := http.Response{
Header: http.Header{
"Link": {`<https://api.github.com/?page=1>; rel="first",` +
` <https://api.github.com/?page=2>; rel="prev",` +
` <https://api.github.com/?page=4>; rel="next",` +
` <https://api.github.com/?page=5>; rel="last"`,
},
},
}
response := newResponse(&r)
if got, want := response.FirstPage, 1; got != want {
t.Errorf("response.FirstPage: %v, want %v", got, want)
}
if got, want := response.PrevPage, 2; want != got {
t.Errorf("response.PrevPage: %v, want %v", got, want)
}
if got, want := response.NextPage, 4; want != got {
t.Errorf("response.NextPage: %v, want %v", got, want)
}
if got, want := response.LastPage, 5; want != got {
t.Errorf("response.LastPage: %v, want %v", got, want)
}
}
func TestResponse_populatePageValues_invalid(t *testing.T) {
r := http.Response{
Header: http.Header{
"Link": {`<https://api.github.com/?page=1>,` +
`<https://api.github.com/?page=abc>; rel="first",` +
`https://api.github.com/?page=2; rel="prev",` +
`<https://api.github.com/>; rel="next",` +
`<https://api.github.com/?page=>; rel="last"`,
},
},
}
response := newResponse(&r)
if got, want := response.FirstPage, 0; got != want {
t.Errorf("response.FirstPage: %v, want %v", got, want)
}
if got, want := response.PrevPage, 0; got != want {
t.Errorf("response.PrevPage: %v, want %v", got, want)
}
if got, want := response.NextPage, 0; got != want {
t.Errorf("response.NextPage: %v, want %v", got, want)
}
if got, want := response.LastPage, 0; got != want {
t.Errorf("response.LastPage: %v, want %v", got, want)
}
// more invalid URLs
r = http.Response{
Header: http.Header{
"Link": {`<https://api.github.com/%?page=2>; rel="first"`},
},
}
response = newResponse(&r)
if got, want := response.FirstPage, 0; got != want {
t.Errorf("response.FirstPage: %v, want %v", got, want)
}
}
func TestDo(t *testing.T) {
setup()
defer teardown()
type foo struct {
A string
}
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if m := "GET"; m != r.Method {
t.Errorf("Request method = %v, want %v", r.Method, m)
}
fmt.Fprint(w, `{"A":"a"}`)
})
req, _ := client.NewRequest("GET", "/", nil)
body := new(foo)
client.Do(req, body)
want := &foo{"a"}
if !reflect.DeepEqual(body, want) {
t.Errorf("Response body = %v, want %v", body, want)
}
}
func TestDo_httpError(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Bad Request", 400)
})
req, _ := client.NewRequest("GET", "/", nil)
_, err := client.Do(req, nil)
if err == nil {
t.Error("Expected HTTP 400 error.")
}
}
// Test handling of an error caused by the internal http client's Do()
// function. A redirect loop is pretty unlikely to occur within the GitHub
// API, but does allow us to exercise the right code path.
func TestDo_redirectLoop(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/", http.StatusFound)
})
req, _ := client.NewRequest("GET", "/", nil)
_, err := client.Do(req, nil)
if err == nil {
t.Error("Expected error to be returned.")
}
if err, ok := err.(*url.Error); !ok {
t.Errorf("Expected a URL error; got %#v.", err)
}
}
func TestDo_rateLimit(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Add(headerRateLimit, "60")
w.Header().Add(headerRateRemaining, "59")
w.Header().Add(headerRateReset, "1372700873")
})
if got, want := client.Rate.Limit, 0; got != want {
t.Errorf("Client rate limit = %v, want %v", got, want)
}
if got, want := client.Rate.Remaining, 0; got != want {
t.Errorf("Client rate remaining = %v, got %v", got, want)
}
if !client.Rate.Reset.IsZero() {
t.Errorf("Client rate reset not initialized to zero value")
}
req, _ := client.NewRequest("GET", "/", nil)
client.Do(req, nil)
if got, want := client.Rate.Limit, 60; got != want {
t.Errorf("Client rate limit = %v, want %v", got, want)
}
if got, want := client.Rate.Remaining, 59; got != want {
t.Errorf("Client rate remaining = %v, want %v", got, want)
}
reset := time.Date(2013, 7, 1, 17, 47, 53, 0, time.UTC)
if client.Rate.Reset.UTC() != reset {
t.Errorf("Client rate reset = %v, want %v", client.Rate.Reset, reset)
}
}
// ensure rate limit is still parsed, even for error responses
func TestDo_rateLimit_errorResponse(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Add(headerRateLimit, "60")
w.Header().Add(headerRateRemaining, "59")
w.Header().Add(headerRateReset, "1372700873")
http.Error(w, "Bad Request", 400)
})
req, _ := client.NewRequest("GET", "/", nil)
client.Do(req, nil)
if got, want := client.Rate.Limit, 60; got != want {
t.Errorf("Client rate limit = %v, want %v", got, want)
}
if got, want := client.Rate.Remaining, 59; got != want {
t.Errorf("Client rate remaining = %v, want %v", got, want)
}
reset := time.Date(2013, 7, 1, 17, 47, 53, 0, time.UTC)
if client.Rate.Reset.UTC() != reset {
t.Errorf("Client rate reset = %v, want %v", client.Rate.Reset, reset)
}
}
func TestSanitizeURL(t *testing.T) {
tests := []struct {
in, want string
}{
{"/?a=b", "/?a=b"},
{"/?a=b&client_secret=secret", "/?a=b&client_secret=REDACTED"},
{"/?a=b&client_id=id&client_secret=secret", "/?a=b&client_id=id&client_secret=REDACTED"},
}
for _, tt := range tests {
inURL, _ := url.Parse(tt.in)
want, _ := url.Parse(tt.want)
if got := sanitizeURL(inURL); !reflect.DeepEqual(got, want) {
t.Errorf("sanitizeURL(%v) returned %v, want %v", tt.in, got, want)
}
}
}
func TestCheckResponse(t *testing.T) {
res := &http.Response{
Request: &http.Request{},
StatusCode: http.StatusBadRequest,
Body: ioutil.NopCloser(strings.NewReader(`{"message":"m",
"errors": [{"resource": "r", "field": "f", "code": "c"}]}`)),
}
err := CheckResponse(res).(*ErrorResponse)
if err == nil {
t.Errorf("Expected error response.")
}
want := &ErrorResponse{
Response: res,
Message: "m",
Errors: []Error{{Resource: "r", Field: "f", Code: "c"}},
}
if !reflect.DeepEqual(err, want) {
t.Errorf("Error = %#v, want %#v", err, want)
}
}
// ensure that we properly handle API errors that do not contain a response body
func TestCheckResponse_noBody(t *testing.T) {
res := &http.Response{
Request: &http.Request{},
StatusCode: http.StatusBadRequest,
Body: ioutil.NopCloser(strings.NewReader("")),
}
err := CheckResponse(res).(*ErrorResponse)
if err == nil {
t.Errorf("Expected error response.")
}
want := &ErrorResponse{
Response: res,
}
if !reflect.DeepEqual(err, want) {
t.Errorf("Error = %#v, want %#v", err, want)
}
}
func TestParseBooleanResponse_true(t *testing.T) {
result, err := parseBoolResponse(nil)
if err != nil {
t.Errorf("parseBoolResponse returned error: %+v", err)
}
if want := true; result != want {
t.Errorf("parseBoolResponse returned %+v, want: %+v", result, want)
}
}
func TestParseBooleanResponse_false(t *testing.T) {
v := &ErrorResponse{Response: &http.Response{StatusCode: http.StatusNotFound}}
result, err := parseBoolResponse(v)
if err != nil {
t.Errorf("parseBoolResponse returned error: %+v", err)
}
if want := false; result != want {
t.Errorf("parseBoolResponse returned %+v, want: %+v", result, want)
}
}
func TestParseBooleanResponse_error(t *testing.T) {
v := &ErrorResponse{Response: &http.Response{StatusCode: http.StatusBadRequest}}
result, err := parseBoolResponse(v)
if err == nil {
t.Errorf("Expected error to be returned.")
}
if want := false; result != want {
t.Errorf("parseBoolResponse returned %+v, want: %+v", result, want)
}
}
func TestErrorResponse_Error(t *testing.T) {
res := &http.Response{Request: &http.Request{}}
err := ErrorResponse{Message: "m", Response: res}
if err.Error() == "" {
t.Errorf("Expected non-empty ErrorResponse.Error()")
}
}
func TestError_Error(t *testing.T) {
err := Error{}
if err.Error() == "" {
t.Errorf("Expected non-empty Error.Error()")
}
}
func TestRateLimit(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/rate_limit", func(w http.ResponseWriter, r *http.Request) {
if m := "GET"; m != r.Method {
t.Errorf("Request method = %v, want %v", r.Method, m)
}
//fmt.Fprint(w, `{"resources":{"core": {"limit":2,"remaining":1,"reset":1372700873}}}`)
fmt.Fprint(w, `{"resources":{
"core": {"limit":2,"remaining":1,"reset":1372700873},
"search": {"limit":3,"remaining":2,"reset":1372700874}
}}`)
})
rate, _, err := client.RateLimit()
if err != nil {
t.Errorf("Rate limit returned error: %v", err)
}
want := &Rate{
Limit: 2,
Remaining: 1,
Reset: Timestamp{time.Date(2013, 7, 1, 17, 47, 53, 0, time.UTC).Local()},
}
if !reflect.DeepEqual(rate, want) {
t.Errorf("RateLimit returned %+v, want %+v", rate, want)
}
}
func TestRateLimits(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/rate_limit", func(w http.ResponseWriter, r *http.Request) {
if m := "GET"; m != r.Method {
t.Errorf("Request method = %v, want %v", r.Method, m)
}
fmt.Fprint(w, `{"resources":{
"core": {"limit":2,"remaining":1,"reset":1372700873},
"search": {"limit":3,"remaining":2,"reset":1372700874}
}}`)
})
rate, _, err := client.RateLimits()
if err != nil {
t.Errorf("RateLimits returned error: %v", err)
}
want := &RateLimits{
Core: &Rate{
Limit: 2,
Remaining: 1,
Reset: Timestamp{time.Date(2013, 7, 1, 17, 47, 53, 0, time.UTC).Local()},
},
Search: &Rate{
Limit: 3,
Remaining: 2,
Reset: Timestamp{time.Date(2013, 7, 1, 17, 47, 54, 0, time.UTC).Local()},
},
}
if !reflect.DeepEqual(rate, want) {
t.Errorf("RateLimits returned %+v, want %+v", rate, want)
}
}
func TestUnauthenticatedRateLimitedTransport(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
var v, want string
q := r.URL.Query()
if v, want = q.Get("client_id"), "id"; v != want {
t.Errorf("OAuth Client ID = %v, want %v", v, want)
}
if v, want = q.Get("client_secret"), "secret"; v != want {
t.Errorf("OAuth Client Secret = %v, want %v", v, want)
}
})
tp := &UnauthenticatedRateLimitedTransport{
ClientID: "id",
ClientSecret: "secret",
}
unauthedClient := NewClient(tp.Client())
unauthedClient.BaseURL = client.BaseURL
req, _ := unauthedClient.NewRequest("GET", "/", nil)
unauthedClient.Do(req, nil)
}
func TestUnauthenticatedRateLimitedTransport_missingFields(t *testing.T) {
// missing ClientID
tp := &UnauthenticatedRateLimitedTransport{
ClientSecret: "secret",
}
_, err := tp.RoundTrip(nil)
if err == nil {
t.Errorf("Expected error to be returned")
}
// missing ClientSecret
tp = &UnauthenticatedRateLimitedTransport{
ClientID: "id",
}
_, err = tp.RoundTrip(nil)
if err == nil {
t.Errorf("Expected error to be returned")
}
}
func TestUnauthenticatedRateLimitedTransport_transport(t *testing.T) {
// default transport
tp := &UnauthenticatedRateLimitedTransport{
ClientID: "id",
ClientSecret: "secret",
}
if tp.transport() != http.DefaultTransport {
t.Errorf("Expected http.DefaultTransport to be used.")
}
// custom transport
tp = &UnauthenticatedRateLimitedTransport{
ClientID: "id",
ClientSecret: "secret",
Transport: &http.Transport{},
}
if tp.transport() == http.DefaultTransport {
t.Errorf("Expected custom transport to be used.")
}
}

63
vendor/github.com/google/go-github/github/gitignore.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,63 @@
// 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"
// GitignoresService provides access to the gitignore related functions in the
// GitHub API.
//
// GitHub API docs: http://developer.github.com/v3/gitignore/
type GitignoresService struct {
client *Client
}
// Gitignore represents a .gitignore file as returned by the GitHub API.
type Gitignore struct {
Name *string `json:"name,omitempty"`
Source *string `json:"source,omitempty"`
}
func (g Gitignore) String() string {
return Stringify(g)
}
// List all available Gitignore templates.
//
// http://developer.github.com/v3/gitignore/#listing-available-templates
func (s GitignoresService) List() ([]string, *Response, error) {
req, err := s.client.NewRequest("GET", "gitignore/templates", nil)
if err != nil {
return nil, nil, err
}
availableTemplates := new([]string)
resp, err := s.client.Do(req, availableTemplates)
if err != nil {
return nil, resp, err
}
return *availableTemplates, resp, err
}
// Get a Gitignore by name.
//
// http://developer.github.com/v3/gitignore/#get-a-single-template
func (s GitignoresService) Get(name string) (*Gitignore, *Response, error) {
u := fmt.Sprintf("gitignore/templates/%v", name)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
gitignore := new(Gitignore)
resp, err := s.client.Do(req, gitignore)
if err != nil {
return nil, resp, err
}
return gitignore, resp, err
}

58
vendor/github.com/google/go-github/github/gitignore_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,58 @@
// 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/http"
"reflect"
"testing"
)
func TestGitignoresService_List(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/gitignore/templates", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `["C", "Go"]`)
})
available, _, err := client.Gitignores.List()
if err != nil {
t.Errorf("Gitignores.List returned error: %v", err)
}
want := []string{"C", "Go"}
if !reflect.DeepEqual(available, want) {
t.Errorf("Gitignores.List returned %+v, want %+v", available, want)
}
}
func TestGitignoresService_Get(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/gitignore/templates/name", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"name":"Name","source":"template source"}`)
})
gitignore, _, err := client.Gitignores.Get("name")
if err != nil {
t.Errorf("Gitignores.List returned error: %v", err)
}
want := &Gitignore{Name: String("Name"), Source: String("template source")}
if !reflect.DeepEqual(gitignore, want) {
t.Errorf("Gitignores.Get returned %+v, want %+v", gitignore, want)
}
}
func TestGitignoresService_Get_invalidTemplate(t *testing.T) {
_, _, err := client.Gitignores.Get("%")
testURLParseError(t, err)
}

261
vendor/github.com/google/go-github/github/issues.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,261 @@
// 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"
"time"
)
// IssuesService handles communication with the issue related
// methods of the GitHub API.
//
// GitHub API docs: http://developer.github.com/v3/issues/
type IssuesService struct {
client *Client
}
// Issue represents a GitHub issue on a repository.
type Issue struct {
Number *int `json:"number,omitempty"`
State *string `json:"state,omitempty"`
Title *string `json:"title,omitempty"`
Body *string `json:"body,omitempty"`
User *User `json:"user,omitempty"`
Labels []Label `json:"labels,omitempty"`
Assignee *User `json:"assignee,omitempty"`
Comments *int `json:"comments,omitempty"`
ClosedAt *time.Time `json:"closed_at,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
URL *string `json:"url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
Milestone *Milestone `json:"milestone,omitempty"`
PullRequestLinks *PullRequestLinks `json:"pull_request,omitempty"`
// TextMatches is only populated from search results that request text matches
// See: search.go and https://developer.github.com/v3/search/#text-match-metadata
TextMatches []TextMatch `json:"text_matches,omitempty"`
}
func (i Issue) String() string {
return Stringify(i)
}
// IssueRequest represents a request to create/edit an issue.
// It is separate from Issue above because otherwise Labels
// and Assignee fail to serialize to the correct JSON.
type IssueRequest struct {
Title *string `json:"title,omitempty"`
Body *string `json:"body,omitempty"`
Labels *[]string `json:"labels,omitempty"`
Assignee *string `json:"assignee,omitempty"`
State *string `json:"state,omitempty"`
Milestone *int `json:"milestone,omitempty"`
}
// IssueListOptions specifies the optional parameters to the IssuesService.List
// and IssuesService.ListByOrg methods.
type IssueListOptions struct {
// Filter specifies which issues to list. Possible values are: assigned,
// created, mentioned, subscribed, all. Default is "assigned".
Filter string `url:"filter,omitempty"`
// State filters issues based on their state. Possible values are: open,
// closed. Default is "open".
State string `url:"state,omitempty"`
// Labels filters issues based on their label.
Labels []string `url:"labels,comma,omitempty"`
// Sort specifies how to sort issues. Possible values are: created, updated,
// and comments. Default value is "created".
Sort string `url:"sort,omitempty"`
// Direction in which to sort issues. Possible values are: asc, desc.
// Default is "asc".
Direction string `url:"direction,omitempty"`
// Since filters issues by time.
Since time.Time `url:"since,omitempty"`
ListOptions
}
// PullRequestLinks object is added to the Issue object when it's an issue included
// in the IssueCommentEvent webhook payload, if the webhooks is fired by a comment on a PR
type PullRequestLinks struct {
URL *string `json:"url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
DiffURL *string `json:"diff_url,omitempty"`
PatchURL *string `json:"patch_url,omitempty"`
}
// List the issues for the authenticated user. If all is true, list issues
// across all the user's visible repositories including owned, member, and
// organization repositories; if false, list only owned and member
// repositories.
//
// GitHub API docs: http://developer.github.com/v3/issues/#list-issues
func (s *IssuesService) List(all bool, opt *IssueListOptions) ([]Issue, *Response, error) {
var u string
if all {
u = "issues"
} else {
u = "user/issues"
}
return s.listIssues(u, opt)
}
// ListByOrg fetches the issues in the specified organization for the
// authenticated user.
//
// GitHub API docs: http://developer.github.com/v3/issues/#list-issues
func (s *IssuesService) ListByOrg(org string, opt *IssueListOptions) ([]Issue, *Response, error) {
u := fmt.Sprintf("orgs/%v/issues", org)
return s.listIssues(u, opt)
}
func (s *IssuesService) listIssues(u string, opt *IssueListOptions) ([]Issue, *Response, error) {
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
}
issues := new([]Issue)
resp, err := s.client.Do(req, issues)
if err != nil {
return nil, resp, err
}
return *issues, resp, err
}
// IssueListByRepoOptions specifies the optional parameters to the
// IssuesService.ListByRepo method.
type IssueListByRepoOptions struct {
// Milestone limits issues for the specified milestone. Possible values are
// a milestone number, "none" for issues with no milestone, "*" for issues
// with any milestone.
Milestone string `url:"milestone,omitempty"`
// State filters issues based on their state. Possible values are: open,
// closed. Default is "open".
State string `url:"state,omitempty"`
// Assignee filters issues based on their assignee. Possible values are a
// user name, "none" for issues that are not assigned, "*" for issues with
// any assigned user.
Assignee string `url:"assignee,omitempty"`
// Creator filters issues based on their creator.
Creator string `url:"creator,omitempty"`
// Mentioned filters issues to those mentioned a specific user.
Mentioned string `url:"mentioned,omitempty"`
// Labels filters issues based on their label.
Labels []string `url:"labels,omitempty,comma"`
// Sort specifies how to sort issues. Possible values are: created, updated,
// and comments. Default value is "created".
Sort string `url:"sort,omitempty"`
// Direction in which to sort issues. Possible values are: asc, desc.
// Default is "asc".
Direction string `url:"direction,omitempty"`
// Since filters issues by time.
Since time.Time `url:"since,omitempty"`
ListOptions
}
// ListByRepo lists the issues for the specified repository.
//
// GitHub API docs: http://developer.github.com/v3/issues/#list-issues-for-a-repository
func (s *IssuesService) ListByRepo(owner string, repo string, opt *IssueListByRepoOptions) ([]Issue, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues", owner, repo)
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
}
issues := new([]Issue)
resp, err := s.client.Do(req, issues)
if err != nil {
return nil, resp, err
}
return *issues, resp, err
}
// Get a single issue.
//
// GitHub API docs: http://developer.github.com/v3/issues/#get-a-single-issue
func (s *IssuesService) Get(owner string, repo string, number int) (*Issue, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/%d", owner, repo, number)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
issue := new(Issue)
resp, err := s.client.Do(req, issue)
if err != nil {
return nil, resp, err
}
return issue, resp, err
}
// Create a new issue on the specified repository.
//
// GitHub API docs: http://developer.github.com/v3/issues/#create-an-issue
func (s *IssuesService) Create(owner string, repo string, issue *IssueRequest) (*Issue, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues", owner, repo)
req, err := s.client.NewRequest("POST", u, issue)
if err != nil {
return nil, nil, err
}
i := new(Issue)
resp, err := s.client.Do(req, i)
if err != nil {
return nil, resp, err
}
return i, resp, err
}
// Edit an issue.
//
// GitHub API docs: http://developer.github.com/v3/issues/#edit-an-issue
func (s *IssuesService) Edit(owner string, repo string, number int, issue *IssueRequest) (*Issue, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/%d", owner, repo, number)
req, err := s.client.NewRequest("PATCH", u, issue)
if err != nil {
return nil, nil, err
}
i := new(Issue)
resp, err := s.client.Do(req, i)
if err != nil {
return nil, resp, err
}
return i, resp, err
}

46
vendor/github.com/google/go-github/github/issues_assignees.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,46 @@
// 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"
// ListAssignees fetches all available assignees (owners and collaborators) to
// which issues may be assigned.
//
// GitHub API docs: http://developer.github.com/v3/issues/assignees/#list-assignees
func (s *IssuesService) ListAssignees(owner string, repo string, opt *ListOptions) ([]User, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/assignees", owner, repo)
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
}
assignees := new([]User)
resp, err := s.client.Do(req, assignees)
if err != nil {
return nil, resp, err
}
return *assignees, resp, err
}
// IsAssignee checks if a user is an assignee for the specified repository.
//
// GitHub API docs: http://developer.github.com/v3/issues/assignees/#check-assignee
func (s *IssuesService) IsAssignee(owner string, repo string, user string) (bool, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/assignees/%v", owner, repo, user)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return false, nil, err
}
resp, err := s.client.Do(req, nil)
assignee, err := parseBoolResponse(err)
return assignee, resp, err
}

98
vendor/github.com/google/go-github/github/issues_assignees_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,98 @@
// 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/http"
"reflect"
"testing"
)
func TestIssuesService_ListAssignees(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/assignees", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{"page": "2"})
fmt.Fprint(w, `[{"id":1}]`)
})
opt := &ListOptions{Page: 2}
assignees, _, err := client.Issues.ListAssignees("o", "r", opt)
if err != nil {
t.Errorf("Issues.List returned error: %v", err)
}
want := []User{{ID: Int(1)}}
if !reflect.DeepEqual(assignees, want) {
t.Errorf("Issues.ListAssignees returned %+v, want %+v", assignees, want)
}
}
func TestIssuesService_ListAssignees_invalidOwner(t *testing.T) {
_, _, err := client.Issues.ListAssignees("%", "r", nil)
testURLParseError(t, err)
}
func TestIssuesService_IsAssignee_true(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/assignees/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
})
assignee, _, err := client.Issues.IsAssignee("o", "r", "u")
if err != nil {
t.Errorf("Issues.IsAssignee returned error: %v", err)
}
if want := true; assignee != want {
t.Errorf("Issues.IsAssignee returned %+v, want %+v", assignee, want)
}
}
func TestIssuesService_IsAssignee_false(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/assignees/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.WriteHeader(http.StatusNotFound)
})
assignee, _, err := client.Issues.IsAssignee("o", "r", "u")
if err != nil {
t.Errorf("Issues.IsAssignee returned error: %v", err)
}
if want := false; assignee != want {
t.Errorf("Issues.IsAssignee returned %+v, want %+v", assignee, want)
}
}
func TestIssuesService_IsAssignee_error(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/assignees/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
http.Error(w, "BadRequest", http.StatusBadRequest)
})
assignee, _, err := client.Issues.IsAssignee("o", "r", "u")
if err == nil {
t.Errorf("Expected HTTP 400 response")
}
if want := false; assignee != want {
t.Errorf("Issues.IsAssignee returned %+v, want %+v", assignee, want)
}
}
func TestIssuesService_IsAssignee_invalidOwner(t *testing.T) {
_, _, err := client.Issues.IsAssignee("%", "r", "u")
testURLParseError(t, err)
}

138
vendor/github.com/google/go-github/github/issues_comments.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,138 @@
// 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"
"time"
)
// IssueComment represents a comment left on an issue.
type IssueComment struct {
ID *int `json:"id,omitempty"`
Body *string `json:"body,omitempty"`
User *User `json:"user,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
URL *string `json:"url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
IssueURL *string `json:"issue_url,omitempty"`
}
func (i IssueComment) String() string {
return Stringify(i)
}
// IssueListCommentsOptions specifies the optional parameters to the
// IssuesService.ListComments method.
type IssueListCommentsOptions struct {
// Sort specifies how to sort comments. Possible values are: created, updated.
Sort string `url:"sort,omitempty"`
// Direction in which to sort comments. Possible values are: asc, desc.
Direction string `url:"direction,omitempty"`
// Since filters comments by time.
Since time.Time `url:"since,omitempty"`
ListOptions
}
// ListComments lists all comments on the specified issue. Specifying an issue
// number of 0 will return all comments on all issues for the repository.
//
// GitHub API docs: http://developer.github.com/v3/issues/comments/#list-comments-on-an-issue
func (s *IssuesService) ListComments(owner string, repo string, number int, opt *IssueListCommentsOptions) ([]IssueComment, *Response, error) {
var u string
if number == 0 {
u = fmt.Sprintf("repos/%v/%v/issues/comments", owner, repo)
} else {
u = fmt.Sprintf("repos/%v/%v/issues/%d/comments", owner, repo, number)
}
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
}
comments := new([]IssueComment)
resp, err := s.client.Do(req, comments)
if err != nil {
return nil, resp, err
}
return *comments, resp, err
}
// GetComment fetches the specified issue comment.
//
// GitHub API docs: http://developer.github.com/v3/issues/comments/#get-a-single-comment
func (s *IssuesService) GetComment(owner string, repo string, id int) (*IssueComment, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, id)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
comment := new(IssueComment)
resp, err := s.client.Do(req, comment)
if err != nil {
return nil, resp, err
}
return comment, resp, err
}
// CreateComment creates a new comment on the specified issue.
//
// GitHub API docs: http://developer.github.com/v3/issues/comments/#create-a-comment
func (s *IssuesService) CreateComment(owner string, repo string, number int, comment *IssueComment) (*IssueComment, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/%d/comments", owner, repo, number)
req, err := s.client.NewRequest("POST", u, comment)
if err != nil {
return nil, nil, err
}
c := new(IssueComment)
resp, err := s.client.Do(req, c)
if err != nil {
return nil, resp, err
}
return c, resp, err
}
// EditComment updates an issue comment.
//
// GitHub API docs: http://developer.github.com/v3/issues/comments/#edit-a-comment
func (s *IssuesService) EditComment(owner string, repo string, id int, comment *IssueComment) (*IssueComment, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, id)
req, err := s.client.NewRequest("PATCH", u, comment)
if err != nil {
return nil, nil, err
}
c := new(IssueComment)
resp, err := s.client.Do(req, c)
if err != nil {
return nil, resp, err
}
return c, resp, err
}
// DeleteComment deletes an issue comment.
//
// GitHub API docs: http://developer.github.com/v3/issues/comments/#delete-a-comment
func (s *IssuesService) DeleteComment(owner string, repo string, id int) (*Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, id)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}

184
vendor/github.com/google/go-github/github/issues_comments_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,184 @@
// 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 (
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
"time"
)
func TestIssuesService_ListComments_allIssues(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/comments", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"sort": "updated",
"direction": "desc",
"since": "2002-02-10T15:30:00Z",
"page": "2",
})
fmt.Fprint(w, `[{"id":1}]`)
})
opt := &IssueListCommentsOptions{
Sort: "updated",
Direction: "desc",
Since: time.Date(2002, time.February, 10, 15, 30, 0, 0, time.UTC),
ListOptions: ListOptions{Page: 2},
}
comments, _, err := client.Issues.ListComments("o", "r", 0, opt)
if err != nil {
t.Errorf("Issues.ListComments returned error: %v", err)
}
want := []IssueComment{{ID: Int(1)}}
if !reflect.DeepEqual(comments, want) {
t.Errorf("Issues.ListComments returned %+v, want %+v", comments, want)
}
}
func TestIssuesService_ListComments_specificIssue(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/1/comments", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `[{"id":1}]`)
})
comments, _, err := client.Issues.ListComments("o", "r", 1, nil)
if err != nil {
t.Errorf("Issues.ListComments returned error: %v", err)
}
want := []IssueComment{{ID: Int(1)}}
if !reflect.DeepEqual(comments, want) {
t.Errorf("Issues.ListComments returned %+v, want %+v", comments, want)
}
}
func TestIssuesService_ListComments_invalidOwner(t *testing.T) {
_, _, err := client.Issues.ListComments("%", "r", 1, nil)
testURLParseError(t, err)
}
func TestIssuesService_GetComment(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/comments/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"id":1}`)
})
comment, _, err := client.Issues.GetComment("o", "r", 1)
if err != nil {
t.Errorf("Issues.GetComment returned error: %v", err)
}
want := &IssueComment{ID: Int(1)}
if !reflect.DeepEqual(comment, want) {
t.Errorf("Issues.GetComment returned %+v, want %+v", comment, want)
}
}
func TestIssuesService_GetComment_invalidOrg(t *testing.T) {
_, _, err := client.Issues.GetComment("%", "r", 1)
testURLParseError(t, err)
}
func TestIssuesService_CreateComment(t *testing.T) {
setup()
defer teardown()
input := &IssueComment{Body: String("b")}
mux.HandleFunc("/repos/o/r/issues/1/comments", func(w http.ResponseWriter, r *http.Request) {
v := new(IssueComment)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "POST")
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `{"id":1}`)
})
comment, _, err := client.Issues.CreateComment("o", "r", 1, input)
if err != nil {
t.Errorf("Issues.CreateComment returned error: %v", err)
}
want := &IssueComment{ID: Int(1)}
if !reflect.DeepEqual(comment, want) {
t.Errorf("Issues.CreateComment returned %+v, want %+v", comment, want)
}
}
func TestIssuesService_CreateComment_invalidOrg(t *testing.T) {
_, _, err := client.Issues.CreateComment("%", "r", 1, nil)
testURLParseError(t, err)
}
func TestIssuesService_EditComment(t *testing.T) {
setup()
defer teardown()
input := &IssueComment{Body: String("b")}
mux.HandleFunc("/repos/o/r/issues/comments/1", func(w http.ResponseWriter, r *http.Request) {
v := new(IssueComment)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PATCH")
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `{"id":1}`)
})
comment, _, err := client.Issues.EditComment("o", "r", 1, input)
if err != nil {
t.Errorf("Issues.EditComment returned error: %v", err)
}
want := &IssueComment{ID: Int(1)}
if !reflect.DeepEqual(comment, want) {
t.Errorf("Issues.EditComment returned %+v, want %+v", comment, want)
}
}
func TestIssuesService_EditComment_invalidOwner(t *testing.T) {
_, _, err := client.Issues.EditComment("%", "r", 1, nil)
testURLParseError(t, err)
}
func TestIssuesService_DeleteComment(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/comments/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
})
_, err := client.Issues.DeleteComment("o", "r", 1)
if err != nil {
t.Errorf("Issues.DeleteComments returned error: %v", err)
}
}
func TestIssuesService_DeleteComment_invalidOwner(t *testing.T) {
_, err := client.Issues.DeleteComment("%", "r", 1)
testURLParseError(t, err)
}

149
vendor/github.com/google/go-github/github/issues_events.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,149 @@
// Copyright 2014 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"
"time"
)
// IssueEvent represents an event that occurred around an Issue or Pull Request.
type IssueEvent struct {
ID *int `json:"id,omitempty"`
URL *string `json:"url,omitempty"`
// The User that generated this event.
Actor *User `json:"actor,omitempty"`
// Event identifies the actual type of Event that occurred. Possible
// values are:
//
// closed
// The Actor closed the issue.
// If the issue was closed by commit message, CommitID holds the SHA1 hash of the commit.
//
// merged
// The Actor merged into master a branch containing a commit mentioning the issue.
// CommitID holds the SHA1 of the merge commit.
//
// referenced
// 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
// Someone unspecified @mentioned the Actor [sic] in an issue comment body.
//
// assigned, unassigned
// The Actor assigned the issue to or removed the assignment from the Assignee.
//
// 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.
//
Event *string `json:"event,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.
//
// GitHub API docs: https://developer.github.com/v3/issues/events/#list-events-for-an-issue
func (s *IssuesService) ListIssueEvents(owner, repo string, number int, opt *ListOptions) ([]IssueEvent, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/%v/events", owner, repo, number)
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
}
var events []IssueEvent
resp, err := s.client.Do(req, &events)
if err != nil {
return nil, resp, err
}
return events, resp, err
}
// ListRepositoryEvents lists events for the specified repository.
//
// GitHub API docs: https://developer.github.com/v3/issues/events/#list-events-for-a-repository
func (s *IssuesService) ListRepositoryEvents(owner, repo string, opt *ListOptions) ([]IssueEvent, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/events", owner, repo)
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
}
var events []IssueEvent
resp, err := s.client.Do(req, &events)
if err != nil {
return nil, resp, err
}
return events, resp, err
}
// GetEvent returns the specified issue event.
//
// GitHub API docs: https://developer.github.com/v3/issues/events/#get-a-single-event
func (s *IssuesService) GetEvent(owner, repo string, id int) (*IssueEvent, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/events/%v", owner, repo, id)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
event := new(IssueEvent)
resp, err := s.client.Do(req, event)
if err != nil {
return nil, resp, err
}
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)
}

86
vendor/github.com/google/go-github/github/issues_events_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,86 @@
// Copyright 2014 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/http"
"reflect"
"testing"
)
func TestIssuesService_ListIssueEvents(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/1/events", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"page": "1",
"per_page": "2",
})
fmt.Fprint(w, `[{"id":1}]`)
})
opt := &ListOptions{Page: 1, PerPage: 2}
events, _, err := client.Issues.ListIssueEvents("o", "r", 1, opt)
if err != nil {
t.Errorf("Issues.ListIssueEvents returned error: %v", err)
}
want := []IssueEvent{{ID: Int(1)}}
if !reflect.DeepEqual(events, want) {
t.Errorf("Issues.ListIssueEvents returned %+v, want %+v", events, want)
}
}
func TestIssuesService_ListRepositoryEvents(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/events", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"page": "1",
"per_page": "2",
})
fmt.Fprint(w, `[{"id":1}]`)
})
opt := &ListOptions{Page: 1, PerPage: 2}
events, _, err := client.Issues.ListRepositoryEvents("o", "r", opt)
if err != nil {
t.Errorf("Issues.ListRepositoryEvents returned error: %v", err)
}
want := []IssueEvent{{ID: Int(1)}}
if !reflect.DeepEqual(events, want) {
t.Errorf("Issues.ListRepositoryEvents returned %+v, want %+v", events, want)
}
}
func TestIssuesService_GetEvent(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/events/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"id":1}`)
})
event, _, err := client.Issues.GetEvent("o", "r", 1)
if err != nil {
t.Errorf("Issues.GetEvent returned error: %v", err)
}
want := &IssueEvent{ID: Int(1)}
if !reflect.DeepEqual(event, want) {
t.Errorf("Issues.GetEvent returned %+v, want %+v", event, want)
}
}

222
vendor/github.com/google/go-github/github/issues_labels.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,222 @@
// 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"
// Label represents a GitHub label on an Issue
type Label struct {
URL *string `json:"url,omitempty"`
Name *string `json:"name,omitempty"`
Color *string `json:"color,omitempty"`
}
func (l Label) String() string {
return fmt.Sprint(*l.Name)
}
// ListLabels lists all labels for a repository.
//
// GitHub API docs: http://developer.github.com/v3/issues/labels/#list-all-labels-for-this-repository
func (s *IssuesService) ListLabels(owner string, repo string, opt *ListOptions) ([]Label, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/labels", owner, repo)
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
}
labels := new([]Label)
resp, err := s.client.Do(req, labels)
if err != nil {
return nil, resp, err
}
return *labels, resp, err
}
// GetLabel gets a single label.
//
// GitHub API docs: http://developer.github.com/v3/issues/labels/#get-a-single-label
func (s *IssuesService) GetLabel(owner string, repo string, name string) (*Label, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/labels/%v", owner, repo, name)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
label := new(Label)
resp, err := s.client.Do(req, label)
if err != nil {
return nil, resp, err
}
return label, resp, err
}
// CreateLabel creates a new label on the specified repository.
//
// GitHub API docs: http://developer.github.com/v3/issues/labels/#create-a-label
func (s *IssuesService) CreateLabel(owner string, repo string, label *Label) (*Label, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/labels", owner, repo)
req, err := s.client.NewRequest("POST", u, label)
if err != nil {
return nil, nil, err
}
l := new(Label)
resp, err := s.client.Do(req, l)
if err != nil {
return nil, resp, err
}
return l, resp, err
}
// EditLabel edits a label.
//
// GitHub API docs: http://developer.github.com/v3/issues/labels/#update-a-label
func (s *IssuesService) EditLabel(owner string, repo string, name string, label *Label) (*Label, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/labels/%v", owner, repo, name)
req, err := s.client.NewRequest("PATCH", u, label)
if err != nil {
return nil, nil, err
}
l := new(Label)
resp, err := s.client.Do(req, l)
if err != nil {
return nil, resp, err
}
return l, resp, err
}
// DeleteLabel deletes a label.
//
// GitHub API docs: http://developer.github.com/v3/issues/labels/#delete-a-label
func (s *IssuesService) DeleteLabel(owner string, repo string, name string) (*Response, error) {
u := fmt.Sprintf("repos/%v/%v/labels/%v", owner, repo, name)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}
// ListLabelsByIssue lists all labels for an issue.
//
// GitHub API docs: http://developer.github.com/v3/issues/labels/#list-all-labels-for-this-repository
func (s *IssuesService) ListLabelsByIssue(owner string, repo string, number int, opt *ListOptions) ([]Label, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/%d/labels", owner, repo, number)
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
}
labels := new([]Label)
resp, err := s.client.Do(req, labels)
if err != nil {
return nil, resp, err
}
return *labels, resp, err
}
// AddLabelsToIssue adds labels to an issue.
//
// GitHub API docs: http://developer.github.com/v3/issues/labels/#list-all-labels-for-this-repository
func (s *IssuesService) AddLabelsToIssue(owner string, repo string, number int, labels []string) ([]Label, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/%d/labels", owner, repo, number)
req, err := s.client.NewRequest("POST", u, labels)
if err != nil {
return nil, nil, err
}
l := new([]Label)
resp, err := s.client.Do(req, l)
if err != nil {
return nil, resp, err
}
return *l, resp, err
}
// RemoveLabelForIssue removes a label for an issue.
//
// GitHub API docs: http://developer.github.com/v3/issues/labels/#remove-a-label-from-an-issue
func (s *IssuesService) RemoveLabelForIssue(owner string, repo string, number int, label string) (*Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/%d/labels/%v", owner, repo, number, label)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}
// ReplaceLabelsForIssue replaces all labels for an issue.
//
// GitHub API docs: http://developer.github.com/v3/issues/labels/#replace-all-labels-for-an-issue
func (s *IssuesService) ReplaceLabelsForIssue(owner string, repo string, number int, labels []string) ([]Label, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/%d/labels", owner, repo, number)
req, err := s.client.NewRequest("PUT", u, labels)
if err != nil {
return nil, nil, err
}
l := new([]Label)
resp, err := s.client.Do(req, l)
if err != nil {
return nil, resp, err
}
return *l, resp, err
}
// RemoveLabelsForIssue removes all labels for an issue.
//
// GitHub API docs: http://developer.github.com/v3/issues/labels/#remove-all-labels-from-an-issue
func (s *IssuesService) RemoveLabelsForIssue(owner string, repo string, number int) (*Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/%d/labels", owner, repo, number)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}
// ListLabelsForMilestone lists labels for every issue in a milestone.
//
// GitHub API docs: http://developer.github.com/v3/issues/labels/#get-labels-for-every-issue-in-a-milestone
func (s *IssuesService) ListLabelsForMilestone(owner string, repo string, number int, opt *ListOptions) ([]Label, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/milestones/%d/labels", owner, repo, number)
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
}
labels := new([]Label)
resp, err := s.client.Do(req, labels)
if err != nil {
return nil, resp, err
}
return *labels, resp, err
}

313
vendor/github.com/google/go-github/github/issues_labels_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,313 @@
// 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 (
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
)
func TestIssuesService_ListLabels(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/labels", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{"page": "2"})
fmt.Fprint(w, `[{"name": "a"},{"name": "b"}]`)
})
opt := &ListOptions{Page: 2}
labels, _, err := client.Issues.ListLabels("o", "r", opt)
if err != nil {
t.Errorf("Issues.ListLabels returned error: %v", err)
}
want := []Label{{Name: String("a")}, {Name: String("b")}}
if !reflect.DeepEqual(labels, want) {
t.Errorf("Issues.ListLabels returned %+v, want %+v", labels, want)
}
}
func TestIssuesService_ListLabels_invalidOwner(t *testing.T) {
_, _, err := client.Issues.ListLabels("%", "%", nil)
testURLParseError(t, err)
}
func TestIssuesService_GetLabel(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/labels/n", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"url":"u", "name": "n", "color": "c"}`)
})
label, _, err := client.Issues.GetLabel("o", "r", "n")
if err != nil {
t.Errorf("Issues.GetLabel returned error: %v", err)
}
want := &Label{URL: String("u"), Name: String("n"), Color: String("c")}
if !reflect.DeepEqual(label, want) {
t.Errorf("Issues.GetLabel returned %+v, want %+v", label, want)
}
}
func TestIssuesService_GetLabel_invalidOwner(t *testing.T) {
_, _, err := client.Issues.GetLabel("%", "%", "%")
testURLParseError(t, err)
}
func TestIssuesService_CreateLabel(t *testing.T) {
setup()
defer teardown()
input := &Label{Name: String("n")}
mux.HandleFunc("/repos/o/r/labels", func(w http.ResponseWriter, r *http.Request) {
v := new(Label)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "POST")
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `{"url":"u"}`)
})
label, _, err := client.Issues.CreateLabel("o", "r", input)
if err != nil {
t.Errorf("Issues.CreateLabel returned error: %v", err)
}
want := &Label{URL: String("u")}
if !reflect.DeepEqual(label, want) {
t.Errorf("Issues.CreateLabel returned %+v, want %+v", label, want)
}
}
func TestIssuesService_CreateLabel_invalidOwner(t *testing.T) {
_, _, err := client.Issues.CreateLabel("%", "%", nil)
testURLParseError(t, err)
}
func TestIssuesService_EditLabel(t *testing.T) {
setup()
defer teardown()
input := &Label{Name: String("z")}
mux.HandleFunc("/repos/o/r/labels/n", func(w http.ResponseWriter, r *http.Request) {
v := new(Label)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PATCH")
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `{"url":"u"}`)
})
label, _, err := client.Issues.EditLabel("o", "r", "n", input)
if err != nil {
t.Errorf("Issues.EditLabel returned error: %v", err)
}
want := &Label{URL: String("u")}
if !reflect.DeepEqual(label, want) {
t.Errorf("Issues.EditLabel returned %+v, want %+v", label, want)
}
}
func TestIssuesService_EditLabel_invalidOwner(t *testing.T) {
_, _, err := client.Issues.EditLabel("%", "%", "%", nil)
testURLParseError(t, err)
}
func TestIssuesService_DeleteLabel(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/labels/n", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
})
_, err := client.Issues.DeleteLabel("o", "r", "n")
if err != nil {
t.Errorf("Issues.DeleteLabel returned error: %v", err)
}
}
func TestIssuesService_DeleteLabel_invalidOwner(t *testing.T) {
_, err := client.Issues.DeleteLabel("%", "%", "%")
testURLParseError(t, err)
}
func TestIssuesService_ListLabelsByIssue(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/1/labels", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{"page": "2"})
fmt.Fprint(w, `[{"name": "a"},{"name": "b"}]`)
})
opt := &ListOptions{Page: 2}
labels, _, err := client.Issues.ListLabelsByIssue("o", "r", 1, opt)
if err != nil {
t.Errorf("Issues.ListLabelsByIssue returned error: %v", err)
}
want := []Label{{Name: String("a")}, {Name: String("b")}}
if !reflect.DeepEqual(labels, want) {
t.Errorf("Issues.ListLabelsByIssue returned %+v, want %+v", labels, want)
}
}
func TestIssuesService_ListLabelsByIssue_invalidOwner(t *testing.T) {
_, _, err := client.Issues.ListLabelsByIssue("%", "%", 1, nil)
testURLParseError(t, err)
}
func TestIssuesService_AddLabelsToIssue(t *testing.T) {
setup()
defer teardown()
input := []string{"a", "b"}
mux.HandleFunc("/repos/o/r/issues/1/labels", func(w http.ResponseWriter, r *http.Request) {
v := new([]string)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "POST")
if !reflect.DeepEqual(*v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `[{"url":"u"}]`)
})
labels, _, err := client.Issues.AddLabelsToIssue("o", "r", 1, input)
if err != nil {
t.Errorf("Issues.AddLabelsToIssue returned error: %v", err)
}
want := []Label{{URL: String("u")}}
if !reflect.DeepEqual(labels, want) {
t.Errorf("Issues.AddLabelsToIssue returned %+v, want %+v", labels, want)
}
}
func TestIssuesService_AddLabelsToIssue_invalidOwner(t *testing.T) {
_, _, err := client.Issues.AddLabelsToIssue("%", "%", 1, nil)
testURLParseError(t, err)
}
func TestIssuesService_RemoveLabelForIssue(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/1/labels/l", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
})
_, err := client.Issues.RemoveLabelForIssue("o", "r", 1, "l")
if err != nil {
t.Errorf("Issues.RemoveLabelForIssue returned error: %v", err)
}
}
func TestIssuesService_RemoveLabelForIssue_invalidOwner(t *testing.T) {
_, err := client.Issues.RemoveLabelForIssue("%", "%", 1, "%")
testURLParseError(t, err)
}
func TestIssuesService_ReplaceLabelsForIssue(t *testing.T) {
setup()
defer teardown()
input := []string{"a", "b"}
mux.HandleFunc("/repos/o/r/issues/1/labels", func(w http.ResponseWriter, r *http.Request) {
v := new([]string)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PUT")
if !reflect.DeepEqual(*v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `[{"url":"u"}]`)
})
labels, _, err := client.Issues.ReplaceLabelsForIssue("o", "r", 1, input)
if err != nil {
t.Errorf("Issues.ReplaceLabelsForIssue returned error: %v", err)
}
want := []Label{{URL: String("u")}}
if !reflect.DeepEqual(labels, want) {
t.Errorf("Issues.ReplaceLabelsForIssue returned %+v, want %+v", labels, want)
}
}
func TestIssuesService_ReplaceLabelsForIssue_invalidOwner(t *testing.T) {
_, _, err := client.Issues.ReplaceLabelsForIssue("%", "%", 1, nil)
testURLParseError(t, err)
}
func TestIssuesService_RemoveLabelsForIssue(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/1/labels", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
})
_, err := client.Issues.RemoveLabelsForIssue("o", "r", 1)
if err != nil {
t.Errorf("Issues.RemoveLabelsForIssue returned error: %v", err)
}
}
func TestIssuesService_RemoveLabelsForIssue_invalidOwner(t *testing.T) {
_, err := client.Issues.RemoveLabelsForIssue("%", "%", 1)
testURLParseError(t, err)
}
func TestIssuesService_ListLabelsForMilestone(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/milestones/1/labels", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{"page": "2"})
fmt.Fprint(w, `[{"name": "a"},{"name": "b"}]`)
})
opt := &ListOptions{Page: 2}
labels, _, err := client.Issues.ListLabelsForMilestone("o", "r", 1, opt)
if err != nil {
t.Errorf("Issues.ListLabelsForMilestone returned error: %v", err)
}
want := []Label{{Name: String("a")}, {Name: String("b")}}
if !reflect.DeepEqual(labels, want) {
t.Errorf("Issues.ListLabelsForMilestone returned %+v, want %+v", labels, want)
}
}
func TestIssuesService_ListLabelsForMilestone_invalidOwner(t *testing.T) {
_, _, err := client.Issues.ListLabelsForMilestone("%", "%", 1, nil)
testURLParseError(t, err)
}

140
vendor/github.com/google/go-github/github/issues_milestones.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,140 @@
// Copyright 2014 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"
"time"
)
// Milestone represents a Github repository milestone.
type Milestone struct {
URL *string `json:"url,omitempty"`
Number *int `json:"number,omitempty"`
State *string `json:"state,omitempty"`
Title *string `json:"title,omitempty"`
Description *string `json:"description,omitempty"`
Creator *User `json:"creator,omitempty"`
OpenIssues *int `json:"open_issues,omitempty"`
ClosedIssues *int `json:"closed_issues,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
DueOn *time.Time `json:"due_on,omitempty"`
}
func (m Milestone) String() string {
return Stringify(m)
}
// MilestoneListOptions specifies the optional parameters to the
// IssuesService.ListMilestones method.
type MilestoneListOptions struct {
// State filters milestones based on their state. Possible values are:
// open, closed. Default is "open".
State string `url:"state,omitempty"`
// Sort specifies how to sort milestones. Possible values are: due_date, completeness.
// Default value is "due_date".
Sort string `url:"sort,omitempty"`
// Direction in which to sort milestones. Possible values are: asc, desc.
// Default is "asc".
Direction string `url:"direction,omitempty"`
}
// ListMilestones lists all milestones for a repository.
//
// 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, 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
}
milestones := new([]Milestone)
resp, err := s.client.Do(req, milestones)
if err != nil {
return nil, resp, err
}
return *milestones, resp, err
}
// GetMilestone gets a single 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)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
milestone := new(Milestone)
resp, err := s.client.Do(req, milestone)
if err != nil {
return nil, resp, err
}
return milestone, resp, err
}
// CreateMilestone creates a new milestone on the specified repository.
//
// 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)
req, err := s.client.NewRequest("POST", u, milestone)
if err != nil {
return nil, nil, err
}
m := new(Milestone)
resp, err := s.client.Do(req, m)
if err != nil {
return nil, resp, err
}
return m, resp, err
}
// EditMilestone edits a milestone.
//
// GitHub API docs: https://developer.github.com/v3/issues/milestones/#update-a-milestone
func (s *IssuesService) EditMilestone(owner string, repo string, number int, milestone *Milestone) (*Milestone, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/milestones/%d", owner, repo, number)
req, err := s.client.NewRequest("PATCH", u, milestone)
if err != nil {
return nil, nil, err
}
m := new(Milestone)
resp, err := s.client.Do(req, m)
if err != nil {
return nil, resp, err
}
return m, resp, err
}
// DeleteMilestone deletes a milestone.
//
// GitHub API docs: https://developer.github.com/v3/issues/milestones/#delete-a-milestone
func (s *IssuesService) DeleteMilestone(owner string, repo string, number int) (*Response, error) {
u := fmt.Sprintf("repos/%v/%v/milestones/%d", owner, repo, number)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}

157
vendor/github.com/google/go-github/github/issues_milestones_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,157 @@
// Copyright 2014 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 (
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
)
func TestIssuesService_ListMilestones(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/milestones", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"state": "closed",
"sort": "due_date",
"direction": "asc",
})
fmt.Fprint(w, `[{"number":1}]`)
})
opt := &MilestoneListOptions{"closed", "due_date", "asc"}
milestones, _, err := client.Issues.ListMilestones("o", "r", opt)
if err != nil {
t.Errorf("IssuesService.ListMilestones returned error: %v", err)
}
want := []Milestone{{Number: Int(1)}}
if !reflect.DeepEqual(milestones, want) {
t.Errorf("IssuesService.ListMilestones returned %+v, want %+v", milestones, want)
}
}
func TestIssuesService_ListMilestones_invalidOwner(t *testing.T) {
_, _, err := client.Issues.ListMilestones("%", "r", nil)
testURLParseError(t, err)
}
func TestIssuesService_GetMilestone(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/milestones/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"number":1}`)
})
milestone, _, err := client.Issues.GetMilestone("o", "r", 1)
if err != nil {
t.Errorf("IssuesService.GetMilestone returned error: %v", err)
}
want := &Milestone{Number: Int(1)}
if !reflect.DeepEqual(milestone, want) {
t.Errorf("IssuesService.GetMilestone returned %+v, want %+v", milestone, want)
}
}
func TestIssuesService_GetMilestone_invalidOwner(t *testing.T) {
_, _, err := client.Issues.GetMilestone("%", "r", 1)
testURLParseError(t, err)
}
func TestIssuesService_CreateMilestone(t *testing.T) {
setup()
defer teardown()
input := &Milestone{Title: String("t")}
mux.HandleFunc("/repos/o/r/milestones", func(w http.ResponseWriter, r *http.Request) {
v := new(Milestone)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "POST")
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `{"number":1}`)
})
milestone, _, err := client.Issues.CreateMilestone("o", "r", input)
if err != nil {
t.Errorf("IssuesService.CreateMilestone returned error: %v", err)
}
want := &Milestone{Number: Int(1)}
if !reflect.DeepEqual(milestone, want) {
t.Errorf("IssuesService.CreateMilestone returned %+v, want %+v", milestone, want)
}
}
func TestIssuesService_CreateMilestone_invalidOwner(t *testing.T) {
_, _, err := client.Issues.CreateMilestone("%", "r", nil)
testURLParseError(t, err)
}
func TestIssuesService_EditMilestone(t *testing.T) {
setup()
defer teardown()
input := &Milestone{Title: String("t")}
mux.HandleFunc("/repos/o/r/milestones/1", func(w http.ResponseWriter, r *http.Request) {
v := new(Milestone)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PATCH")
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `{"number":1}`)
})
milestone, _, err := client.Issues.EditMilestone("o", "r", 1, input)
if err != nil {
t.Errorf("IssuesService.EditMilestone returned error: %v", err)
}
want := &Milestone{Number: Int(1)}
if !reflect.DeepEqual(milestone, want) {
t.Errorf("IssuesService.EditMilestone returned %+v, want %+v", milestone, want)
}
}
func TestIssuesService_EditMilestone_invalidOwner(t *testing.T) {
_, _, err := client.Issues.EditMilestone("%", "r", 1, nil)
testURLParseError(t, err)
}
func TestIssuesService_DeleteMilestone(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/milestones/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
})
_, err := client.Issues.DeleteMilestone("o", "r", 1)
if err != nil {
t.Errorf("IssuesService.DeleteMilestone returned error: %v", err)
}
}
func TestIssuesService_DeleteMilestone_invalidOwner(t *testing.T) {
_, err := client.Issues.DeleteMilestone("%", "r", 1)
testURLParseError(t, err)
}

242
vendor/github.com/google/go-github/github/issues_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,242 @@
// 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 (
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
"time"
)
func TestIssuesService_List_all(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/issues", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"filter": "all",
"state": "closed",
"labels": "a,b",
"sort": "updated",
"direction": "asc",
"since": "2002-02-10T15:30:00Z",
"page": "1",
"per_page": "2",
})
fmt.Fprint(w, `[{"number":1}]`)
})
opt := &IssueListOptions{
"all", "closed", []string{"a", "b"}, "updated", "asc",
time.Date(2002, time.February, 10, 15, 30, 0, 0, time.UTC),
ListOptions{Page: 1, PerPage: 2},
}
issues, _, err := client.Issues.List(true, opt)
if err != nil {
t.Errorf("Issues.List returned error: %v", err)
}
want := []Issue{{Number: Int(1)}}
if !reflect.DeepEqual(issues, want) {
t.Errorf("Issues.List returned %+v, want %+v", issues, want)
}
}
func TestIssuesService_List_owned(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/user/issues", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `[{"number":1}]`)
})
issues, _, err := client.Issues.List(false, nil)
if err != nil {
t.Errorf("Issues.List returned error: %v", err)
}
want := []Issue{{Number: Int(1)}}
if !reflect.DeepEqual(issues, want) {
t.Errorf("Issues.List returned %+v, want %+v", issues, want)
}
}
func TestIssuesService_ListByOrg(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/issues", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `[{"number":1}]`)
})
issues, _, err := client.Issues.ListByOrg("o", nil)
if err != nil {
t.Errorf("Issues.ListByOrg returned error: %v", err)
}
want := []Issue{{Number: Int(1)}}
if !reflect.DeepEqual(issues, want) {
t.Errorf("Issues.List returned %+v, want %+v", issues, want)
}
}
func TestIssuesService_ListByOrg_invalidOrg(t *testing.T) {
_, _, err := client.Issues.ListByOrg("%", nil)
testURLParseError(t, err)
}
func TestIssuesService_ListByRepo(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"milestone": "*",
"state": "closed",
"assignee": "a",
"creator": "c",
"mentioned": "m",
"labels": "a,b",
"sort": "updated",
"direction": "asc",
"since": "2002-02-10T15:30:00Z",
})
fmt.Fprint(w, `[{"number":1}]`)
})
opt := &IssueListByRepoOptions{
"*", "closed", "a", "c", "m", []string{"a", "b"}, "updated", "asc",
time.Date(2002, time.February, 10, 15, 30, 0, 0, time.UTC),
ListOptions{0, 0},
}
issues, _, err := client.Issues.ListByRepo("o", "r", opt)
if err != nil {
t.Errorf("Issues.ListByOrg returned error: %v", err)
}
want := []Issue{{Number: Int(1)}}
if !reflect.DeepEqual(issues, want) {
t.Errorf("Issues.List returned %+v, want %+v", issues, want)
}
}
func TestIssuesService_ListByRepo_invalidOwner(t *testing.T) {
_, _, err := client.Issues.ListByRepo("%", "r", nil)
testURLParseError(t, err)
}
func TestIssuesService_Get(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"number":1, "labels": [{"url": "u", "name": "n", "color": "c"}]}`)
})
issue, _, err := client.Issues.Get("o", "r", 1)
if err != nil {
t.Errorf("Issues.Get returned error: %v", err)
}
want := &Issue{
Number: Int(1),
Labels: []Label{{
URL: String("u"),
Name: String("n"),
Color: String("c"),
}},
}
if !reflect.DeepEqual(issue, want) {
t.Errorf("Issues.Get returned %+v, want %+v", issue, want)
}
}
func TestIssuesService_Get_invalidOwner(t *testing.T) {
_, _, err := client.Issues.Get("%", "r", 1)
testURLParseError(t, err)
}
func TestIssuesService_Create(t *testing.T) {
setup()
defer teardown()
input := &IssueRequest{
Title: String("t"),
Body: String("b"),
Assignee: String("a"),
Labels: &[]string{"l1", "l2"},
}
mux.HandleFunc("/repos/o/r/issues", func(w http.ResponseWriter, r *http.Request) {
v := new(IssueRequest)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "POST")
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `{"number":1}`)
})
issue, _, err := client.Issues.Create("o", "r", input)
if err != nil {
t.Errorf("Issues.Create returned error: %v", err)
}
want := &Issue{Number: Int(1)}
if !reflect.DeepEqual(issue, want) {
t.Errorf("Issues.Create returned %+v, want %+v", issue, want)
}
}
func TestIssuesService_Create_invalidOwner(t *testing.T) {
_, _, err := client.Issues.Create("%", "r", nil)
testURLParseError(t, err)
}
func TestIssuesService_Edit(t *testing.T) {
setup()
defer teardown()
input := &IssueRequest{Title: String("t")}
mux.HandleFunc("/repos/o/r/issues/1", func(w http.ResponseWriter, r *http.Request) {
v := new(IssueRequest)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PATCH")
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `{"number":1}`)
})
issue, _, err := client.Issues.Edit("o", "r", 1, input)
if err != nil {
t.Errorf("Issues.Edit returned error: %v", err)
}
want := &Issue{Number: Int(1)}
if !reflect.DeepEqual(issue, want) {
t.Errorf("Issues.Edit returned %+v, want %+v", issue, want)
}
}
func TestIssuesService_Edit_invalidOwner(t *testing.T) {
_, _, err := client.Issues.Edit("%", "r", 1, nil)
testURLParseError(t, err)
}

81
vendor/github.com/google/go-github/github/licenses.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,81 @@
// 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"
// LicensesService handles communication with the license related
// methods of the GitHub API.
//
// GitHub API docs: http://developer.github.com/v3/pulls/
type LicensesService struct {
client *Client
}
// License represents an open source license.
type License struct {
Key *string `json:"key,omitempty"`
Name *string `json:"name,omitempty"`
URL *string `json:"url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
Featured *bool `json:"featured,omitempty"`
Description *string `json:"description,omitempty"`
Category *string `json:"category,omitempty"`
Implementation *string `json:"implementation,omitempty"`
Required *[]string `json:"required,omitempty"`
Permitted *[]string `json:"permitted,omitempty"`
Forbidden *[]string `json:"forbidden,omitempty"`
Body *string `json:"body,omitempty"`
}
func (l License) String() string {
return Stringify(l)
}
// List popular open source licenses.
//
// GitHub API docs: https://developer.github.com/v3/licenses/#list-all-licenses
func (s *LicensesService) List() ([]License, *Response, error) {
req, err := s.client.NewRequest("GET", "licenses", nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeLicensesPreview)
licenses := new([]License)
resp, err := s.client.Do(req, licenses)
if err != nil {
return nil, resp, err
}
return *licenses, resp, err
}
// Get extended metadata for one license.
//
// GitHub API docs: https://developer.github.com/v3/licenses/#get-an-individual-license
func (s *LicensesService) Get(licenseName string) (*License, *Response, error) {
u := fmt.Sprintf("licenses/%s", licenseName)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeLicensesPreview)
license := new(License)
resp, err := s.client.Do(req, license)
if err != nil {
return nil, resp, err
}
return license, resp, err
}

64
vendor/github.com/google/go-github/github/licenses_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,64 @@
// 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/http"
"reflect"
"testing"
)
func TestLicensesService_List(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/licenses", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeLicensesPreview)
fmt.Fprint(w, `[{"key":"mit","name":"MIT","url":"https://api.github.com/licenses/mit"}]`)
})
licenses, _, err := client.Licenses.List()
if err != nil {
t.Errorf("Licenses.List returned error: %v", err)
}
want := []License{{
Key: String("mit"),
Name: String("MIT"),
URL: String("https://api.github.com/licenses/mit"),
}}
if !reflect.DeepEqual(licenses, want) {
t.Errorf("Licenses.List returned %+v, want %+v", licenses, want)
}
}
func TestLicensesService_Get(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/licenses/mit", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeLicensesPreview)
fmt.Fprint(w, `{"key":"mit","name":"MIT"}`)
})
license, _, err := client.Licenses.Get("mit")
if err != nil {
t.Errorf("Licenses.Get returned error: %v", err)
}
want := &License{Key: String("mit"), Name: String("MIT")}
if !reflect.DeepEqual(license, want) {
t.Errorf("Licenses.Get returned %+v, want %+v", license, want)
}
}
func TestLicensesService_Get_invalidTemplate(t *testing.T) {
_, _, err := client.Licenses.Get("%")
testURLParseError(t, err)
}

197
vendor/github.com/google/go-github/github/misc.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,197 @@
// Copyright 2014 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 (
"bytes"
"fmt"
"net/url"
)
// MarkdownOptions specifies optional parameters to the Markdown method.
type MarkdownOptions struct {
// Mode identifies the rendering mode. Possible values are:
// markdown - render a document as plain Markdown, just like
// README files are rendered.
//
// gfm - to render a document as user-content, e.g. like user
// comments or issues are rendered. In GFM mode, hard line breaks are
// always taken into account, and issue and user mentions are linked
// accordingly.
//
// Default is "markdown".
Mode string
// Context identifies the repository context. Only taken into account
// when rendering as "gfm".
Context string
}
type markdownRequest struct {
Text *string `json:"text,omitempty"`
Mode *string `json:"mode,omitempty"`
Context *string `json:"context,omitempty"`
}
// Markdown renders an arbitrary Markdown document.
//
// GitHub API docs: https://developer.github.com/v3/markdown/
func (c *Client) Markdown(text string, opt *MarkdownOptions) (string, *Response, error) {
request := &markdownRequest{Text: String(text)}
if opt != nil {
if opt.Mode != "" {
request.Mode = String(opt.Mode)
}
if opt.Context != "" {
request.Context = String(opt.Context)
}
}
req, err := c.NewRequest("POST", "markdown", request)
if err != nil {
return "", nil, err
}
buf := new(bytes.Buffer)
resp, err := c.Do(req, buf)
if err != nil {
return "", resp, err
}
return buf.String(), resp, nil
}
// ListEmojis returns the emojis available to use on GitHub.
//
// GitHub API docs: https://developer.github.com/v3/emojis/
func (c *Client) ListEmojis() (map[string]string, *Response, error) {
req, err := c.NewRequest("GET", "emojis", nil)
if err != nil {
return nil, nil, err
}
var emoji map[string]string
resp, err := c.Do(req, &emoji)
if err != nil {
return nil, resp, err
}
return emoji, resp, nil
}
// APIMeta represents metadata about the GitHub API.
type APIMeta struct {
// An Array of IP addresses in CIDR format specifying the addresses
// that incoming service hooks will originate from on GitHub.com.
Hooks []string `json:"hooks,omitempty"`
// An Array of IP addresses in CIDR format specifying the Git servers
// for GitHub.com.
Git []string `json:"git,omitempty"`
// Whether authentication with username and password is supported.
// (GitHub Enterprise instances using CAS or OAuth for authentication
// will return false. Features like Basic Authentication with a
// username and password, sudo mode, and two-factor authentication are
// not supported on these servers.)
VerifiablePasswordAuthentication *bool `json:"verifiable_password_authentication,omitempty"`
// An array of IP addresses in CIDR format specifying the addresses
// which serve GitHub Pages websites.
Pages []string `json:"pages,omitempty"`
}
// APIMeta returns information about GitHub.com, the service. Or, if you access
// this endpoint on your organizations GitHub Enterprise installation, this
// endpoint provides information about that installation.
//
// GitHub API docs: https://developer.github.com/v3/meta/
func (c *Client) APIMeta() (*APIMeta, *Response, error) {
req, err := c.NewRequest("GET", "meta", nil)
if err != nil {
return nil, nil, err
}
meta := new(APIMeta)
resp, err := c.Do(req, meta)
if err != nil {
return nil, resp, err
}
return meta, resp, nil
}
// Octocat returns an ASCII art octocat with the specified message in a speech
// bubble. If message is empty, a random zen phrase is used.
func (c *Client) Octocat(message string) (string, *Response, error) {
u := "octocat"
if message != "" {
u = fmt.Sprintf("%s?s=%s", u, url.QueryEscape(message))
}
req, err := c.NewRequest("GET", u, nil)
if err != nil {
return "", nil, err
}
buf := new(bytes.Buffer)
resp, err := c.Do(req, buf)
if err != nil {
return "", resp, err
}
return buf.String(), resp, nil
}
// Zen returns a random line from The Zen of GitHub.
//
// see also: http://warpspire.com/posts/taste/
func (c *Client) Zen() (string, *Response, error) {
req, err := c.NewRequest("GET", "zen", nil)
if err != nil {
return "", nil, err
}
buf := new(bytes.Buffer)
resp, err := c.Do(req, buf)
if err != nil {
return "", resp, err
}
return buf.String(), resp, nil
}
// ServiceHook represents a hook that has configuration settings, a list of
// available events, and default events.
type ServiceHook struct {
Name *string `json:"name,omitempty"`
Events []string `json:"events,omitempty"`
SupportedEvents []string `json:"supported_events,omitempty"`
Schema [][]string `json:"schema,omitempty"`
}
func (s *ServiceHook) String() string {
return Stringify(s)
}
// ListServiceHooks lists all of the available service hooks.
//
// GitHub API docs: https://developer.github.com/webhooks/#services
func (c *Client) ListServiceHooks() ([]ServiceHook, *Response, error) {
u := "hooks"
req, err := c.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
hooks := new([]ServiceHook)
resp, err := c.Do(req, hooks)
if err != nil {
return nil, resp, err
}
return *hooks, resp, err
}

170
vendor/github.com/google/go-github/github/misc_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,170 @@
// Copyright 2014 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 (
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
)
func TestMarkdown(t *testing.T) {
setup()
defer teardown()
input := &markdownRequest{
Text: String("# text #"),
Mode: String("gfm"),
Context: String("google/go-github"),
}
mux.HandleFunc("/markdown", func(w http.ResponseWriter, r *http.Request) {
v := new(markdownRequest)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "POST")
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `<h1>text</h1>`)
})
md, _, err := client.Markdown("# text #", &MarkdownOptions{
Mode: "gfm",
Context: "google/go-github",
})
if err != nil {
t.Errorf("Markdown returned error: %v", err)
}
if want := "<h1>text</h1>"; want != md {
t.Errorf("Markdown returned %+v, want %+v", md, want)
}
}
func TestListEmojis(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/emojis", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"+1": "+1.png"}`)
})
emoji, _, err := client.ListEmojis()
if err != nil {
t.Errorf("ListEmojis returned error: %v", err)
}
want := map[string]string{"+1": "+1.png"}
if !reflect.DeepEqual(want, emoji) {
t.Errorf("ListEmojis returned %+v, want %+v", emoji, want)
}
}
func TestAPIMeta(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/meta", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"hooks":["h"], "git":["g"], "pages":["p"], "verifiable_password_authentication": true}`)
})
meta, _, err := client.APIMeta()
if err != nil {
t.Errorf("APIMeta returned error: %v", err)
}
want := &APIMeta{
Hooks: []string{"h"},
Git: []string{"g"},
Pages: []string{"p"},
VerifiablePasswordAuthentication: Bool(true),
}
if !reflect.DeepEqual(want, meta) {
t.Errorf("APIMeta returned %+v, want %+v", meta, want)
}
}
func TestOctocat(t *testing.T) {
setup()
defer teardown()
input := "input"
output := "sample text"
mux.HandleFunc("/octocat", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{"s": input})
w.Header().Set("Content-Type", "application/octocat-stream")
fmt.Fprint(w, output)
})
got, _, err := client.Octocat(input)
if err != nil {
t.Errorf("Octocat returned error: %v", err)
}
if want := output; got != want {
t.Errorf("Octocat returned %+v, want %+v", got, want)
}
}
func TestZen(t *testing.T) {
setup()
defer teardown()
output := "sample text"
mux.HandleFunc("/zen", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.Header().Set("Content-Type", "text/plain;charset=utf-8")
fmt.Fprint(w, output)
})
got, _, err := client.Zen()
if err != nil {
t.Errorf("Zen returned error: %v", err)
}
if want := output; got != want {
t.Errorf("Zen returned %+v, want %+v", got, want)
}
}
func TestRepositoriesService_ListServiceHooks(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/hooks", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `[{
"name":"n",
"events":["e"],
"supported_events":["s"],
"schema":[
["a", "b"]
]
}]`)
})
hooks, _, err := client.Repositories.ListServiceHooks()
if err != nil {
t.Errorf("Repositories.ListHooks returned error: %v", err)
}
want := []ServiceHook{{
Name: String("n"),
Events: []string{"e"},
SupportedEvents: []string{"s"},
Schema: [][]string{{"a", "b"}},
}}
if !reflect.DeepEqual(hooks, want) {
t.Errorf("Repositories.ListServiceHooks returned %+v, want %+v", hooks, want)
}
}

137
vendor/github.com/google/go-github/github/orgs.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,137 @@
// 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"
"time"
)
// OrganizationsService provides access to the organization related functions
// in the GitHub API.
//
// GitHub API docs: http://developer.github.com/v3/orgs/
type OrganizationsService struct {
client *Client
}
// Organization represents a GitHub organization account.
type Organization struct {
Login *string `json:"login,omitempty"`
ID *int `json:"id,omitempty"`
AvatarURL *string `json:"avatar_url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
Name *string `json:"name,omitempty"`
Company *string `json:"company,omitempty"`
Blog *string `json:"blog,omitempty"`
Location *string `json:"location,omitempty"`
Email *string `json:"email,omitempty"`
PublicRepos *int `json:"public_repos,omitempty"`
PublicGists *int `json:"public_gists,omitempty"`
Followers *int `json:"followers,omitempty"`
Following *int `json:"following,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
TotalPrivateRepos *int `json:"total_private_repos,omitempty"`
OwnedPrivateRepos *int `json:"owned_private_repos,omitempty"`
PrivateGists *int `json:"private_gists,omitempty"`
DiskUsage *int `json:"disk_usage,omitempty"`
Collaborators *int `json:"collaborators,omitempty"`
BillingEmail *string `json:"billing_email,omitempty"`
Type *string `json:"type,omitempty"`
Plan *Plan `json:"plan,omitempty"`
// API URLs
URL *string `json:"url,omitempty"`
EventsURL *string `json:"events_url,omitempty"`
MembersURL *string `json:"members_url,omitempty"`
PublicMembersURL *string `json:"public_members_url,omitempty"`
ReposURL *string `json:"repos_url,omitempty"`
}
func (o Organization) String() string {
return Stringify(o)
}
// Plan represents the payment plan for an account. See plans at https://github.com/plans.
type Plan struct {
Name *string `json:"name,omitempty"`
Space *int `json:"space,omitempty"`
Collaborators *int `json:"collaborators,omitempty"`
PrivateRepos *int `json:"private_repos,omitempty"`
}
func (p Plan) String() string {
return Stringify(p)
}
// List the organizations for a user. Passing the empty string will list
// organizations for the authenticated user.
//
// GitHub API docs: http://developer.github.com/v3/orgs/#list-user-organizations
func (s *OrganizationsService) List(user string, opt *ListOptions) ([]Organization, *Response, error) {
var u string
if user != "" {
u = fmt.Sprintf("users/%v/orgs", user)
} else {
u = "user/orgs"
}
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
}
orgs := new([]Organization)
resp, err := s.client.Do(req, orgs)
if err != nil {
return nil, resp, err
}
return *orgs, resp, err
}
// Get fetches an organization by name.
//
// GitHub API docs: http://developer.github.com/v3/orgs/#get-an-organization
func (s *OrganizationsService) Get(org string) (*Organization, *Response, error) {
u := fmt.Sprintf("orgs/%v", org)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
organization := new(Organization)
resp, err := s.client.Do(req, organization)
if err != nil {
return nil, resp, err
}
return organization, resp, err
}
// Edit an organization.
//
// GitHub API docs: http://developer.github.com/v3/orgs/#edit-an-organization
func (s *OrganizationsService) Edit(name string, org *Organization) (*Organization, *Response, error) {
u := fmt.Sprintf("orgs/%v", name)
req, err := s.client.NewRequest("PATCH", u, org)
if err != nil {
return nil, nil, err
}
o := new(Organization)
resp, err := s.client.Do(req, o)
if err != nil {
return nil, resp, err
}
return o, resp, err
}

104
vendor/github.com/google/go-github/github/orgs_hooks.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,104 @@
// Copyright 2015 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"
// ListHooks lists all Hooks for the specified organization.
//
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#list-hooks
func (s *OrganizationsService) ListHooks(org string, opt *ListOptions) ([]Hook, *Response, error) {
u := fmt.Sprintf("orgs/%v/hooks", org)
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
}
hooks := new([]Hook)
resp, err := s.client.Do(req, hooks)
if err != nil {
return nil, resp, err
}
return *hooks, resp, err
}
// GetHook returns a single specified Hook.
//
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#get-single-hook
func (s *OrganizationsService) GetHook(org string, id int) (*Hook, *Response, error) {
u := fmt.Sprintf("orgs/%v/hooks/%d", org, id)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
hook := new(Hook)
resp, err := s.client.Do(req, hook)
return hook, resp, err
}
// CreateHook creates a Hook for the specified org.
// Name and Config are required fields.
//
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#create-a-hook
func (s *OrganizationsService) CreateHook(org string, hook *Hook) (*Hook, *Response, error) {
u := fmt.Sprintf("orgs/%v/hooks", org)
req, err := s.client.NewRequest("POST", u, hook)
if err != nil {
return nil, nil, err
}
h := new(Hook)
resp, err := s.client.Do(req, h)
if err != nil {
return nil, resp, err
}
return h, resp, err
}
// EditHook updates a specified Hook.
//
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#edit-a-hook
func (s *OrganizationsService) EditHook(org string, id int, hook *Hook) (*Hook, *Response, error) {
u := fmt.Sprintf("orgs/%v/hooks/%d", org, id)
req, err := s.client.NewRequest("PATCH", u, hook)
if err != nil {
return nil, nil, err
}
h := new(Hook)
resp, err := s.client.Do(req, h)
return h, resp, err
}
// PingHook triggers a 'ping' event to be sent to the Hook.
//
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#ping-a-hook
func (s *OrganizationsService) PingHook(org string, id int) (*Response, error) {
u := fmt.Sprintf("orgs/%v/hooks/%d/pings", org, id)
req, err := s.client.NewRequest("POST", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}
// DeleteHook deletes a specified Hook.
//
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#delete-a-hook
func (s *OrganizationsService) DeleteHook(org string, id int) (*Response, error) {
u := fmt.Sprintf("orgs/%v/hooks/%d", org, id)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}

134
vendor/github.com/google/go-github/github/orgs_hooks_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,134 @@
// Copyright 2015 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 (
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
)
func TestOrganizationsService_ListHooks(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/hooks", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{"page": "2"})
fmt.Fprint(w, `[{"id":1}, {"id":2}]`)
})
opt := &ListOptions{Page: 2}
hooks, _, err := client.Organizations.ListHooks("o", opt)
if err != nil {
t.Errorf("Organizations.ListHooks returned error: %v", err)
}
want := []Hook{{ID: Int(1)}, {ID: Int(2)}}
if !reflect.DeepEqual(hooks, want) {
t.Errorf("Organizations.ListHooks returned %+v, want %+v", hooks, want)
}
}
func TestOrganizationsService_ListHooks_invalidOrg(t *testing.T) {
_, _, err := client.Organizations.ListHooks("%", nil)
testURLParseError(t, err)
}
func TestOrganizationsService_GetHook(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/hooks/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"id":1}`)
})
hook, _, err := client.Organizations.GetHook("o", 1)
if err != nil {
t.Errorf("Organizations.GetHook returned error: %v", err)
}
want := &Hook{ID: Int(1)}
if !reflect.DeepEqual(hook, want) {
t.Errorf("Organizations.GetHook returned %+v, want %+v", hook, want)
}
}
func TestOrganizationsService_GetHook_invalidOrg(t *testing.T) {
_, _, err := client.Organizations.GetHook("%", 1)
testURLParseError(t, err)
}
func TestOrganizationsService_EditHook(t *testing.T) {
setup()
defer teardown()
input := &Hook{Name: String("t")}
mux.HandleFunc("/orgs/o/hooks/1", func(w http.ResponseWriter, r *http.Request) {
v := new(Hook)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PATCH")
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `{"id":1}`)
})
hook, _, err := client.Organizations.EditHook("o", 1, input)
if err != nil {
t.Errorf("Organizations.EditHook returned error: %v", err)
}
want := &Hook{ID: Int(1)}
if !reflect.DeepEqual(hook, want) {
t.Errorf("Organizations.EditHook returned %+v, want %+v", hook, want)
}
}
func TestOrganizationsService_EditHook_invalidOrg(t *testing.T) {
_, _, err := client.Organizations.EditHook("%", 1, nil)
testURLParseError(t, err)
}
func TestOrganizationsService_PingHook(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/hooks/1/pings", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "POST")
})
_, err := client.Organizations.PingHook("o", 1)
if err != nil {
t.Errorf("Organizations.PingHook returned error: %v", err)
}
}
func TestOrganizationsService_DeleteHook(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/hooks/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
})
_, err := client.Organizations.DeleteHook("o", 1)
if err != nil {
t.Errorf("Organizations.DeleteHook returned error: %v", err)
}
}
func TestOrganizationsService_DeleteHook_invalidOrg(t *testing.T) {
_, err := client.Organizations.DeleteHook("%", 1)
testURLParseError(t, err)
}

276
vendor/github.com/google/go-github/github/orgs_members.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,276 @@
// 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"
// Membership represents the status of a user's membership in an organization or team.
type Membership struct {
URL *string `json:"url,omitempty"`
// State is the user's status within the organization or team.
// Possible values are: "active", "pending"
State *string `json:"state,omitempty"`
// Role identifies the user's role within the organization or team.
// Possible values for organization membership:
// member - non-owner organization member
// admin - organization owner
//
// Possible values for team membership are:
// member - a normal member of the team
// maintainer - a team maintainer. Able to add/remove other team
// members, promote other team members to team
// maintainer, and edit the teams name and description
Role *string `json:"role,omitempty"`
// For organization membership, the API URL of the organization.
OrganizationURL *string `json:"organization_url,omitempty"`
// For organization membership, the organization the membership is for.
Organization *Organization `json:"organization,omitempty"`
// For organization membership, the user the membership is for.
User *User `json:"user,omitempty"`
}
func (m Membership) String() string {
return Stringify(m)
}
// ListMembersOptions specifies optional parameters to the
// OrganizationsService.ListMembers method.
type ListMembersOptions struct {
// If true (or if the authenticated user is not an owner of the
// organization), list only publicly visible members.
PublicOnly bool `url:"-"`
// Filter members returned in the list. Possible values are:
// 2fa_disabled, all. Default is "all".
Filter string `url:"filter,omitempty"`
// Role filters memebers returned by their role in the organization.
// Possible values are:
// all - all members of the organization, regardless of role
// admin - organization owners
// member - non-organization members
//
// Default is "all".
Role string `url:"role,omitempty"`
ListOptions
}
// ListMembers lists the members for an organization. If the authenticated
// user is an owner of the organization, this will return both concealed and
// public members, otherwise it will only return public members.
//
// GitHub API docs: http://developer.github.com/v3/orgs/members/#members-list
func (s *OrganizationsService) ListMembers(org string, opt *ListMembersOptions) ([]User, *Response, error) {
var u string
if opt != nil && opt.PublicOnly {
u = fmt.Sprintf("orgs/%v/public_members", org)
} else {
u = fmt.Sprintf("orgs/%v/members", org)
}
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
}
if opt != nil && opt.Role != "" {
req.Header.Set("Accept", mediaTypeOrgPermissionPreview)
}
members := new([]User)
resp, err := s.client.Do(req, members)
if err != nil {
return nil, resp, err
}
return *members, resp, err
}
// IsMember checks if a user is a member of an organization.
//
// GitHub API docs: http://developer.github.com/v3/orgs/members/#check-membership
func (s *OrganizationsService) IsMember(org, user string) (bool, *Response, error) {
u := fmt.Sprintf("orgs/%v/members/%v", org, user)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return false, nil, err
}
resp, err := s.client.Do(req, nil)
member, err := parseBoolResponse(err)
return member, resp, err
}
// IsPublicMember checks if a user is a public member of an organization.
//
// GitHub API docs: http://developer.github.com/v3/orgs/members/#check-public-membership
func (s *OrganizationsService) IsPublicMember(org, user string) (bool, *Response, error) {
u := fmt.Sprintf("orgs/%v/public_members/%v", org, user)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return false, nil, err
}
resp, err := s.client.Do(req, nil)
member, err := parseBoolResponse(err)
return member, resp, err
}
// RemoveMember removes a user from all teams of an organization.
//
// GitHub API docs: http://developer.github.com/v3/orgs/members/#remove-a-member
func (s *OrganizationsService) RemoveMember(org, user string) (*Response, error) {
u := fmt.Sprintf("orgs/%v/members/%v", org, user)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}
// PublicizeMembership publicizes a user's membership in an organization. (A
// user cannot publicize the membership for another user.)
//
// GitHub API docs: http://developer.github.com/v3/orgs/members/#publicize-a-users-membership
func (s *OrganizationsService) PublicizeMembership(org, user string) (*Response, error) {
u := fmt.Sprintf("orgs/%v/public_members/%v", org, user)
req, err := s.client.NewRequest("PUT", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}
// ConcealMembership conceals a user's membership in an organization.
//
// GitHub API docs: http://developer.github.com/v3/orgs/members/#conceal-a-users-membership
func (s *OrganizationsService) ConcealMembership(org, user string) (*Response, error) {
u := fmt.Sprintf("orgs/%v/public_members/%v", org, user)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}
// ListOrgMembershipsOptions specifies optional parameters to the
// OrganizationsService.ListOrgMemberships method.
type ListOrgMembershipsOptions struct {
// Filter memberships to include only those with the specified state.
// Possible values are: "active", "pending".
State string `url:"state,omitempty"`
ListOptions
}
// ListOrgMemberships lists the organization memberships for the authenticated user.
//
// GitHub API docs: https://developer.github.com/v3/orgs/members/#list-your-organization-memberships
func (s *OrganizationsService) ListOrgMemberships(opt *ListOrgMembershipsOptions) ([]Membership, *Response, error) {
u := "user/memberships/orgs"
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
}
var memberships []Membership
resp, err := s.client.Do(req, &memberships)
if err != nil {
return nil, resp, err
}
return memberships, resp, err
}
// GetOrgMembership gets the membership for a user in a specified organization.
// Passing an empty string for user will get the membership for the
// authenticated user.
//
// GitHub API docs: https://developer.github.com/v3/orgs/members/#get-organization-membership
// GitHub API docs: https://developer.github.com/v3/orgs/members/#get-your-organization-membership
func (s *OrganizationsService) GetOrgMembership(user, org string) (*Membership, *Response, error) {
var u string
if user != "" {
u = fmt.Sprintf("orgs/%v/memberships/%v", org, user)
} else {
u = fmt.Sprintf("user/memberships/orgs/%v", org)
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
membership := new(Membership)
resp, err := s.client.Do(req, membership)
if err != nil {
return nil, resp, err
}
return membership, resp, err
}
// EditOrgMembership edits the membership for user in specified organization.
// Passing an empty string for user will edit the membership for the
// authenticated user.
//
// 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, 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(method, u, membership)
if err != nil {
return nil, nil, err
}
m := new(Membership)
resp, err := s.client.Do(req, m)
if err != nil {
return nil, resp, err
}
return m, resp, err
}
// RemoveOrgMembership removes user from the specified organization. If the
// user has been invited to the organization, this will cancel their invitation.
//
// GitHub API docs: https://developer.github.com/v3/orgs/members/#remove-organization-membership
func (s *OrganizationsService) RemoveOrgMembership(user, org string) (*Response, error) {
u := fmt.Sprintf("orgs/%v/memberships/%v", org, user)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}

356
vendor/github.com/google/go-github/github/orgs_members_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,356 @@
// 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 (
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
)
func TestOrganizationsService_ListMembers(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/members", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeOrgPermissionPreview)
testFormValues(t, r, values{
"filter": "2fa_disabled",
"role": "admin",
"page": "2",
})
fmt.Fprint(w, `[{"id":1}]`)
})
opt := &ListMembersOptions{
PublicOnly: false,
Filter: "2fa_disabled",
Role: "admin",
ListOptions: ListOptions{Page: 2},
}
members, _, err := client.Organizations.ListMembers("o", opt)
if err != nil {
t.Errorf("Organizations.ListMembers returned error: %v", err)
}
want := []User{{ID: Int(1)}}
if !reflect.DeepEqual(members, want) {
t.Errorf("Organizations.ListMembers returned %+v, want %+v", members, want)
}
}
func TestOrganizationsService_ListMembers_invalidOrg(t *testing.T) {
_, _, err := client.Organizations.ListMembers("%", nil)
testURLParseError(t, err)
}
func TestOrganizationsService_ListMembers_public(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/public_members", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `[{"id":1}]`)
})
opt := &ListMembersOptions{PublicOnly: true}
members, _, err := client.Organizations.ListMembers("o", opt)
if err != nil {
t.Errorf("Organizations.ListMembers returned error: %v", err)
}
want := []User{{ID: Int(1)}}
if !reflect.DeepEqual(members, want) {
t.Errorf("Organizations.ListMembers returned %+v, want %+v", members, want)
}
}
func TestOrganizationsService_IsMember(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/members/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.WriteHeader(http.StatusNoContent)
})
member, _, err := client.Organizations.IsMember("o", "u")
if err != nil {
t.Errorf("Organizations.IsMember returned error: %v", err)
}
if want := true; member != want {
t.Errorf("Organizations.IsMember returned %+v, want %+v", member, want)
}
}
// ensure that a 404 response is interpreted as "false" and not an error
func TestOrganizationsService_IsMember_notMember(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/members/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.WriteHeader(http.StatusNotFound)
})
member, _, err := client.Organizations.IsMember("o", "u")
if err != nil {
t.Errorf("Organizations.IsMember returned error: %+v", err)
}
if want := false; member != want {
t.Errorf("Organizations.IsMember returned %+v, want %+v", member, want)
}
}
// ensure that a 400 response is interpreted as an actual error, and not simply
// as "false" like the above case of a 404
func TestOrganizationsService_IsMember_error(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/members/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
http.Error(w, "BadRequest", http.StatusBadRequest)
})
member, _, err := client.Organizations.IsMember("o", "u")
if err == nil {
t.Errorf("Expected HTTP 400 response")
}
if want := false; member != want {
t.Errorf("Organizations.IsMember returned %+v, want %+v", member, want)
}
}
func TestOrganizationsService_IsMember_invalidOrg(t *testing.T) {
_, _, err := client.Organizations.IsMember("%", "u")
testURLParseError(t, err)
}
func TestOrganizationsService_IsPublicMember(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/public_members/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.WriteHeader(http.StatusNoContent)
})
member, _, err := client.Organizations.IsPublicMember("o", "u")
if err != nil {
t.Errorf("Organizations.IsPublicMember returned error: %v", err)
}
if want := true; member != want {
t.Errorf("Organizations.IsPublicMember returned %+v, want %+v", member, want)
}
}
// ensure that a 404 response is interpreted as "false" and not an error
func TestOrganizationsService_IsPublicMember_notMember(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/public_members/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.WriteHeader(http.StatusNotFound)
})
member, _, err := client.Organizations.IsPublicMember("o", "u")
if err != nil {
t.Errorf("Organizations.IsPublicMember returned error: %v", err)
}
if want := false; member != want {
t.Errorf("Organizations.IsPublicMember returned %+v, want %+v", member, want)
}
}
// ensure that a 400 response is interpreted as an actual error, and not simply
// as "false" like the above case of a 404
func TestOrganizationsService_IsPublicMember_error(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/public_members/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
http.Error(w, "BadRequest", http.StatusBadRequest)
})
member, _, err := client.Organizations.IsPublicMember("o", "u")
if err == nil {
t.Errorf("Expected HTTP 400 response")
}
if want := false; member != want {
t.Errorf("Organizations.IsPublicMember returned %+v, want %+v", member, want)
}
}
func TestOrganizationsService_IsPublicMember_invalidOrg(t *testing.T) {
_, _, err := client.Organizations.IsPublicMember("%", "u")
testURLParseError(t, err)
}
func TestOrganizationsService_RemoveMember(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/members/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
})
_, err := client.Organizations.RemoveMember("o", "u")
if err != nil {
t.Errorf("Organizations.RemoveMember returned error: %v", err)
}
}
func TestOrganizationsService_RemoveMember_invalidOrg(t *testing.T) {
_, err := client.Organizations.RemoveMember("%", "u")
testURLParseError(t, err)
}
func TestOrganizationsService_ListOrgMemberships(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/user/memberships/orgs", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"state": "active",
"page": "2",
})
fmt.Fprint(w, `[{"url":"u"}]`)
})
opt := &ListOrgMembershipsOptions{
State: "active",
ListOptions: ListOptions{Page: 2},
}
memberships, _, err := client.Organizations.ListOrgMemberships(opt)
if err != nil {
t.Errorf("Organizations.ListOrgMemberships returned error: %v", err)
}
want := []Membership{{URL: String("u")}}
if !reflect.DeepEqual(memberships, want) {
t.Errorf("Organizations.ListOrgMemberships returned %+v, want %+v", memberships, want)
}
}
func TestOrganizationsService_GetOrgMembership_AuthenticatedUser(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/user/memberships/orgs/o", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"url":"u"}`)
})
membership, _, err := client.Organizations.GetOrgMembership("", "o")
if err != nil {
t.Errorf("Organizations.GetOrgMembership returned error: %v", err)
}
want := &Membership{URL: String("u")}
if !reflect.DeepEqual(membership, want) {
t.Errorf("Organizations.GetOrgMembership returned %+v, want %+v", membership, want)
}
}
func TestOrganizationsService_GetOrgMembership_SpecifiedUser(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/memberships/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"url":"u"}`)
})
membership, _, err := client.Organizations.GetOrgMembership("u", "o")
if err != nil {
t.Errorf("Organizations.GetOrgMembership returned error: %v", err)
}
want := &Membership{URL: String("u")}
if !reflect.DeepEqual(membership, want) {
t.Errorf("Organizations.GetOrgMembership returned %+v, want %+v", membership, want)
}
}
func TestOrganizationsService_EditOrgMembership_AuthenticatedUser(t *testing.T) {
setup()
defer teardown()
input := &Membership{State: String("active")}
mux.HandleFunc("/user/memberships/orgs/o", func(w http.ResponseWriter, r *http.Request) {
v := new(Membership)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PATCH")
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `{"url":"u"}`)
})
membership, _, err := client.Organizations.EditOrgMembership("", "o", input)
if err != nil {
t.Errorf("Organizations.EditOrgMembership returned error: %v", err)
}
want := &Membership{URL: String("u")}
if !reflect.DeepEqual(membership, want) {
t.Errorf("Organizations.EditOrgMembership returned %+v, want %+v", membership, want)
}
}
func TestOrganizationsService_EditOrgMembership_SpecifiedUser(t *testing.T) {
setup()
defer teardown()
input := &Membership{State: String("active")}
mux.HandleFunc("/orgs/o/memberships/u", func(w http.ResponseWriter, r *http.Request) {
v := new(Membership)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PUT")
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `{"url":"u"}`)
})
membership, _, err := client.Organizations.EditOrgMembership("u", "o", input)
if err != nil {
t.Errorf("Organizations.EditOrgMembership returned error: %v", err)
}
want := &Membership{URL: String("u")}
if !reflect.DeepEqual(membership, want) {
t.Errorf("Organizations.EditOrgMembership returned %+v, want %+v", membership, want)
}
}
func TestOrganizationsService_RemoveOrgMembership(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/memberships/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
w.WriteHeader(http.StatusNoContent)
})
_, err := client.Organizations.RemoveOrgMembership("u", "o")
if err != nil {
t.Errorf("Organizations.RemoveOrgMembership returned error: %v", err)
}
}

396
vendor/github.com/google/go-github/github/orgs_teams.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,396 @@
// 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"
// Team represents a team within a GitHub organization. Teams are used to
// manage access to an organization's repositories.
type Team struct {
ID *int `json:"id,omitempty"`
Name *string `json:"name,omitempty"`
URL *string `json:"url,omitempty"`
Slug *string `json:"slug,omitempty"`
// Permission is deprecated when creating or editing a team in an org
// using the new GitHub permission model. It no longer identifies the
// permission a team has on its repos, but only specifies the default
// permission a repo is initially added with. Avoid confusion by
// specifying a permission value when calling AddTeamRepo.
Permission *string `json:"permission,omitempty"`
// Privacy identifies the level of privacy this team should have.
// Possible values are:
// secret - only visible to organization owners and members of this team
// closed - visible to all members of this organization
// Default is "secret".
Privacy *string `json:"privacy,omitempty"`
MembersCount *int `json:"members_count,omitempty"`
ReposCount *int `json:"repos_count,omitempty"`
Organization *Organization `json:"organization,omitempty"`
}
func (t Team) String() string {
return Stringify(t)
}
// ListTeams lists all of the teams for an organization.
//
// GitHub API docs: http://developer.github.com/v3/orgs/teams/#list-teams
func (s *OrganizationsService) ListTeams(org string, opt *ListOptions) ([]Team, *Response, error) {
u := fmt.Sprintf("orgs/%v/teams", org)
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
}
teams := new([]Team)
resp, err := s.client.Do(req, teams)
if err != nil {
return nil, resp, err
}
return *teams, resp, err
}
// GetTeam fetches a team by ID.
//
// GitHub API docs: http://developer.github.com/v3/orgs/teams/#get-team
func (s *OrganizationsService) GetTeam(team int) (*Team, *Response, error) {
u := fmt.Sprintf("teams/%v", team)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
t := new(Team)
resp, err := s.client.Do(req, t)
if err != nil {
return nil, resp, err
}
return t, resp, err
}
// CreateTeam creates a new team within an organization.
//
// GitHub API docs: http://developer.github.com/v3/orgs/teams/#create-team
func (s *OrganizationsService) CreateTeam(org string, team *Team) (*Team, *Response, error) {
u := fmt.Sprintf("orgs/%v/teams", org)
req, err := s.client.NewRequest("POST", u, team)
if err != nil {
return nil, nil, err
}
if team.Privacy != nil {
req.Header.Set("Accept", mediaTypeOrgPermissionPreview)
}
t := new(Team)
resp, err := s.client.Do(req, t)
if err != nil {
return nil, resp, err
}
return t, resp, err
}
// EditTeam edits a team.
//
// GitHub API docs: http://developer.github.com/v3/orgs/teams/#edit-team
func (s *OrganizationsService) EditTeam(id int, team *Team) (*Team, *Response, error) {
u := fmt.Sprintf("teams/%v", id)
req, err := s.client.NewRequest("PATCH", u, team)
if err != nil {
return nil, nil, err
}
if team.Privacy != nil {
req.Header.Set("Accept", mediaTypeOrgPermissionPreview)
}
t := new(Team)
resp, err := s.client.Do(req, t)
if err != nil {
return nil, resp, err
}
return t, resp, err
}
// DeleteTeam deletes a team.
//
// GitHub API docs: http://developer.github.com/v3/orgs/teams/#delete-team
func (s *OrganizationsService) DeleteTeam(team int) (*Response, error) {
u := fmt.Sprintf("teams/%v", team)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}
// OrganizationListTeamMembersOptions specifies the optional parameters to the
// OrganizationsService.ListTeamMembers method.
type OrganizationListTeamMembersOptions struct {
// Role filters members returned by their role in the team. Possible
// values are "all", "member", "maintainer". Default is "all".
Role string `url:"role,omitempty"`
ListOptions
}
// ListTeamMembers lists all of the users who are members of the specified
// team.
//
// GitHub API docs: http://developer.github.com/v3/orgs/teams/#list-team-members
func (s *OrganizationsService) ListTeamMembers(team int, opt *OrganizationListTeamMembersOptions) ([]User, *Response, error) {
u := fmt.Sprintf("teams/%v/members", team)
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
}
if opt != nil && opt.Role != "" {
req.Header.Set("Accept", mediaTypeOrgPermissionPreview)
}
members := new([]User)
resp, err := s.client.Do(req, members)
if err != nil {
return nil, resp, err
}
return *members, resp, err
}
// IsTeamMember checks if a user is a member of the specified team.
//
// GitHub API docs: http://developer.github.com/v3/orgs/teams/#get-team-member
func (s *OrganizationsService) IsTeamMember(team int, user string) (bool, *Response, error) {
u := fmt.Sprintf("teams/%v/members/%v", team, user)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return false, nil, err
}
resp, err := s.client.Do(req, nil)
member, err := parseBoolResponse(err)
return member, resp, err
}
// ListTeamRepos lists the repositories that the specified team has access to.
//
// GitHub API docs: http://developer.github.com/v3/orgs/teams/#list-team-repos
func (s *OrganizationsService) ListTeamRepos(team int, opt *ListOptions) ([]Repository, *Response, error) {
u := fmt.Sprintf("teams/%v/repos", team)
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
}
repos := new([]Repository)
resp, err := s.client.Do(req, repos)
if err != nil {
return nil, resp, err
}
return *repos, resp, err
}
// IsTeamRepo checks if a team manages the specified repository. If the
// repository is managed by team, a Repository is returned which includes the
// permissions team has for that repo.
//
// GitHub API docs: http://developer.github.com/v3/orgs/teams/#get-team-repo
func (s *OrganizationsService) IsTeamRepo(team int, owner string, repo string) (*Repository, *Response, error) {
u := fmt.Sprintf("teams/%v/repos/%v/%v", team, owner, repo)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeOrgPermissionRepoPreview)
repository := new(Repository)
resp, err := s.client.Do(req, repository)
if err != nil {
return nil, resp, err
}
return repository, resp, err
}
// OrganizationAddTeamRepoOptions specifies the optional parameters to the
// OrganizationsService.AddTeamRepo method.
type OrganizationAddTeamRepoOptions struct {
// Permission specifies the permission to grant the team on this repository.
// Possible values are:
// pull - team members can pull, but not push to or administer this repository
// push - team members can pull and push, but not administer this repository
// admin - team members can pull, push and administer this repository
//
// If not specified, the team's permission attribute will be used.
Permission string `json:"permission,omitempty"`
}
// AddTeamRepo adds a repository to be managed by the specified team. The
// specified repository must be owned by the organization to which the team
// belongs, or a direct fork of a repository owned by the organization.
//
// GitHub API docs: http://developer.github.com/v3/orgs/teams/#add-team-repo
func (s *OrganizationsService) AddTeamRepo(team int, owner string, repo string, opt *OrganizationAddTeamRepoOptions) (*Response, error) {
u := fmt.Sprintf("teams/%v/repos/%v/%v", team, owner, repo)
req, err := s.client.NewRequest("PUT", u, opt)
if err != nil {
return nil, err
}
if opt != nil {
req.Header.Set("Accept", mediaTypeOrgPermissionPreview)
}
return s.client.Do(req, nil)
}
// RemoveTeamRepo removes a repository from being managed by the specified
// team. Note that this does not delete the repository, it just removes it
// from the team.
//
// GitHub API docs: http://developer.github.com/v3/orgs/teams/#remove-team-repo
func (s *OrganizationsService) RemoveTeamRepo(team int, owner string, repo string) (*Response, error) {
u := fmt.Sprintf("teams/%v/repos/%v/%v", team, owner, repo)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}
// ListUserTeams lists a user's teams
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#list-user-teams
func (s *OrganizationsService) ListUserTeams(opt *ListOptions) ([]Team, *Response, error) {
u := "user/teams"
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
}
teams := new([]Team)
resp, err := s.client.Do(req, teams)
if err != nil {
return nil, resp, err
}
return *teams, resp, err
}
// GetTeamMembership returns the membership status for a user in a team.
//
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#get-team-membership
func (s *OrganizationsService) GetTeamMembership(team int, user string) (*Membership, *Response, error) {
u := fmt.Sprintf("teams/%v/memberships/%v", team, user)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
t := new(Membership)
resp, err := s.client.Do(req, t)
if err != nil {
return nil, resp, err
}
return t, resp, err
}
// OrganizationAddTeamMembershipOptions does stuff specifies the optional
// parameters to the OrganizationsService.AddTeamMembership method.
type OrganizationAddTeamMembershipOptions struct {
// Role specifies the role the user should have in the team. Possible
// values are:
// member - a normal member of the team
// maintainer - a team maintainer. Able to add/remove other team
// members, promote other team members to team
// maintainer, and edit the teams name and description
//
// Default value is "member".
Role string `json:"role,omitempty"`
}
// AddTeamMembership adds or invites a user to a team.
//
// In order to add a membership between a user and a team, the authenticated
// user must have 'admin' permissions to the team or be an owner of the
// organization that the team is associated with.
//
// If the user is already a part of the team's organization (meaning they're on
// at least one other team in the organization), this endpoint will add the
// user to the team.
//
// If the user is completely unaffiliated with the team's organization (meaning
// they're on none of the organization's teams), this endpoint will send an
// invitation to the user via email. This newly-created membership will be in
// the "pending" state until the user accepts the invitation, at which point
// the membership will transition to the "active" state and the user will be
// added as a member of the team.
//
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#add-team-membership
func (s *OrganizationsService) AddTeamMembership(team int, user string, opt *OrganizationAddTeamMembershipOptions) (*Membership, *Response, error) {
u := fmt.Sprintf("teams/%v/memberships/%v", team, user)
req, err := s.client.NewRequest("PUT", u, opt)
if err != nil {
return nil, nil, err
}
if opt != nil {
req.Header.Set("Accept", mediaTypeOrgPermissionPreview)
}
t := new(Membership)
resp, err := s.client.Do(req, t)
if err != nil {
return nil, resp, err
}
return t, resp, err
}
// RemoveTeamMembership removes a user from a team.
//
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#remove-team-membership
func (s *OrganizationsService) RemoveTeamMembership(team int, user string) (*Response, error) {
u := fmt.Sprintf("teams/%v/memberships/%v", team, user)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}

506
vendor/github.com/google/go-github/github/orgs_teams_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,506 @@
// 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 (
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
)
func TestOrganizationsService_ListTeams(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/teams", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{"page": "2"})
fmt.Fprint(w, `[{"id":1}]`)
})
opt := &ListOptions{Page: 2}
teams, _, err := client.Organizations.ListTeams("o", opt)
if err != nil {
t.Errorf("Organizations.ListTeams returned error: %v", err)
}
want := []Team{{ID: Int(1)}}
if !reflect.DeepEqual(teams, want) {
t.Errorf("Organizations.ListTeams returned %+v, want %+v", teams, want)
}
}
func TestOrganizationsService_ListTeams_invalidOrg(t *testing.T) {
_, _, err := client.Organizations.ListTeams("%", nil)
testURLParseError(t, err)
}
func TestOrganizationsService_GetTeam(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"id":1, "name":"n", "url":"u", "slug": "s", "permission":"p"}`)
})
team, _, err := client.Organizations.GetTeam(1)
if err != nil {
t.Errorf("Organizations.GetTeam returned error: %v", err)
}
want := &Team{ID: Int(1), Name: String("n"), URL: String("u"), Slug: String("s"), Permission: String("p")}
if !reflect.DeepEqual(team, want) {
t.Errorf("Organizations.GetTeam returned %+v, want %+v", team, want)
}
}
func TestOrganizationsService_CreateTeam(t *testing.T) {
setup()
defer teardown()
input := &Team{Name: String("n"), Privacy: String("closed")}
mux.HandleFunc("/orgs/o/teams", func(w http.ResponseWriter, r *http.Request) {
v := new(Team)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "POST")
testHeader(t, r, "Accept", mediaTypeOrgPermissionPreview)
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `{"id":1}`)
})
team, _, err := client.Organizations.CreateTeam("o", input)
if err != nil {
t.Errorf("Organizations.CreateTeam returned error: %v", err)
}
want := &Team{ID: Int(1)}
if !reflect.DeepEqual(team, want) {
t.Errorf("Organizations.CreateTeam returned %+v, want %+v", team, want)
}
}
func TestOrganizationsService_CreateTeam_invalidOrg(t *testing.T) {
_, _, err := client.Organizations.CreateTeam("%", nil)
testURLParseError(t, err)
}
func TestOrganizationsService_EditTeam(t *testing.T) {
setup()
defer teardown()
input := &Team{Name: String("n"), Privacy: String("closed")}
mux.HandleFunc("/teams/1", func(w http.ResponseWriter, r *http.Request) {
v := new(Team)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PATCH")
testHeader(t, r, "Accept", mediaTypeOrgPermissionPreview)
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `{"id":1}`)
})
team, _, err := client.Organizations.EditTeam(1, input)
if err != nil {
t.Errorf("Organizations.EditTeam returned error: %v", err)
}
want := &Team{ID: Int(1)}
if !reflect.DeepEqual(team, want) {
t.Errorf("Organizations.EditTeam returned %+v, want %+v", team, want)
}
}
func TestOrganizationsService_DeleteTeam(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
})
_, err := client.Organizations.DeleteTeam(1)
if err != nil {
t.Errorf("Organizations.DeleteTeam returned error: %v", err)
}
}
func TestOrganizationsService_ListTeamMembers(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/members", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeOrgPermissionPreview)
testFormValues(t, r, values{"role": "member", "page": "2"})
fmt.Fprint(w, `[{"id":1}]`)
})
opt := &OrganizationListTeamMembersOptions{Role: "member", ListOptions: ListOptions{Page: 2}}
members, _, err := client.Organizations.ListTeamMembers(1, opt)
if err != nil {
t.Errorf("Organizations.ListTeamMembers returned error: %v", err)
}
want := []User{{ID: Int(1)}}
if !reflect.DeepEqual(members, want) {
t.Errorf("Organizations.ListTeamMembers returned %+v, want %+v", members, want)
}
}
func TestOrganizationsService_IsTeamMember_true(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/members/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
})
member, _, err := client.Organizations.IsTeamMember(1, "u")
if err != nil {
t.Errorf("Organizations.IsTeamMember returned error: %v", err)
}
if want := true; member != want {
t.Errorf("Organizations.IsTeamMember returned %+v, want %+v", member, want)
}
}
// ensure that a 404 response is interpreted as "false" and not an error
func TestOrganizationsService_IsTeamMember_false(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/members/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.WriteHeader(http.StatusNotFound)
})
member, _, err := client.Organizations.IsTeamMember(1, "u")
if err != nil {
t.Errorf("Organizations.IsTeamMember returned error: %+v", err)
}
if want := false; member != want {
t.Errorf("Organizations.IsTeamMember returned %+v, want %+v", member, want)
}
}
// ensure that a 400 response is interpreted as an actual error, and not simply
// as "false" like the above case of a 404
func TestOrganizationsService_IsTeamMember_error(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/members/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
http.Error(w, "BadRequest", http.StatusBadRequest)
})
member, _, err := client.Organizations.IsTeamMember(1, "u")
if err == nil {
t.Errorf("Expected HTTP 400 response")
}
if want := false; member != want {
t.Errorf("Organizations.IsTeamMember returned %+v, want %+v", member, want)
}
}
func TestOrganizationsService_IsTeamMember_invalidUser(t *testing.T) {
_, _, err := client.Organizations.IsTeamMember(1, "%")
testURLParseError(t, err)
}
func TestOrganizationsService_PublicizeMembership(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/public_members/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "PUT")
w.WriteHeader(http.StatusNoContent)
})
_, err := client.Organizations.PublicizeMembership("o", "u")
if err != nil {
t.Errorf("Organizations.PublicizeMembership returned error: %v", err)
}
}
func TestOrganizationsService_PublicizeMembership_invalidOrg(t *testing.T) {
_, err := client.Organizations.PublicizeMembership("%", "u")
testURLParseError(t, err)
}
func TestOrganizationsService_ConcealMembership(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/public_members/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
w.WriteHeader(http.StatusNoContent)
})
_, err := client.Organizations.ConcealMembership("o", "u")
if err != nil {
t.Errorf("Organizations.ConcealMembership returned error: %v", err)
}
}
func TestOrganizationsService_ConcealMembership_invalidOrg(t *testing.T) {
_, err := client.Organizations.ConcealMembership("%", "u")
testURLParseError(t, err)
}
func TestOrganizationsService_ListTeamRepos(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/repos", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{"page": "2"})
fmt.Fprint(w, `[{"id":1}]`)
})
opt := &ListOptions{Page: 2}
members, _, err := client.Organizations.ListTeamRepos(1, opt)
if err != nil {
t.Errorf("Organizations.ListTeamRepos returned error: %v", err)
}
want := []Repository{{ID: Int(1)}}
if !reflect.DeepEqual(members, want) {
t.Errorf("Organizations.ListTeamRepos returned %+v, want %+v", members, want)
}
}
func TestOrganizationsService_IsTeamRepo_true(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/repos/o/r", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeOrgPermissionRepoPreview)
fmt.Fprint(w, `{"id":1}`)
})
repo, _, err := client.Organizations.IsTeamRepo(1, "o", "r")
if err != nil {
t.Errorf("Organizations.IsTeamRepo returned error: %v", err)
}
want := &Repository{ID: Int(1)}
if !reflect.DeepEqual(repo, want) {
t.Errorf("Organizations.IsTeamRepo returned %+v, want %+v", repo, want)
}
}
func TestOrganizationsService_IsTeamRepo_false(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/repos/o/r", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.WriteHeader(http.StatusNotFound)
})
repo, resp, err := client.Organizations.IsTeamRepo(1, "o", "r")
if err == nil {
t.Errorf("Expected HTTP 404 response")
}
if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want {
t.Errorf("Organizations.IsTeamRepo returned status %d, want %d", got, want)
}
if repo != nil {
t.Errorf("Organizations.IsTeamRepo returned %+v, want nil", repo)
}
}
func TestOrganizationsService_IsTeamRepo_error(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/repos/o/r", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
http.Error(w, "BadRequest", http.StatusBadRequest)
})
repo, resp, err := client.Organizations.IsTeamRepo(1, "o", "r")
if err == nil {
t.Errorf("Expected HTTP 400 response")
}
if got, want := resp.Response.StatusCode, http.StatusBadRequest; got != want {
t.Errorf("Organizations.IsTeamRepo returned status %d, want %d", got, want)
}
if repo != nil {
t.Errorf("Organizations.IsTeamRepo returned %+v, want nil", repo)
}
}
func TestOrganizationsService_IsTeamRepo_invalidOwner(t *testing.T) {
_, _, err := client.Organizations.IsTeamRepo(1, "%", "r")
testURLParseError(t, err)
}
func TestOrganizationsService_AddTeamRepo(t *testing.T) {
setup()
defer teardown()
opt := &OrganizationAddTeamRepoOptions{Permission: "admin"}
mux.HandleFunc("/teams/1/repos/o/r", func(w http.ResponseWriter, r *http.Request) {
v := new(OrganizationAddTeamRepoOptions)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PUT")
testHeader(t, r, "Accept", mediaTypeOrgPermissionPreview)
if !reflect.DeepEqual(v, opt) {
t.Errorf("Request body = %+v, want %+v", v, opt)
}
w.WriteHeader(http.StatusNoContent)
})
_, err := client.Organizations.AddTeamRepo(1, "o", "r", opt)
if err != nil {
t.Errorf("Organizations.AddTeamRepo returned error: %v", err)
}
}
func TestOrganizationsService_AddTeamRepo_noAccess(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/repos/o/r", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "PUT")
w.WriteHeader(422)
})
_, err := client.Organizations.AddTeamRepo(1, "o", "r", nil)
if err == nil {
t.Errorf("Expcted error to be returned")
}
}
func TestOrganizationsService_AddTeamRepo_invalidOwner(t *testing.T) {
_, err := client.Organizations.AddTeamRepo(1, "%", "r", nil)
testURLParseError(t, err)
}
func TestOrganizationsService_RemoveTeamRepo(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/repos/o/r", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
w.WriteHeader(http.StatusNoContent)
})
_, err := client.Organizations.RemoveTeamRepo(1, "o", "r")
if err != nil {
t.Errorf("Organizations.RemoveTeamRepo returned error: %v", err)
}
}
func TestOrganizationsService_RemoveTeamRepo_invalidOwner(t *testing.T) {
_, err := client.Organizations.RemoveTeamRepo(1, "%", "r")
testURLParseError(t, err)
}
func TestOrganizationsService_GetTeamMembership(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/memberships/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"url":"u", "state":"active"}`)
})
membership, _, err := client.Organizations.GetTeamMembership(1, "u")
if err != nil {
t.Errorf("Organizations.GetTeamMembership returned error: %v", err)
}
want := &Membership{URL: String("u"), State: String("active")}
if !reflect.DeepEqual(membership, want) {
t.Errorf("Organizations.GetTeamMembership returned %+v, want %+v", membership, want)
}
}
func TestOrganizationsService_AddTeamMembership(t *testing.T) {
setup()
defer teardown()
opt := &OrganizationAddTeamMembershipOptions{Role: "maintainer"}
mux.HandleFunc("/teams/1/memberships/u", func(w http.ResponseWriter, r *http.Request) {
v := new(OrganizationAddTeamMembershipOptions)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PUT")
testHeader(t, r, "Accept", mediaTypeOrgPermissionPreview)
if !reflect.DeepEqual(v, opt) {
t.Errorf("Request body = %+v, want %+v", v, opt)
}
fmt.Fprint(w, `{"url":"u", "state":"pending"}`)
})
membership, _, err := client.Organizations.AddTeamMembership(1, "u", opt)
if err != nil {
t.Errorf("Organizations.AddTeamMembership returned error: %v", err)
}
want := &Membership{URL: String("u"), State: String("pending")}
if !reflect.DeepEqual(membership, want) {
t.Errorf("Organizations.AddTeamMembership returned %+v, want %+v", membership, want)
}
}
func TestOrganizationsService_RemoveTeamMembership(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/memberships/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
w.WriteHeader(http.StatusNoContent)
})
_, err := client.Organizations.RemoveTeamMembership(1, "u")
if err != nil {
t.Errorf("Organizations.RemoveTeamMembership returned error: %v", err)
}
}
func TestOrganizationsService_ListUserTeams(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/user/teams", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{"page": "1"})
fmt.Fprint(w, `[{"id":1}]`)
})
opt := &ListOptions{Page: 1}
teams, _, err := client.Organizations.ListUserTeams(opt)
if err != nil {
t.Errorf("Organizations.ListUserTeams returned error: %v", err)
}
want := []Team{{ID: Int(1)}}
if !reflect.DeepEqual(teams, want) {
t.Errorf("Organizations.ListUserTeams returned %+v, want %+v", teams, want)
}
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше