github.com/googleapis/api-linter@v1.65.2/rules/aip0154/declarative_friendly_required.go (about) 1 // Copyright 2020 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 aip0154 16 17 import ( 18 "fmt" 19 "strings" 20 21 "github.com/googleapis/api-linter/lint" 22 "github.com/googleapis/api-linter/rules/internal/utils" 23 "github.com/jhump/protoreflect/desc" 24 ) 25 26 var declarativeFriendlyRequired = &lint.MessageRule{ 27 Name: lint.NewRuleName(154, "declarative-friendly-required"), 28 OnlyIf: func(m *desc.MessageDescriptor) bool { 29 // Sanity check: If the resource is not declarative-friendly, none of 30 // this logic applies. 31 if resource := utils.DeclarativeFriendlyResource(m); resource != nil { 32 // This should apply if the resource in question is declarative-friendly, 33 // but our IsDeclarativeFriendly method will return true for both 34 // resources and request messages, and they need to be handled subtly 35 // differently. 36 if m == resource { 37 return true 38 } 39 40 // If this is a request message, then make several more checks based on 41 // what the method looks like. 42 if name := m.GetName(); strings.HasSuffix(name, "Request") { 43 name = strings.TrimSuffix(name, "Request") 44 45 // If this is a GET request, then this message is exempt. 46 if method := utils.FindMethod(m.GetFile(), name); method != nil { 47 for _, rule := range utils.GetHTTPRules(method) { 48 if rule.Method == "GET" { 49 return false 50 } 51 } 52 } 53 54 // If the message contains the resource, then this message is exempt. 55 for _, field := range m.GetFields() { 56 if field.GetMessageType() == resource { 57 return false 58 } 59 } 60 61 // Okay, this message should include an etag. 62 return true 63 } 64 } 65 66 return false 67 }, 68 LintMessage: func(m *desc.MessageDescriptor) []lint.Problem { 69 for _, field := range m.GetFields() { 70 if field.GetName() == "etag" { 71 return nil 72 } 73 } 74 75 whoami := "resources" 76 if strings.HasSuffix(m.GetName(), "Request") { 77 whoami = "mutation requests without the resource" 78 } 79 return []lint.Problem{{ 80 Message: fmt.Sprintf("Declarative-friendly %s should include `string etag`.", whoami), 81 Descriptor: m, 82 }} 83 }, 84 }