mirror of
https://github.com/Luzifer/repo-template.git
synced 2024-11-10 16:40:04 +00:00
149 lines
3.6 KiB
Go
149 lines
3.6 KiB
Go
|
// 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.
|
||
|
|
||
|
// This tool tests for the JSON mappings in the go-github data types. It will
|
||
|
// identify fields that are returned by the live GitHub API, but that are not
|
||
|
// currently mapped into a struct field of the relevant go-github type. This
|
||
|
// helps to ensure that all relevant data returned by the API is being made
|
||
|
// accessible, particularly new fields that are periodically (and sometimes
|
||
|
// quietly) added to the API over time.
|
||
|
//
|
||
|
// These tests simply aid in identifying which fields aren't being mapped; it
|
||
|
// is not necessarily true that every one of them should always be mapped.
|
||
|
// Some fields may be undocumented for a reason, either because they aren't
|
||
|
// actually used yet or should not be relied upon.
|
||
|
package main
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"encoding/json"
|
||
|
"flag"
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"reflect"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/google/go-github/github"
|
||
|
"golang.org/x/oauth2"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
client *github.Client
|
||
|
|
||
|
// auth indicates whether tests are being run with an OAuth token.
|
||
|
// Tests can use this flag to skip certain tests when run without auth.
|
||
|
auth bool
|
||
|
|
||
|
skipURLs = flag.Bool("skip_urls", false, "skip url fields")
|
||
|
)
|
||
|
|
||
|
func main() {
|
||
|
flag.Parse()
|
||
|
|
||
|
token := os.Getenv("GITHUB_AUTH_TOKEN")
|
||
|
if token == "" {
|
||
|
print("!!! No OAuth token. Some tests won't run. !!!\n\n")
|
||
|
client = github.NewClient(nil)
|
||
|
} else {
|
||
|
tc := oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(
|
||
|
&oauth2.Token{AccessToken: token},
|
||
|
))
|
||
|
client = github.NewClient(tc)
|
||
|
auth = true
|
||
|
}
|
||
|
|
||
|
for _, tt := range []struct {
|
||
|
url string
|
||
|
typ interface{}
|
||
|
}{
|
||
|
//{"rate_limit", &github.RateLimits{}},
|
||
|
{"users/octocat", &github.User{}},
|
||
|
{"user", &github.User{}},
|
||
|
{"users/willnorris/keys", &[]github.Key{}},
|
||
|
{"orgs/google-test", &github.Organization{}},
|
||
|
{"repos/google/go-github", &github.Repository{}},
|
||
|
{"repos/google/go-github/issues/1", &github.Issue{}},
|
||
|
{"/gists/9257657", &github.Gist{}},
|
||
|
} {
|
||
|
err := testType(tt.url, tt.typ)
|
||
|
if err != nil {
|
||
|
fmt.Printf("error: %v\n", err)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// testType fetches the JSON resource at urlStr and compares its keys to the
|
||
|
// struct fields of typ.
|
||
|
func testType(urlStr string, typ interface{}) error {
|
||
|
slice := reflect.Indirect(reflect.ValueOf(typ)).Kind() == reflect.Slice
|
||
|
|
||
|
req, err := client.NewRequest("GET", urlStr, nil)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// start with a json.RawMessage so we can decode multiple ways below
|
||
|
raw := new(json.RawMessage)
|
||
|
_, err = client.Do(context.Background(), req, raw)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// unmarshal directly to a map
|
||
|
var m1 map[string]interface{}
|
||
|
if slice {
|
||
|
var s []map[string]interface{}
|
||
|
err = json.Unmarshal(*raw, &s)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
m1 = s[0]
|
||
|
} else {
|
||
|
err = json.Unmarshal(*raw, &m1)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// unmarshal to typ first, then re-marshal and unmarshal to a map
|
||
|
err = json.Unmarshal(*raw, typ)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
var byt []byte
|
||
|
if slice {
|
||
|
// use first item in slice
|
||
|
v := reflect.Indirect(reflect.ValueOf(typ))
|
||
|
byt, err = json.Marshal(v.Index(0).Interface())
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
} else {
|
||
|
byt, err = json.Marshal(typ)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var m2 map[string]interface{}
|
||
|
err = json.Unmarshal(byt, &m2)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// now compare the two maps
|
||
|
for k, v := range m1 {
|
||
|
if *skipURLs && strings.HasSuffix(k, "_url") {
|
||
|
continue
|
||
|
}
|
||
|
if _, ok := m2[k]; !ok {
|
||
|
fmt.Printf("%v missing field for key: %v (example value: %v)\n", reflect.TypeOf(typ), k, v)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|