add prune and remove unused packages

This commit is contained in:
Michelle Au
2019-03-08 14:54:43 -08:00
parent f59b58d164
commit 8c0accad66
17240 changed files with 27 additions and 4750030 deletions

View File

@@ -1,4 +0,0 @@
reviewers:
- roycaihw
approvers:
- roycaihw

View File

@@ -1,23 +0,0 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package rules contains API rules that are enforced in OpenAPI spec generation
// as part of the machinery. Files under this package implement APIRule interface
// which evaluates Go type and produces list of API rule violations.
//
// Implementations of APIRule should be added to API linter under openAPIGen code-
// generator to get integrated in the generation process.
package rules

View File

@@ -1,172 +0,0 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package rules
import (
"reflect"
"strings"
"k8s.io/kube-openapi/pkg/util/sets"
"k8s.io/gengo/types"
)
var (
// Blacklist of JSON tags that should skip match evaluation
jsonTagBlacklist = sets.NewString(
// Omitted field is ignored by the package
"-",
)
// Blacklist of JSON names that should skip match evaluation
jsonNameBlacklist = sets.NewString(
// Empty name is used for inline struct field (e.g. metav1.TypeMeta)
"",
// Special case for object and list meta
"metadata",
)
// List of substrings that aren't allowed in Go name and JSON name
disallowedNameSubstrings = sets.NewString(
// Underscore is not allowed in either name
"_",
// Dash is not allowed in either name. Note that since dash is a valid JSON tag, this should be checked
// after JSON tag blacklist check.
"-",
)
)
/*
NamesMatch implements APIRule interface.
Go field names must be CamelCase. JSON field names must be camelCase. Other than capitalization of the
initial letter, the two should almost always match. No underscores nor dashes in either.
This rule verifies the convention "Other than capitalization of the initial letter, the two should almost always match."
Examples (also in unit test):
Go name | JSON name | match
podSpec false
PodSpec podSpec true
PodSpec PodSpec false
podSpec podSpec false
PodSpec spec false
Spec podSpec false
JSONSpec jsonSpec true
JSONSpec jsonspec false
HTTPJSONSpec httpJSONSpec true
NOTE: this validator cannot tell two sequential all-capital words from one word, therefore the case below
is also considered matched.
HTTPJSONSpec httpjsonSpec true
NOTE: JSON names in jsonNameBlacklist should skip evaluation
true
podSpec true
podSpec - true
podSpec metadata true
*/
type NamesMatch struct{}
// Name returns the name of APIRule
func (n *NamesMatch) Name() string {
return "names_match"
}
// Validate evaluates API rule on type t and returns a list of field names in
// the type that violate the rule. Empty field name [""] implies the entire
// type violates the rule.
func (n *NamesMatch) Validate(t *types.Type) ([]string, error) {
fields := make([]string, 0)
// Only validate struct type and ignore the rest
switch t.Kind {
case types.Struct:
for _, m := range t.Members {
goName := m.Name
jsonTag, ok := reflect.StructTag(m.Tags).Lookup("json")
// Distinguish empty JSON tag and missing JSON tag. Empty JSON tag / name is
// allowed (in JSON name blacklist) but missing JSON tag is invalid.
if !ok {
fields = append(fields, goName)
continue
}
if jsonTagBlacklist.Has(jsonTag) {
continue
}
jsonName := strings.Split(jsonTag, ",")[0]
if !namesMatch(goName, jsonName) {
fields = append(fields, goName)
}
}
}
return fields, nil
}
// namesMatch evaluates if goName and jsonName match the API rule
// TODO: Use an off-the-shelf CamelCase solution instead of implementing this logic. The following existing
// packages have been tried out:
// github.com/markbates/inflect
// github.com/segmentio/go-camelcase
// github.com/iancoleman/strcase
// github.com/fatih/camelcase
// Please see https://github.com/kubernetes/kube-openapi/pull/83#issuecomment-400842314 for more details
// about why they don't satisfy our need. What we need can be a function that detects an acronym at the
// beginning of a string.
func namesMatch(goName, jsonName string) bool {
if jsonNameBlacklist.Has(jsonName) {
return true
}
if !isAllowedName(goName) || !isAllowedName(jsonName) {
return false
}
if strings.ToLower(goName) != strings.ToLower(jsonName) {
return false
}
// Go field names must be CamelCase. JSON field names must be camelCase.
if !isCapital(goName[0]) || isCapital(jsonName[0]) {
return false
}
for i := 0; i < len(goName); i++ {
if goName[i] == jsonName[i] {
// goName[0:i-1] is uppercase and jsonName[0:i-1] is lowercase, goName[i:]
// and jsonName[i:] should match;
// goName[i] should be lowercase if i is equal to 1, e.g.:
// goName | jsonName
// PodSpec podSpec
// or uppercase if i is greater than 1, e.g.:
// goname | jsonName
// JSONSpec jsonSpec
// This is to rule out cases like:
// goname | jsonName
// JSONSpec jsonspec
return goName[i:] == jsonName[i:] && (i == 1 || isCapital(goName[i]))
}
}
return true
}
// isCaptical returns true if one character is capital
func isCapital(b byte) bool {
return b >= 'A' && b <= 'Z'
}
// isAllowedName checks the list of disallowedNameSubstrings and returns true if name doesn't contain
// any disallowed substring.
func isAllowedName(name string) bool {
for _, substr := range disallowedNameSubstrings.UnsortedList() {
if strings.Contains(name, substr) {
return false
}
}
return true
}

