rules/terraform_resource_data_arg_layout.go (69 lines of code) (raw):
package rules
import (
"fmt"
"github.com/terraform-linters/tflint-plugin-sdk/logger"
"github.com/Azure/tflint-ruleset-basic-ext/project"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
)
type TerraformResourceDataArgLayoutRule struct {
tflint.DefaultRule
}
// NewTerraformResourceDataArgLayoutRule returns a new rule
func NewTerraformResourceDataArgLayoutRule() *TerraformResourceDataArgLayoutRule {
return &TerraformResourceDataArgLayoutRule{}
}
// Name returns the rule name
func (r *TerraformResourceDataArgLayoutRule) Name() string {
return "terraform_resource_data_arg_layout"
}
// Enabled returns whether the rule is enabled by default
func (r *TerraformResourceDataArgLayoutRule) Enabled() bool {
return false
}
// Severity returns the rule severity
func (r *TerraformResourceDataArgLayoutRule) Severity() tflint.Severity {
return tflint.NOTICE
}
// Link returns the rule reference link
func (r *TerraformResourceDataArgLayoutRule) Link() string {
return project.ReferenceLink(r.Name())
}
// Check checks whether the arguments/attributes in a block are sorted in azure doc Layout
func (r *TerraformResourceDataArgLayoutRule) Check(runner tflint.Runner) error {
files, err := runner.GetFiles()
if err != nil {
return err
}
for _, file := range files {
subErr := r.visitFile(runner, file)
if subErr != nil {
err = multierror.Append(err, subErr)
}
}
return err
}
func (r *TerraformResourceDataArgLayoutRule) visitFile(runner tflint.Runner, file *hcl.File) error {
body, ok := file.Body.(*hclsyntax.Body)
if !ok {
logger.Debug("skip terraform_resource_data_arg_layout check since it's not hcl file")
return nil
}
if body == nil {
return nil
}
var err error
for _, block := range body.Blocks {
switch block.Type {
case "resource", "data":
emitter := func(block Block) error {
return runner.EmitIssue(
r,
fmt.Sprintf("Arguments are expected to be arranged in following Layout:\n%s", block.ToString()),
block.DefRange(),
)
}
b := BuildResourceBlock(block, file, emitter)
if subErr := b.CheckBlock(); subErr != nil {
err = multierror.Append(err, subErr)
}
}
}
return err
}
//func (r *TerraformResourceDataArgLayoutRule) visitResourceDataBlock(runner tflint.Runner, block *hclsyntax.Block) error {
// issue := new(helper.Issue)
// r.visitBlock(runner, block, issue)
// if !r.isIssueEmpty(issue) {
// return runner.EmitIssue((*issue).Rule, (*issue).Message, (*issue).Range)
// }
// return nil
//}
//
//func (r *TerraformResourceDataArgLayoutRule) visitBlock(runner tflint.Runner, block *hclsyntax.Block, issue *helper.Issue) string {
// file, _ := runner.GetFile(block.Range().Filename)
// argGrps, isCorrectLayout := r.getSortedArgGrps(block)
// var sortedArgHclTxts []string
// isGapNeeded := false
// for _, args := range argGrps {
// if len(args) == 0 {
// continue
// }
// if isGapNeeded {
// sortedArgHclTxts = append(sortedArgHclTxts, "")
// }
// for _, arg := range args {
// var argHclTxt string
// if arg.Block == nil {
// argHclTxt = string(arg.Range.SliceBytes(file.Bytes))
// } else {
// argHclTxt = r.visitBlock(runner, arg.Block, issue)
// }
// sortedArgHclTxts = append(sortedArgHclTxts, argHclTxt)
// }
// isGapNeeded = true
// }
// sortedBlockHclTxt := strings.Join(sortedArgHclTxts, "\n")
// if strings.TrimSpace(sortedBlockHclTxt) == "" {
// sortedBlockHclTxt = fmt.Sprintf("%s {}", r.getBlockHead(block))
// } else {
// sortedBlockHclTxt = fmt.Sprintf("%s {\n%s\n}", r.getBlockHead(block), sortedBlockHclTxt)
// }
// sortedBlockHclTxt = string(hclwrite.Format([]byte(sortedBlockHclTxt)))
//
// if !isCorrectLayout {
// issue.Rule = r
// issue.Message = fmt.Sprintf("Arguments are expected to be arranged in following Layout:\n%s", sortedBlockHclTxt)
// issue.Range = block.DefRange()
// }
// return sortedBlockHclTxt
//}
//
//func (r *TerraformResourceDataArgLayoutRule) getSortedArgGrps(block *hclsyntax.Block) ([][]Arg, bool) {
// var headMetaArgs, tailMetaArgs, attrs, nestedBlocks []Arg
// for attrName, attr := range block.Body.Attributes {
// arg := Arg{
// Name: attrName,
// Range: attr.Range(),
// }
// if IsHeadMeta(attrName) {
// headMetaArgs = append(headMetaArgs, arg)
// } else if IsTailMeta(attrName) {
// tailMetaArgs = append(tailMetaArgs, arg)
// } else {
// attrs = append(attrs, arg)
// }
// }
// for _, nestedBlock := range block.Body.Blocks {
// blockName := r.getBlockHead(nestedBlock)
// arg := Arg{
// Name: blockName,
// Range: nestedBlock.Range(),
// Block: nestedBlock,
// }
// if IsHeadMeta(blockName) {
// headMetaArgs = append(headMetaArgs, arg)
// } else if IsTailMeta(blockName) {
// tailMetaArgs = append(tailMetaArgs, arg)
// } else {
// nestedBlocks = append(nestedBlocks, arg)
// }
// }
// sort.Slice(headMetaArgs, func(i, j int) bool {
// return GetHeadMetaPriority(headMetaArgs[i].Name) > GetHeadMetaPriority(headMetaArgs[j].Name)
// })
// sort.Slice(tailMetaArgs, func(i, j int) bool {
// return GetTailMetaPriority(tailMetaArgs[i].Name) > GetTailMetaPriority(tailMetaArgs[j].Name)
// })
// attrs = GetArgsWithOriginalOrder(attrs)
// nestedBlocks = GetArgsWithOriginalOrder(nestedBlocks)
//
// argGrps := [][]Arg{headMetaArgs, attrs, nestedBlocks, tailMetaArgs}
// var lastArgGrp, sortedArgs []Arg
// isCorrectLayout := true
// for _, argGrp := range argGrps {
// if isCorrectLayout && len(lastArgGrp) > 0 && len(argGrp) > 0 {
// if argGrp[0].Range.Start.Line-lastArgGrp[len(lastArgGrp)-1].Range.End.Line < 2 {
// isCorrectLayout = false
// }
// }
// if len(argGrp) > 0 {
// lastArgGrp = argGrp
// }
// sortedArgs = append(sortedArgs, argGrp...)
// }
// isCorrectLayout = isCorrectLayout && reflect.DeepEqual(sortedArgs, GetArgsWithOriginalOrder(sortedArgs))
// return argGrps, isCorrectLayout
//}
//
//func (r *TerraformResourceDataArgLayoutRule) getBlockHead(block *hclsyntax.Block) string {
// heads := []string{block.Type}
// for _, label := range block.Labels {
// heads = append(heads, fmt.Sprintf("\"%s\"", label))
// }
// return strings.Join(heads, " ")
//}
//
//func (r *TerraformResourceDataArgLayoutRule) isIssueEmpty(issue *helper.Issue) bool {
// return *issue == helper.Issue{}
//}