github.com/googleapis/api-linter@v1.65.2/rules/internal/utils/resource.go (about) 1 // Copyright 2023 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package utils 16 17 import ( 18 "strings" 19 20 "github.com/jhump/protoreflect/desc" 21 apb "google.golang.org/genproto/googleapis/api/annotations" 22 ) 23 24 // GetResourceSingular returns the resource singular. The 25 // empty string is returned if the singular cannot be found. 26 // Since the singular is not always annotated, it extracts 27 // it from multiple different locations including: 28 // 1. the singular annotation 29 // 2. the type definition 30 func GetResourceSingular(r *apb.ResourceDescriptor) string { 31 if r == nil { 32 return "" 33 } 34 if r.Singular != "" { 35 return r.Singular 36 } 37 if r.Type != "" { 38 _, tn, ok := SplitResourceTypeName(r.Type) 39 if ok { 40 return tn 41 } 42 } 43 return "" 44 } 45 46 // GetResourcePlural is a convenience method for getting the `plural` field of a 47 // resource. 48 func GetResourcePlural(r *apb.ResourceDescriptor) string { 49 if r == nil { 50 return "" 51 } 52 53 return r.Plural 54 } 55 56 // GetResourceNameField is a convenience method for getting the name of the 57 // field that represents the resource's name. This is either set by the 58 // `name_field` attribute, or defaults to "name". 59 func GetResourceNameField(r *apb.ResourceDescriptor) string { 60 if r == nil { 61 return "" 62 } 63 if n := r.GetNameField(); n != "" { 64 return n 65 } 66 return "name" 67 } 68 69 // IsResourceRevision determines if the given message represents a resource 70 // revision as described in AIP-162. 71 func IsResourceRevision(m *desc.MessageDescriptor) bool { 72 return IsResource(m) && strings.HasSuffix(m.GetName(), "Revision") 73 } 74 75 // IsRevisionRelationship determines if the "revision" resource is actually 76 // a revision of the "parent" resource. 77 func IsRevisionRelationship(parent, revision *apb.ResourceDescriptor) bool { 78 _, pType, ok := SplitResourceTypeName(parent.GetType()) 79 if !ok { 80 return false 81 } 82 _, rType, ok := SplitResourceTypeName(revision.GetType()) 83 if !ok { 84 return false 85 } 86 87 if !strings.HasSuffix(rType, "Revision") { 88 return false 89 } 90 rType = strings.TrimSuffix(rType, "Revision") 91 return pType == rType 92 }