View File

@@ -1,359 +0,0 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package rules
import (
"reflect"
"testing"
"k8s.io/gengo/types"
)
func TestNamesMatch(t *testing.T) {
tcs := []struct {
// name of test case
name string
t *types.Type
// expected list of violation fields
expected []string
}{
// The comments are in format of {goName, jsonName, match},
// {"PodSpec", "podSpec", true},
{
name: "simple",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "PodSpec",
Tags: `json:"podSpec"`,
},
},
},
expected: []string{},
},
// {"PodSpec", "podSpec", true},
{
name: "multiple_json_tags",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "PodSpec",
Tags: `json:"podSpec,omitempty"`,
},
},
},
expected: []string{},
},
// {"PodSpec", "podSpec", true},
{
name: "protobuf_tag",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "PodSpec",
Tags: `json:"podSpec,omitempty" protobuf:"bytes,1,opt,name=podSpec"`,
},
},
},
expected: []string{},
},
// {"", "podSpec", false},
{
name: "empty",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "",
Tags: `json:"podSpec"`,
},
},
},
expected: []string{""},
},
// {"PodSpec", "PodSpec", false},
{
name: "CamelCase_CamelCase",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "PodSpec",
Tags: `json:"PodSpec"`,
},
},
},
expected: []string{"PodSpec"},
},
// {"podSpec", "podSpec", false},
{
name: "camelCase_camelCase",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "podSpec",
Tags: `json:"podSpec"`,
},
},
},
expected: []string{"podSpec"},
},
// {"PodSpec", "spec", false},
{
name: "short_json_name",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "PodSpec",
Tags: `json:"spec"`,
},
},
},
expected: []string{"PodSpec"},
},
// {"Spec", "podSpec", false},
{
name: "long_json_name",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "Spec",
Tags: `json:"podSpec"`,
},
},
},
expected: []string{"Spec"},
},
// {"JSONSpec", "jsonSpec", true},
{
name: "acronym",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "JSONSpec",
Tags: `json:"jsonSpec"`,
},
},
},
expected: []string{},
},
// {"JSONSpec", "jsonspec", false},
{
name: "acronym_invalid",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "JSONSpec",
Tags: `json:"jsonspec"`,
},
},
},
expected: []string{"JSONSpec"},
},
// {"HTTPJSONSpec", "httpJSONSpec", true},
{
name: "multiple_acronym",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "HTTPJSONSpec",
Tags: `json:"httpJSONSpec"`,
},
},
},
expected: []string{},
},
// // NOTE: this validator cannot tell two sequential all-capital words from one word,
// // therefore the case below is also considered matched.
// {"HTTPJSONSpec", "httpjsonSpec", true},
{
name: "multiple_acronym_as_one",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "HTTPJSONSpec",
Tags: `json:"httpjsonSpec"`,
},
},
},
expected: []string{},
},
// NOTE: JSON tags in jsonTagBlacklist should skip evaluation
{
name: "blacklist_tag_dash",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "podSpec",
Tags: `json:"-"`,
},
},
},
expected: []string{},
},
// {"PodSpec", "-", false},
{
name: "invalid_json_name_dash",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "PodSpec",
Tags: `json:"-,"`,
},
},
},
expected: []string{"PodSpec"},
},
// NOTE: JSON names in jsonNameBlacklist should skip evaluation
// {"", "", true},
{
name: "unspecified",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "",
Tags: `json:""`,
},
},
},
expected: []string{},
},
// {"podSpec", "", true},
{
name: "blacklist_empty",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "podSpec",
Tags: `json:""`,
},
},
},
expected: []string{},
},
// {"podSpec", "metadata", true},
{
name: "blacklist_metadata",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "podSpec",
Tags: `json:"metadata"`,
},
},
},
expected: []string{},
},
{
name: "non_struct",
t: &types.Type{
Kind: types.Map,
},
expected: []string{},
},
{
name: "no_json_tag",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "PodSpec",
Tags: `podSpec`,
},
},
},
expected: []string{"PodSpec"},
},
// NOTE: this is to expand test coverage
// {"S", "s", true},
{
name: "single_character",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "S",
Tags: `json:"s"`,
},
},
},
expected: []string{},
},
// NOTE: names with disallowed substrings should fail evaluation
// {"Pod-Spec", "pod-Spec", false},
{
name: "disallowed_substring_dash",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "Pod-Spec",
Tags: `json:"pod-Spec"`,
},
},
},
expected: []string{"Pod-Spec"},
},
// {"Pod_Spec", "pod_Spec", false},
{
name: "disallowed_substring_underscore",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "Pod_Spec",
Tags: `json:"pod_Spec"`,
},
},
},
expected: []string{"Pod_Spec"},
},
}
n := &NamesMatch{}
for _, tc := range tcs {
if violations, _ := n.Validate(tc.t); !reflect.DeepEqual(violations, tc.expected) {
t.Errorf("unexpected validation result: test name %v, want: %v, got: %v",
tc.name, tc.expected, violations)
}
}
}
// TestRuleName tests the Name of API rule. This is to expand test coverage
func TestRuleName(t *testing.T) {
ruleName := "names_match"
n := &NamesMatch{}
if n.Name() != ruleName {
t.Errorf("unexpected API rule name: want: %v, got: %v", ruleName, n.Name())
}
}

