github.com/googleapis/api-linter@v1.65.2/rules/aip0133/request_parent_required.go (about) 1 package aip0133 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/googleapis/api-linter/lint" 8 "github.com/googleapis/api-linter/rules/internal/utils" 9 "github.com/jhump/protoreflect/desc" 10 "github.com/stoewer/go-strcase" 11 ) 12 13 var requestParentRequired = &lint.MessageRule{ 14 Name: lint.NewRuleName(133, "request-parent-required"), 15 OnlyIf: utils.IsCreateRequestMessage, 16 LintMessage: func(m *desc.MessageDescriptor) []lint.Problem { 17 if m.FindFieldByName("parent") == nil { 18 // Sanity check: If the resource has a pattern, and that pattern 19 // contains only one variable, then a parent field is not expected. 20 // 21 // In order to parse out the pattern, we get the resource message 22 // from the request, then get the resource annotation from that, 23 // and then inspect the pattern there (oy!). 24 singular := getResourceMsgNameFromReq(m) 25 if field := m.FindFieldByName(strcase.SnakeCase(singular)); field != nil { 26 if hasNoParent(field.GetMessageType()) { 27 return nil 28 } 29 } 30 31 // Nope, this is not the unusual case, and a parent field is expected. 32 return []lint.Problem{{ 33 Message: fmt.Sprintf("Message %q has no `parent` field", m.GetName()), 34 Descriptor: m, 35 }} 36 } 37 38 return nil 39 }, 40 } 41 42 func hasNoParent(m *desc.MessageDescriptor) bool { 43 if resource := utils.GetResource(m); resource != nil { 44 for _, pattern := range resource.GetPattern() { 45 if strings.Count(pattern, "{") == 1 { 46 return true 47 } 48 } 49 } 50 return false 51 }