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

Support fmtverbs in resource names #67

Merged
merged 5 commits into from
Aug 9, 2022
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
14 changes: 13 additions & 1 deletion cli/blocks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ resource "aws_vpc" "test" {
{
name: "Go fmt verbs",
sourcefile: "testdata/fmt_compat.go",
lineCount: 64,
lineCount: 76,
expectedBlocks: []block{
{
startLine: 8,
Expand Down Expand Up @@ -207,6 +207,18 @@ resource "aws_vpc" "test" {
replica_count = %[2]d
}
}
`,
},
{
startLine: 67,
endLine: 75,
text: `resource "aws_s3_bucket" %[1]q {
bucket = "tf-test-bucket-with-quotedname"
}

resource "aws_s3_bucket" "%[1]s-copy" {
bucket = "tf-test-bucket-with-name-in-quotes"
}
`,
},
},
Expand Down
2 changes: 1 addition & 1 deletion cli/cmds.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ func Make() *cobra.Command {
pflags := root.PersistentFlags()
pflags.BoolP("fmtcompat", "f", false, "enable format string (%s, %d etc) compatibility")
pflags.BoolP("check", "c", false, "return an error during diff if formatting is required")
pflags.BoolP("verbose", "v", false, "show files as they are processed& additional stats")
pflags.BoolP("verbose", "v", false, "show files as they are processed & additional stats")
pflags.BoolP("quiet", "q", false, "quiet mode, only shows block line numbers ")
pflags.BoolP("uncoloured", "u", false, "disable coloured output")

Expand Down
9 changes: 5 additions & 4 deletions cli/diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,19 @@ var diffTestcases = []struct {
"block 3 @ %s:30 failed to process with: failed to parse hcl: testdata/fmt_compat.go:4,3-4:",
"block 4 @ %s:44 failed to process with: failed to parse hcl: testdata/fmt_compat.go:3,3-4:",
"block 5 @ %s:53 failed to process with: failed to parse hcl: testdata/fmt_compat.go:2,26-27:",
"block 6 @ %s:67 failed to process with: failed to parse hcl: testdata/fmt_compat.go:1,26-27:",
},
lineCount: 64,
totalBlockCount: 5,
lineCount: 76,
totalBlockCount: 6,
},
{
name: "Go fmt verbs --fmtcompat",
sourcefile: "testdata/fmt_compat.go",
resultfile: "testdata/fmt_compat_diff_fmtcompat.go.txt",
fmtcompat: true,
lineCount: 64,
lineCount: 76,
unformattedBlockCount: 3,
totalBlockCount: 5,
totalBlockCount: 6,
},
{
name: "Go bad terraform",
Expand Down
9 changes: 5 additions & 4 deletions cli/fmt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,19 @@ var fmtTestcases = []struct {
"block 3 @ %s:30 failed to process with: failed to parse hcl: %s:4,3-4:",
"block 4 @ %s:44 failed to process with: failed to parse hcl: %s:3,3-4:",
"block 5 @ %s:53 failed to process with: failed to parse hcl: %s:2,26-27:",
"block 6 @ %s:67 failed to process with: failed to parse hcl: %s:1,26-27:",
},
lineCount: 64,
totalBlockCount: 5,
lineCount: 76,
totalBlockCount: 6,
},
{
name: "Go fmt verbs --fmtcompat",
sourcefile: "testdata/fmt_compat.go",
resultfile: "testdata/fmt_compat_fmtcompat.go",
fmtcompat: true,
lineCount: 64,
lineCount: 76,
updatedBlockCount: 3,
totalBlockCount: 5,
totalBlockCount: 6,
},
{
name: "Go bad terraform",
Expand Down
12 changes: 12 additions & 0 deletions cli/testdata/fmt_compat.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,15 @@ resource "aws_elasticache_replication_group" "for-expression" {
}
`, randInt)
}

func testFormatVerbResourceName(name string) string {
return fmt.Sprintf(`
resource "aws_s3_bucket" %[1]q {
bucket = "tf-test-bucket-with-quotedname"
}

resource "aws_s3_bucket" "%[1]s-copy" {
bucket = "tf-test-bucket-with-name-in-quotes"
}
`, name)
}
12 changes: 12 additions & 0 deletions cli/testdata/fmt_compat_fmtcompat.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,15 @@ resource "aws_elasticache_replication_group" "for-expression" {
}
`, randInt)
}

func testFormatVerbResourceName(name string) string {
return fmt.Sprintf(`
resource "aws_s3_bucket" %[1]q {
bucket = "tf-test-bucket-with-quotedname"
}

resource "aws_s3_bucket" "%[1]s-copy" {
bucket = "tf-test-bucket-with-name-in-quotes"
}
`, name)
}
12 changes: 12 additions & 0 deletions cli/testdata/fmt_compat_upgrade012.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,15 @@ resource "aws_elasticache_replication_group" "for-expression" {
}
`, randInt)
}