View File

@@ -1,64 +0,0 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package rules
import (
"reflect"
"strings"
"k8s.io/gengo/types"
)
// OmitEmptyMatchCase implements APIRule interface.
// "omitempty" must appear verbatim (no case variants).
type OmitEmptyMatchCase struct{}
func (n *OmitEmptyMatchCase) Name() string {
return "omitempty_match_case"
}
func (n *OmitEmptyMatchCase) Validate(t *types.Type) ([]string, error) {
fields := make([]string, 0)
// Only validate struct type and ignore the rest
switch t.Kind {
case types.Struct:
for _, m := range t.Members {
goName := m.Name
jsonTag, ok := reflect.StructTag(m.Tags).Lookup("json")
if !ok {
continue
}
parts := strings.Split(jsonTag, ",")
if len(parts) < 2 {
// no tags other than name
continue
}
if parts[0] == "-" {
// not serialized
continue
}
for _, part := range parts[1:] {
if strings.EqualFold(part, "omitempty") && part != "omitempty" {
fields = append(fields, goName)
}
}
}
}
return fields, nil
}

View File

@@ -1,110 +0,0 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package rules
import (
"reflect"
"testing"
"k8s.io/gengo/types"
)
func TestOmitEmptyMatchCase(t *testing.T) {
tcs := []struct {
// name of test case
name string
t *types.Type
// expected list of violation fields
expected []string
}{
{
name: "simple",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "PodSpec",
Tags: `json:"podSpec"`,
},
},
},
expected: []string{},
},
{
name: "unserialized",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "PodSpec",
Tags: `json:"-,inline"`,
},
},
},
expected: []string{},
},
{
name: "named_omitEmpty",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "OmitEmpty",
Tags: `json:"omitEmpty,inline"`,
},
},
},
expected: []string{},
},
{
name: "valid",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "PodSpec",
Tags: `json:"podSpec,omitempty"`,
},
},
},
expected: []string{},
},
{
name: "invalid",
t: &types.Type{
Kind: types.Struct,
Members: []types.Member{
types.Member{
Name: "PodSpec",
Tags: `json:"podSpec,omitEmpty"`,
},
},
},
expected: []string{"PodSpec"},
},
}
n := &OmitEmptyMatchCase{}
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
if violations, _ := n.Validate(tc.t); !reflect.DeepEqual(violations, tc.expected) {
t.Errorf("unexpected validation result: want: %v, got: %v", tc.expected, violations)
}
})
}
}