Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tflint: Add tflint-ignore-file annotation #1909

Merged
merged 1 commit into from
Nov 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions docs/user-guide/annotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,28 @@ resource "aws_instance" "foo" {
instance_type = "t10.2xlarge"
}
```

To disable an entire file, you can also use the `tflint-ignore-file` annotation:

```hcl
# tflint-ignore-file: aws_instance_invalid_type

resource "aws_instance" "foo" {
instance_type = "t1.2xlarge"
}
```

This annotation is valid only at the top of the file. The following cannot be used and will result in an error:

```hcl
resource "aws_instance" "foo" {
# tflint-ignore-file: aws_instance_invalid_type
instance_type = "t1.2xlarge"
}
```

```hcl
resource "aws_instance" "foo" { # tflint-ignore-file: aws_instance_invalid_type
instance_type = "t1.2xlarge"
}
```
86 changes: 71 additions & 15 deletions tflint/annotation.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,13 @@ import (
"github.com/hashicorp/hcl/v2/hclsyntax"
)

var annotationPattern = regexp.MustCompile(`tflint-ignore: ([^\n*/#]+)`)

// Annotation represents comments with special meaning in TFLint
type Annotation struct {
Content string
Token hclsyntax.Token
type Annotation interface {
IsAffected(*Issue) bool
String() string
}

// Annotations is slice of Annotation
// Annotations is a slice of Annotation
type Annotations []Annotation

// NewAnnotations find annotations from the passed tokens and return that list.
Expand All @@ -35,21 +33,49 @@ func NewAnnotations(path string, file *hcl.File) (Annotations, hcl.Diagnostics)
continue
}

match := annotationPattern.FindStringSubmatch(string(token.Bytes))
if len(match) != 2 {
// tflint-ignore annotation
match := lineAnnotationPattern.FindStringSubmatch(string(token.Bytes))
if len(match) == 2 {
ret = append(ret, &LineAnnotation{
Content: strings.TrimSpace(match[1]),
Token: token,
})
continue
}

// tflint-ignore-file annotation
match = fileAnnotationPattern.FindStringSubmatch(string(token.Bytes))
if len(match) == 2 {
if !(token.Range.Start.Line == 1 && token.Range.Start.Column == 1) {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "tflint-ignore-file annotation must be written at the top of file",
Detail: fmt.Sprintf("tflint-ignore-file annotation is written at line %d, column %d", token.Range.Start.Line, token.Range.Start.Column),
Subject: token.Range.Ptr(),
})
continue
}
ret = append(ret, &FileAnnotation{
Content: strings.TrimSpace(match[1]),
Token: token,
})
continue
}
ret = append(ret, Annotation{
Content: strings.TrimSpace(match[1]),
Token: token,
})
}

return ret, diags
}

var lineAnnotationPattern = regexp.MustCompile(`tflint-ignore: ([^\n*/#]+)`)

// LineAnnotation is an annotation for ignoring issues in a line
type LineAnnotation struct {
Content string
Token hclsyntax.Token
}

// IsAffected checks if the passed issue is affected with the annotation
func (a *Annotation) IsAffected(issue *Issue) bool {
func (a *LineAnnotation) IsAffected(issue *Issue) bool {
if a.Token.Range.Filename != issue.Range.Filename {
return false
}
Expand All @@ -71,6 +97,36 @@ func (a *Annotation) IsAffected(issue *Issue) bool {
}

// String returns the string representation of the annotation
func (a *Annotation) String() string {
return fmt.Sprintf("annotation:%s (%s)", a.Content, a.Token.Range.String())
func (a *LineAnnotation) String() string {
return fmt.Sprintf("tflint-ignore: %s (%s)", a.Content, a.Token.Range.String())
}

var fileAnnotationPattern = regexp.MustCompile(`tflint-ignore-file: ([^\n*/#]+)`)

// FileAnnotation is an annotation for ignoring issues in a file
type FileAnnotation struct {
Content string
Token hclsyntax.Token
}

// IsAffected checks if the passed issue is affected with the annotation
func (a *FileAnnotation) IsAffected(issue *Issue) bool {
if a.Token.Range.Filename != issue.Range.Filename {
return false
}

rules := strings.Split(a.Content, ",")
for i, rule := range rules {
rules[i] = strings.TrimSpace(rule)
}

if slices.Contains(rules, issue.Rule.Name()) || slices.Contains(rules, "all") {
return true
}
return false
}

// String returns the string representation of the annotation
func (a *FileAnnotation) String() string {
return fmt.Sprintf("tflint-ignore-file: %s (%s)", a.Content, a.Token.Range.String())
}
Loading
Loading