forked from google/go-github
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fields.go
148 lines (130 loc) · 3.61 KB
/
fields.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// 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/v47/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
}