Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
See also terraform-linters/tflint#266
This PR adds a new Runner API for autofix. The newly added
EmitIssueWithFix
API allows plugins to not only emit issues but also automatically apply fixes for the issues.Below is an example of autofixing the instance type "t2.micro" to "t3.micro".
Unlike
EmitIssue
API, this function allows you to pass a function callback for autofix in the 4th argument. Plugin developers can use thetflint.Fixer
in the function callback to change their source code.The following APIs are available in
tflint.Fixer
:ReplaceText(hcl.Range, ...(string|tflint.TextNode))
InsertTextBefore(hcl.Range, string)
InsertTextAfter(hcl.Range, string)
Remove(hcl.Range)
RemoveAttribute(*hcl.Attribute)
RemoveBlock(*hcl.Block)
RemoveExtBlock(*hclext.Block)
They are inspired by ESLint's autofix APIs. See the GoDoc for these details.
Also, it doesn't change the source code directly, but there are some APIs available to help with that:
TextAt(hcl.Range) tflint.TextNode
ValueText(cty.Value) string
RangeTo(to string, filename string, start hcl.Pos) hcl.Range
Please refer to terraform-linters/tflint#266 for how to use the autofix implemented by plugins from TFLint.
Next, describe the internal design. The sequence diagram for communication between the host and plugins is shown below:
This PR adds the
ApplyChanges
API and changes theEmitIssue
API to return whether the issue has been applied (e.g. it may be ignored bytflint-ignore
annotations).After emitting an issue with
EmitIssue
API, if it is not ignored by an annotation, invoke the given fix function.tflint.Fixer
has all the source code internally and the fix function rewrites that as a byte sequence.After the rule inspection is finished, the rewritten source code is applied to the host server by the
ApplyChanges
API. From now on, the body obtained by APIs such asGetModuleContent
will be the fixed source code.There are two implementation considerations worth mentioning here. One is not to use
hclwrite
to rewrite the source code. Thehclwrite
provides APIs for rewriting HCL, but since it handles AST with a different abstraction level thanhclsyntax
, it is not possible to rewrite the corresponding expression fromhcl.Expression
. In order to realize easy rewriting usinghcl.Expression
orhcl.Range
, I thought that it was necessary to implement the rewriting operation as a byte string instead ofhclwrite
. This implementation is ininternal.Fixer
.The other is byte shift by rewriting. The source code is rewritten using the byte index pointed to by
Byte
field inhcl.Pos
. However, if multiple rewrite operations occur, the originalhcl.Pos
may have a byte index that does not reflect the result of the previous rewrite operation. To solve this problem, theinternal.Fixer
tracks byte index shifts that occur during rewriting. The shift is reflected in the byte indices of subsequent operations, allowing the original range to be rewritten appropriately.The discussion on which these designs were based can be found in terraform-linters/tflint#266 (comment).