func testFormatVerbResourceName(name string) string {
return fmt.Sprintf(`
resource "aws_s3_bucket" %[1]q {
bucket = "tf-test-bucket-with-quotedname"
}

resource "aws_s3_bucket" "%[1]s-copy" {
bucket = "tf-test-bucket-with-name-in-quotes"
}
`, name)
}
9 changes: 5 additions & 4 deletions cli/upgrade012_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ var upgradeTestcases = []struct {
"block 3 @ %s:30 failed to process with: terraform init failed:",
"block 4 @ %s:44 failed to process with: terraform init failed:",
"block 5 @ %s:53 failed to process with: terraform init failed:",
"block 6 @ %s:67 failed to process with: terraform init failed:",
},
lineCount: 64,
totalBlockCount: 5,
lineCount: 76,
totalBlockCount: 6,
},
{
name: "Go fmt verbs --fmtcompat",
Expand All @@ -62,9 +63,9 @@ var upgradeTestcases = []struct {
// for-expressions were added in Terraform 0.12
"block 5 @ %s:53 failed to process with: terraform 0.12upgrade failed:",
},
lineCount: 64,
lineCount: 76,
updatedBlockCount: 1,
totalBlockCount: 5,
totalBlockCount: 6,
},
{
name: "Go bad terraform",
Expand Down
4 changes: 3 additions & 1 deletion lib/blocks/blockreader.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,9 @@ func (bv blockVisitor) Visit(cursor *astutil.Cursor) bool {
return true
}

var terraformMatcher = regexp.MustCompile(`(((resource|data)\s+"[-a-z0-9_]+")|(variable|output))\s+"[-a-zA-Z0-9_]+"\s+\{`)
// Includes matching Go format verbs in the resource, data source, variable, or output name.
// Technically, this is only valid for the Go matcher, but included generally for simplicity.
var terraformMatcher = regexp.MustCompile(`(((resource|data)\s+"[-a-z0-9_]+")|(variable|output))\s+"[-a-z0-9_%\[\]]+"\s+\{`)

// A simple check to see if the content looks like a Terraform configuration.
// Looks for a line with either a resource, data source, variable, or output declaration
Expand Down
36 changes: 36 additions & 0 deletions lib/blocks/blockreader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ func TestBlockDetection(t *testing.T) {
resource "aws_s3_bucket" "leading-space-and-line" {
bucket = "tf-test-bucket-leading-space-and-line-%d"
}
`,
},
{
leadingPadding: "\n",
trailingPadding: "\n",
text: `resource "aws_s3_bucket" "%s" {
bucket = "tf-test-bucket-with-quotedname"
}
`,
},
},
Expand Down Expand Up @@ -212,6 +220,34 @@ output "arn" {
}`,
expected: true,
},
{
text: `
resource "aws_s3_bucket" "%s" {
bucket = "tf-test-bucket-simple"
}`,
expected: true,
},
// {
// text: `
// resource "aws_s3_bucket" "%[1]s" {
// bucket = "tf-test-bucket-simple"
// }`,
// expected: true,
// },
// {
// text: `
// resource "aws_s3_bucket" %q {
// bucket = "tf-test-bucket-simple"
// }`,
// expected: true,
// },
// {
// text: `
// resource "aws_s3_bucket" %[1]q {
// bucket = "tf-test-bucket-simple"
// }`,
// expected: true,
// },
{
text: "%d: bad create: \n%#v\n%#v",
expected: false,
Expand Down
8 changes: 8 additions & 0 deletions lib/blocks/testdata/test1.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@ func testLeadingWhiteSpaceAndLine(randInt int) string {
`, randInt)
}

func testFormatVerbResourceName(name string) string {
return fmt.Sprintf(`
resource "aws_s3_bucket" "%s" {
bucket = "tf-test-bucket-with-quotedname"
}
`, name)
}

func notTerraformSimpleString() string {
fmt.Sprintf("%d: bad create: \n%#v\n%#v", i, cm, tc.Create)
}
Expand Down
41 changes: 37 additions & 4 deletions lib/fmtverbs/fmtverbs.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,22 @@ func Escape(b string) string {
// conditional expression: = %t ? ...
b = regexp.MustCompile(`(=\s*)(%\[[\d+]\]t)(\s\?)`).ReplaceAllString(b, `${1}true/*@@_@@ TFMT:${2}:TFMT @@_@@*/${3}`)

// resource name contains %[sdtfg]
b = regexp.MustCompile(`([resource|data]\s+"[-a-zA-Z0-9_]+"\s+"[-a-zA-Z0-9_]*)%(?:\[([\d]+)\])?([sdtfg])`).ReplaceAllString(b, `${1}TFMTRESNAME_${2}${3}`)

// resource name %q
b = regexp.MustCompile(`([resource|data]\s+"[-a-zA-Z0-9_]+"\s+)%(?:\[([\d]+)\])?q`).ReplaceAllString(b, `${1}"TFMTRESNAME_${2}q"`)

// %s - whole line
// figure out why the * doesn't match both later
b = regexp.MustCompile(`(?m:^%(\.[0-9])?[sdfgtq]$)`).ReplaceAllString(b, `#@@_@@ TFMT:$0:TMFT @@_@@#`)
b = regexp.MustCompile(`(?m:^[ \t]*%(\.[0-9])?[sdfgtq]$)`).ReplaceAllString(b, `#@@_@@ TFMT:$0:TMFT @@_@@#`)

// provider meta-argument
// The provider name must be in lowercase
b = regexp.MustCompile(`(provider\s+=\s+)%s`).ReplaceAllString(b, `${1}tfmtprovider.PROVIDER`)
b = regexp.MustCompile(`(provider\s+=\s+)+%\[(\d+)\]s`).ReplaceAllString(b, `${1}tfmtprovider.PROVIDER_${2}`)

// %[n]s
b = regexp.MustCompile(`(?m:^%(\.[0-9])?\[[\d]+\][sdfgtq]$)`).ReplaceAllString(b, `#@@_@@ TFMT:$0:TMFT @@_@@#`)
b = regexp.MustCompile(`(?m:^[ \t]*%(\.[0-9])?\[[\d]+\][sdfgtq]$)`).ReplaceAllString(b, `#@@_@@ TFMT:$0:TMFT @@_@@#`)
Expand All @@ -36,10 +47,16 @@ func Escape(b string) string {
b = regexp.MustCompile(`(?m:\[(%(\.[0-9])?\[[\d]+\][sdfgtq](,\s*)?)+\])`).ReplaceAllString(b, `["@@_@@ TFMT:$0:TFMT @@_@@"]`)

// .12 - something.%s.prop
b = regexp.MustCompile(`\.%([sdfgtq])`).ReplaceAllString(b, `.TFMTKTKTTFMT$1`)
b = regexp.MustCompile(`\.%([sdt])`).ReplaceAllString(b, `.TFMTKTKTTFMT${1}`)

// .12 - something.%[n]s.prop
b = regexp.MustCompile(`\.%\[(\d+)\]([sdfgtq])`).ReplaceAllString(b, `.TFMTKTKTTFMT_$1$2`)
b = regexp.MustCompile(`\.%\[(\d+)\]([sdt])`).ReplaceAllString(b, `.TFMTKTKTTFMT_${1}${2}`)

// .12 - something.text%s.prop
b = regexp.MustCompile(`\.([-a-zA-Z0-9_]+)%([sdt])`).ReplaceAllString(b, `.${1}TFMTKTKTTFMT${2}`)

// .12 - something.text%[n]s.prop
b = regexp.MustCompile(`\.([-a-zA-Z0-9_]+)%\[(\d+)\]([sdt])`).ReplaceAllString(b, `.${1}TFMTKTKTTFMT_${2}${3}`)

// = %s
b = regexp.MustCompile(`(?m:%(\.[0-9])?[sdfgtq](\.[a-z_]+)*$)`).ReplaceAllString(b, `"@@_@@ TFMT:$0:TFMT @@_@@"`)
Expand Down Expand Up @@ -78,10 +95,10 @@ func Unscape(fb string) string {
fb = strings.ReplaceAll(fb, ":TFMT @@_@@\"", "")

// .12 - something.%[n]s.prop
fb = regexp.MustCompile(`\.TFMTKTKTTFMT_(\d+)([sdfgtq])`).ReplaceAllString(fb, `.%[$1]$2`)
fb = regexp.MustCompile(`TFMTKTKTTFMT_(\d+)`).ReplaceAllString(fb, `%[$1]`)

// .12 - something.%s.prop
fb = strings.ReplaceAll(fb, ".TFMTKTKTTFMT", ".%")
fb = strings.ReplaceAll(fb, "TFMTKTKTTFMT", "%")

// function(..., %[n]s, ...)
fb = regexp.MustCompile(`TFMTFNPARAM_(\d+)([sdfgtq])`).ReplaceAllString(fb, `%[$1]$2`)
Expand All @@ -95,5 +112,21 @@ func Unscape(fb string) string {
// %s =
fb = regexp.MustCompile(`Ω([sdfgtq])`).ReplaceAllString(fb, `%${1}`)

// resource name %[n]s
fb = regexp.MustCompile(`TFMTRESNAME_(\d+)([sdtfg])`).ReplaceAllString(fb, `%[${1}]${2}`)

// resource name %s
fb = regexp.MustCompile(`TFMTRESNAME_([sdtfg])`).ReplaceAllString(fb, `%${1}`)

// resource name %[n]q
fb = regexp.MustCompile(`"TFMTRESNAME_(\d+)q"`).ReplaceAllString(fb, `%[${1}]q`)

// resource name %q
fb = regexp.MustCompile(`"TFMTRESNAME_q"`).ReplaceAllLiteralString(fb, `%q`)

// provider meta-argument
fb = regexp.MustCompile(`tfmtprovider.PROVIDER_(\d+)`).ReplaceAllString(fb, `%[${1}]s`)
fb = strings.ReplaceAll(fb, "tfmtprovider.PROVIDER", "%s")

return fb
}
Loading