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  }