Skip to content

Commit

Permalink
rebuilt operation tags functions
Browse files Browse the repository at this point in the history
  • Loading branch information
daveshanley committed Jul 9, 2024
1 parent 7b4c1fe commit 34b0a75
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 82 deletions.
94 changes: 29 additions & 65 deletions functions/openapi/operation_tag_defined.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import (
"fmt"
"github.com/daveshanley/vacuum/model"
vacuumUtils "github.com/daveshanley/vacuum/utils"
"github.com/pb33f/libopenapi/utils"
"github.com/pb33f/doctor/model/high/base"
"gopkg.in/yaml.v3"
"strings"
)

// TagDefined is a rule that checks if an operation uses a tag, it's also defined in the global tag definitions.
Expand All @@ -27,82 +28,45 @@ func (td TagDefined) GetCategory() string {
}

// RunRule will execute the TagDefined rule, based on supplied context and a supplied []*yaml.Node slice.
func (td TagDefined) RunRule(nodes []*yaml.Node, context model.RuleFunctionContext) []model.RuleFunctionResult {

if len(nodes) <= 0 {
return nil
}
func (td TagDefined) RunRule(_ []*yaml.Node, context model.RuleFunctionContext) []model.RuleFunctionResult {

var results []model.RuleFunctionResult

seenGlobalTags := make(map[string]bool)
tagsNode := context.Index.GetGlobalTagsNode()
pathsNode := context.Index.GetPathsNode()

if tagsNode != nil {
for _, tagNode := range tagsNode.Content {
_, tag := utils.FindKeyNode("name", []*yaml.Node{tagNode})
if tag != nil {
seenGlobalTags[tag.Value] = true
}
}
}

if pathsNode == nil {
if context.DrDocument == nil {
return results
}

for x, operationNode := range pathsNode.Content {
var currentPath string
var currentVerb string
if operationNode.Tag == "!!str" {
currentPath = operationNode.Value
var verbNode *yaml.Node
if x+1 == len(pathsNode.Content) {
verbNode = pathsNode.Content[x]
} else {
verbNode = pathsNode.Content[x+1]
}
for y, verbMapNode := range verbNode.Content {

if verbMapNode.Tag == "!!str" {
currentVerb = verbMapNode.Value
} else {
continue
}

var opTagsNode *yaml.Node
if y+1 < len(verbNode.Content) {
verbDataNode := verbNode.Content[y+1]
_, opTagsNode = utils.FindKeyNode("tags", verbDataNode.Content)
} else {
verbDataNode := verbNode.Content[y]
_, opTagsNode = utils.FindKeyNode("tags", verbDataNode.Content)
}
if opTagsNode != nil {

tagIndex := 0
for _, operationTag := range opTagsNode.Content {
if operationTag.Tag == "!!str" {
if !seenGlobalTags[operationTag.Value] {
results = append(results, model.RuleFunctionResult{
Message: fmt.Sprintf("the `%s` operation at path `%s` contains a "+
"tag `%s`, that is not defined in the global document tags",
currentVerb, currentPath, operationTag.Value),
StartNode: operationTag,
EndNode: vacuumUtils.BuildEndNode(operationTag),
Path: fmt.Sprintf("$.paths['%s'].%s.tags[%v]", currentPath, currentVerb, tagIndex),
Rule: context.Rule,
})
}
tagIndex++
globalTags := context.DrDocument.V3Document.Tags
globalTagMap := make(map[string]*base.Tag)
for _, tag := range globalTags {
globalTagMap[tag.Value.Name] = tag
}

paths := context.DrDocument.V3Document.Paths
if paths != nil && paths.PathItems != nil {
for pathItemPairs := paths.PathItems.First(); pathItemPairs != nil; pathItemPairs = pathItemPairs.Next() {
path := pathItemPairs.Key()
v := pathItemPairs.Value()
for opPairs := v.GetOperations().First(); opPairs != nil; opPairs = opPairs.Next() {
method := opPairs.Key()
op := opPairs.Value()
for i, tag := range op.Value.Tags {
if _, ok := globalTagMap[tag]; !ok {
res := model.RuleFunctionResult{
Message: vacuumUtils.SuppliedOrDefault(context.Rule.Message,
fmt.Sprintf("tag `%s` for `%s` operation is not defined as a global tag",
strings.ToUpper(tag), method)),
StartNode: op.Value.GoLow().Tags.Value[i].ValueNode,
EndNode: vacuumUtils.BuildEndNode(op.Value.GoLow().Tags.Value[i].ValueNode),
Path: fmt.Sprintf("$.paths['%s'].%s.tags[%v]", path, method, i),
Rule: context.Rule,
}
results = append(results, res)
op.AddRuleFunctionResult(base.ConvertRuleResult(&res))
}
}
}
}
}
return results

}
35 changes: 18 additions & 17 deletions functions/openapi/operation_tags.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,26 +41,27 @@ func (ot OperationTags) RunRule(nodes []*yaml.Node, context model.RuleFunctionCo
}

paths := context.DrDocument.V3Document.Paths
if paths != nil {
for pathItemPairs := paths.PathItems.First(); pathItemPairs != nil; pathItemPairs = pathItemPairs.Next() {
path := pathItemPairs.Key()
v := pathItemPairs.Value()

for pathItemPairs := paths.PathItems.First(); pathItemPairs != nil; pathItemPairs = pathItemPairs.Next() {
path := pathItemPairs.Key()
v := pathItemPairs.Value()
for opPairs := v.GetOperations().First(); opPairs != nil; opPairs = opPairs.Next() {
method := opPairs.Key()
op := opPairs.Value()

for opPairs := v.GetOperations().First(); opPairs != nil; opPairs = opPairs.Next() {
method := opPairs.Key()
op := opPairs.Value()

if len(op.Value.Tags) <= 0 {
res := model.RuleFunctionResult{
Message: vacuumUtils.SuppliedOrDefault(context.Rule.Message, fmt.Sprintf("tags for `%s` operation at are missing",
strings.ToUpper(method))),
StartNode: op.Value.GoLow().KeyNode,
EndNode: vacuumUtils.BuildEndNode(op.Value.GoLow().KeyNode),
Path: fmt.Sprintf("$.paths['%s'].%s", path, method),
Rule: context.Rule,
if len(op.Value.Tags) <= 0 {
res := model.RuleFunctionResult{
Message: vacuumUtils.SuppliedOrDefault(context.Rule.Message, fmt.Sprintf("tags for `%s` operation at are missing",
strings.ToUpper(method))),
StartNode: op.Value.GoLow().KeyNode,
EndNode: vacuumUtils.BuildEndNode(op.Value.GoLow().KeyNode),
Path: fmt.Sprintf("$.paths['%s'].%s", path, method),
Rule: context.Rule,
}
results = append(results, res)
op.AddRuleFunctionResult(base.ConvertRuleResult(&res))
}
results = append(results, res)
op.AddRuleFunctionResult(base.ConvertRuleResult(&res))
}
}
}
Expand Down

0 comments on commit 34b0a75

Please sign in to comment.