Coder Social home page Coder Social logo

terrafmt's People

Contributors

bflad avatar gdavison avatar jackofallops avatar jeremmfr avatar katbyte avatar magodo avatar megan07 avatar michahoffmann avatar pdecat avatar tombuildsstuff avatar tracypholmes avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

terrafmt's Issues

blocks with int values are not replaced

The line mentioned in the error compute_environment_data_source_test.go:20,37-38 starts at the block update_policy {}

$ find internal/service/batch -type f -name '*_test.go' \
        | sort -u \
        | xargs -I {} terrafmt fmt  --fmtcompat {}
ERRO[2023-11-10 14:37:35] block 2 @ internal/service/batch/compute_environment_data_source_test.go:149 failed to process with: failed to parse hcl: internal/service/batch/compute_environment_data_source_test.go:20,37-38: Invalid expression; Expected the start of an expression, but found an invalid expression token.
resource "aws_batch_compute_environment" "test" {
  compute_environment_name = "@@_@@ TFMT:%[1]q:TFMT @@_@@"

  compute_resources {
    allocation_strategy = "BEST_FIT_PROGRESSIVE"
    instance_role       = aws_iam_instance_profile.ecs_instance.arn
    instance_type       = ["optimal"]
    max_vcpus           = 4
    min_vcpus           = 0
    security_group_ids  = [
      aws_security_group.test.id
    ]
    subnets = [
      aws_subnet.test.id
    ]
    type = "EC2"
  }
  update_policy {
    job_execution_timeout_minutes = "@@_@@ TFMT:%[2]d:TFMT @@_@@"
    terminate_jobs_on_update      = %[3]v
  }

  type = "MANAGED"
}

data "aws_batch_compute_environment" "by_name" {
  compute_environment_name = aws_batch_compute_environment.test.compute_environment_name
}

Test code:

func testAccComputeEnvironmentDataSourceConfig_updatePolicy(rName string, timeout int, terminate bool) string {
	return acctest.ConfigCompose(testAccComputeEnvironmentConfig_baseDefaultSLR(rName), fmt.Sprintf(`
resource "aws_batch_compute_environment" "test" {
  compute_environment_name = %[1]q

  compute_resources {
    allocation_strategy = "BEST_FIT_PROGRESSIVE"
    instance_role       = aws_iam_instance_profile.ecs_instance.arn
    instance_type       = ["optimal"]
    max_vcpus           = 4
    min_vcpus           = 0
    security_group_ids  = [
      aws_security_group.test.id
    ]
    subnets = [
      aws_subnet.test.id
    ]
    type = "EC2"
  }
  update_policy {
    job_execution_timeout_minutes = %[2]d
    terminate_jobs_on_update      = %[3]v
  }

  type = "MANAGED"
}

data "aws_batch_compute_environment" "by_name" {
  compute_environment_name = aws_batch_compute_environment.test.compute_environment_name
}
`, rName, timeout, terminate))
}

Does not format/recognize inline code for offset in markdown

terrafmt does not extract terraform files and does not do inline code formatting from the README.md file if, we start the Three backquotes after 4 spaces in the README.md file. It only works, if we start the Three backquotes at column 0.

Ex:

Works:
works

terrafmt blocks README.md

####### B1 @ #587
resource "aws_lambda_function" "pass" {
function_name = "test-env"
role = ""
runtime = "python3.8"

environment {
variables = {
AWS_DEFAULT_REGION = "us-west-2"
}
}
}
Does not work

Does not work

terrafmt blocks README.md

note: markdown format allows having an offset.

Does not detect blocks where all resource names contain format verbs

In Go source files, a heuristic is used to identify if a block looks like Terraform before running tooling against it. It currently requires at least one line matching a resource or data source block or variable or output block.

In most cases this works, but if a reusable Terraform segment allows all names to be replaced, it is not detected. For example, the following is not detected:

func testAccAvailableAZsNoOptInConfigWithProvider(name, provider string) string {
	return fmt.Sprintf(`
data "aws_availability_zones" "%[1]s" {
  provider = %[2]s

  state = "available"

  filter {
    name   = "opt-in-status"
    values = ["opt-in-not-required"]
  }
}
`, name, provider)
}

When format verbs are enabled, the pattern matching should also match resource names contains format verbs.

Add option to add null separator to blocks command

To help using terrafmt blocks in toolchains, add the option to use a null separator. This would allow e.g. piping to xargs -0 ...

There doesn't seem to be consistency between existing tools:

  • find uses -print0
  • GNU grep uses -Z, --null
  • sort uses -z, --zero-terminated

I propose using --zero-terminated for the long option and -z for the short option, or possibly -0.

Multiple format verbs in conditional not handled correctly

My configuration (hashicorp/terraform-provider-aws#14013) is

cidr_block      = (%[2]q == "cidr_block") ? %[3]q : null
ipv6_cidr_block = (%[2]q == "ipv6_cidr_block") ? %[3]q : null

and terrafmt reports an error

failed to process with: failed to parse hcl: ./aws/resource_aws_route_table_test.go:69,48-49: Unbalanced parentheses; Expected a closing parenthesis to terminate the expression.
...
cidr_block      = (TFFMTKTBRACKETPERCENT[2]q == "cidr_block") ? %[3]q : null
ipv6_cidr_block = (TFFMTKTBRACKETPERCENT[2]q == "ipv6_cidr_block") ? %[3]q : null

This error seems to be in addition to the issue reported in #37.

Format verbs used as resource names not replaced

When a configuration contains a resource where the name is a format verb, the format verb is not replaced, causing HCL parsing to fail.

For example, in https://github.com/hashicorp/terraform-provider-aws/blob/38319aa13aea65d3e946450c1f881d8fef12e734/aws/resource_aws_quicksight_user_test.go#L195-L203

data "aws_caller_identity" "current" {}

resource "aws_quicksight_user" %[1]q {
  aws_account_id = data.aws_caller_identity.current.account_id
  user_name      = %[1]q
  email          = %[2]q
  identity_type  = "QUICKSIGHT"
  user_role      = "READER"
}

Expected Result

The line resource "aws_quicksight_user" %[1]q { should be replaced with something parseable as HCL

Actual Result

The line resource "aws_quicksight_user" %[1]q { is not changed, causing HCL parsing to fail

Functions with more than one parameter not supported with format verb replacement

Terraform for expressions cause terrafmt fmt -f (and therefore probably terrafmt diff and terrafmt upgrade012) to fail.

For example, the following snippet

resource "aws_elasticache_replication_group" "test" {
  replication_group_id          = %[1]q
  replication_group_description = "test description"
  node_type                     = "cache.t2.micro"
  subnet_group_name             = aws_elasticache_subnet_group.test.name
  security_group_ids            = [aws_security_group.test.id]

  node_groups {
	node_group_id              = %[3]q
	primary_availability_zone  = aws_subnet.test[0].availability_zone
	replica_availability_zones = [for x in range(1, %[2]d+1) : element(aws_subnet.test[*].availability_zone, x)]
	replica_count              = %[2]d
  }
}

causes the following error

ERRO[2021-02-01 14:43:47] block 25 @ aws/resource_aws_elasticache_replication_group_test.go:2399 failed to process with: failed to parse hcl: aws/resource_aws_elasticache_replication_group_test.go:11,50-51: Invalid expression; Expected the start of an expression, but found an invalid expression token.
resource "aws_elasticache_replication_group" "test" {
  replication_group_id          = "@@_@@ TFMT:%[1]q:TFMT @@_@@"
  replication_group_description = "test description"
  node_type                     = "cache.t2.micro"
  subnet_group_name             = aws_elasticache_subnet_group.test.name
  security_group_ids            = [aws_security_group.test.id]

  node_groups {
	node_group_id              = "@@_@@ TFMT:%[3]q:TFMT @@_@@"
	primary_availability_zone  = aws_subnet.test[0].availability_zone
	replica_availability_zones = [for x in range(1, %[2]d+1) : element(aws_subnet.test[*].availability_zone, x)]
	replica_count              = "@@_@@ TFMT:%[2]d:TFMT @@_@@"
  }
} 

Format quoted string verb not supported inside Terraform configuration function definition

Description

When using terrafmt diff -f with the following configuration snippet:

	return fmt.Sprintf(`
data "aws_caller_identity" "current" {}

resource "aws_signer_signing_profile" "test" {
  platform_id = "AWSLambda-SHA384-ECDSA"
  name        = replace(%[1]q, "-", "_")
}
# ...
`, rName)
}

An error is returned because the string is not quoted properly during format verb handling (note: replace(TFFMTKTBRACKETPERCENT[1]q, \"-\", \"_\")):

time="2020-11-24 18:23:42" level=error msg="block 1 @ ./aws/data_source_aws_signer_signing_job_test.go:34 failed to process with: failed to parse hcl: ./aws/data_source_aws_signer_signing_job_test.go:5,49-50: Missing argument separator; A comma is required to separate each function argument from the next.\ndata \"aws_caller_identity\" \"current\" {}\n\nresource \"aws_signer_signing_profile\" \"test\" {\n  platform_id = \"AWSLambda-SHA384-ECDSA\"\n  name        = replace(TFFMTKTBRACKETPERCENT[1]q, \"-\", \"_\")\n}\n\nresource \"aws_s3_bucket\" \"source\" {\n  bucket = \"%[1]s-source\"\n\n  versioning {\n    enabled = true\n  }\n\n  force_destroy = true\n}\n\nresource \"aws_s3_bucket\" \"destination\" {\n  bucket        = \"%[1]s-destination\"\n  force_destroy = true\n}\n\nresource \"aws_s3_bucket_object\" \"source\" {\n  bucket = aws_s3_bucket.source.bucket\n  key    = \"lambdatest.zip\"\n  source = \"test-fixtures/lambdatest.zip\"\n}\n\nresource \"aws_signer_signing_job\" \"test\" {\n  profile_name = aws_signer_signing_profile.test.name\n\n  source {\n    s3 {\n      bucket  = aws_s3_bucket_object.source.bucket\n      key     = aws_s3_bucket_object.source.key\n      version = aws_s3_bucket_object.source.version_id\n    }\n  }\n\n  destination {\n    s3 {\n      bucket = aws_s3_bucket.destination.bucket\n    }\n  }\n}\n\ndata \"aws_signer_signing_job\" \"test\" {\n  job_id = aws_signer_signing_job.test.job_id\n}\n"

Support provider defined functions

Terraform 1.8 will introduce support for provider defined functions. hashicorp/hcl/v2 has been updated to support this syntax, so an update to this dependency is required in order to support providers implementing functions.

Here's an example of the HCL parsing failure in the AWS provider:

ERRO[2024-03-06 10:49:01] block 1 @ website/docs/functions/arn_build.html.markdown:19 failed to process with: failed to parse hcl: website/docs/functions/arn_build.html.markdown:3,1
9-20: Missing newline after argument; An argument definition must end with a newline.
# result: arn:aws:iam::444455556666:role/example
output "example" {
  value = provider::aws::arn_build("aws", "iam", "", "444455556666", "role/example")
}

Line Number Delimiter in Output Causes Terminal Links to Open in Browser

Terminals such as iTerm2 will automatically create clickable links for patterns matching file paths and web URLs (to open, hover over while holding command key and click). The current output from terrafmt uses # as the delimiter between file names and line numbers, e.g.

aws/resource_aws_workspaces_directory_test.go#324
aws/resource_aws_workspaces_ip_group_test.go#127
aws/resource_aws_workspaces_ip_group_test.go#149
ERRO[0000] block 2 @ aws/resource_aws_xray_sampling_rule_test.go#194 failed to process with: failed to parse hcl: aws/resource_aws_xray_sampling_rule_test.go:3,20-21: Invalid expression; Expected the start of an expression, but found an invalid expression token.

When clicking those links they open in a web browser since presumably iTerm2 is treating them as a URL due to the # URL separator. Updating output to instead use : as a delimiter should allow terminals to treat these as file paths instead, so they open in your configured editor.

Multiple Go format verbs on one line are not handled by fmtcompat

When handling Terraform blocks in Go files, when a line contains more than one Go format verb, the --fmtcompat flag does not replace any of the flags.

Example 1

provider "aws" {
  ignore_tags {
    keys = [%[1]q, %[2]q]
  }

  skip_credentials_validation = true
  skip_get_ec2_platforms      = true
  skip_metadata_api_check     = true
  skip_requesting_account_id  = true
}

Expected

ignore_tags {
  keys = ["@@_@@ TFMT:%[1]q:TFMT @@_@@", "@@_@@ TFMT:%[2]q:TFMT @@_@@"]
}

Got

ignore_tags {
  keys = [%[1]q, %[2]q]
}

Example 2

resource "aws_accessanalyzer_analyzer" "test" {
  analyzer_name = %[1]q

  tags = {
    %[2]q = %[3]q
  }
}

Expected

tags = {
  "@@_@@ TFMT:%[2]q:TFMT @@_@@" = "@@_@@ TFMT:%[3]q:TFMT @@_@@"
}

Got

tags = {
  %[2]q = "@@_@@ TFMT:%[3]q:TFMT @@_@@"
}

Needed for hashicorp/terraform-provider-aws#14722

Two quoted format verb parameters on the same line do not both get replaced

When a configuration with format verbs has two quoted values on the same line, only the first is replaced.

For example, in https://github.com/hashicorp/terraform-provider-aws/blob/38319aa13aea65d3e946450c1f881d8fef12e734/aws/resource_aws_ecs_capacity_provider_test.go#L438-L448

resource "aws_ecs_capacity_provider" "test" {
  name = %[1]q

  tags = {
    %[2]q = %[3]q,
  }

  auto_scaling_group_provider {
    auto_scaling_group_arn = aws_autoscaling_group.test.arn
  }
}

Expected Result

the line%[2]q = %[3]q, should be replaced with "@@_@@ TFMT:%[2]q:TFMT @@_@@" = "@@_@@ TFMT:%[3]q:TFMT @@_@@", or something similar

Actual Result

the line%[2]q = %[3]q, is replaced with "@@_@@ TFMT:%[2]q:TFMT @@_@@" = %[3]q,, and terrafmt fmt fails.

Proposal: Actionable error codes

When using terrafmt in a tooling pipelines, it can be useful to have actionable error codes to distinguish between different types of errors.

Motivating example

When calling

terrafmt diff ./aws --check --pattern '*_test.go' --quiet --fmtcompat

There are some edge cases with --fmtcompat, i.e. #30 and other cases, where parsing the Terraform configuration will fail. It would be useful to distinguish the case of "this block is not formatted" vs "this block could not be evaluated" (and vs "some other error occurred).

Proposed error codes

Error cases that can occur together should allow bitwise operations, e.g. an enclosing file could have both unformatted blocks and blocks that cannot be evaluated.

Not evaluated/Parsing error Unformatted Code
Y N 2
N Y 4
Y Y 6

Other errors should return the code 1.

Are there other error cases that should have a specific code?

Format verbs for parameter names fail to parse as HCL

When a configuration contains a format verb as a parameter name, it is replaced with a quoted string, which fails HCL parsing.

For example, in https://github.com/hashicorp/terraform-provider-aws/blob/38319aa13aea65d3e946450c1f881d8fef12e734/aws/resource_aws_efs_file_system_test.go#L832-L836

resource "aws_efs_file_system" "test" {
  lifecycle_policy {
    %s = %q
  }
}

Expected Result

The line %s = %q should replace the leading bare string with something compatible with HCL parsing

Actual Result

The line %s = %q is replaced with "@@_@@ TFMT:%s:TFMT @@_@@" = "@@_@@ TFMT:%q:TFMT @@_@@", and terrafmt fmt fails

Long lists always forced to one line?

It seems like terrafmt prefers long one-liners over readable lists. It's after my own heart but perhaps less readable.

terrafmt is not happy with this but maybe should be:

resource "aws_docdb_cluster" "default" {
  availability_zones = [
    data.aws_availability_zones.available.names[0],
    data.aws_availability_zones.available.names[1],
    data.aws_availability_zones.available.names[2]
  ]
}

terrafmt is happy with this but maybe should not be:

resource "aws_docdb_cluster" "default" {
  availability_zones = [data.aws_availability_zones.available.names[0], data.aws_availability_zones.available.names[1], data.aws_availability_zones.available.names[2]]
}

Escape fmtverb doesn't support non-standalone positional verb

Following test case will fail in fmtverbs_test.go:

		{
			name: "assigned-positional-not-standalone",
			block: `
resource  "resource"    "test" {
kat = %[1]s.id
byte = %[1]d.id
} 
`,
			expected: `
resource "resource" "test" {
	kat = %[1]s.id
	byte = %[1]d.id
}
`,
		},

Error message:

--- FAIL: TestFmtVerbBlock (0.00s)
    --- FAIL: TestFmtVerbBlock/assigned-positional-not-standalone (0.00s)
        fmtverbs_test.go:202: Got an error when none was expected: failed to parse hcl: test:3,7-8: Invalid expression; Expected the start of an expression, but found an invalid expression token.
FAIL
exit status 1
FAIL    github.com/katbyte/terrafmt/lib/format  0.006s

Getting "failed to find end of block"

Hi @katbyte,

I'm getting several failed to find end of block errors on https://github.com/claranet/terraform-provider-zabbix/ (master branch)

# for f in zabbix/*_test.go ; do ~/go/bin/terrafmt fmt $f ; done
ERRO[0000] block 1 @ zabbix/resource_zabbix_host_group_test.go#56 failed to find end of block
ERRO[0000] block 1 @ zabbix/resource_zabbix_host_test.go#63 failed to find end of block
ERRO[0000] block 1 @ zabbix/resource_zabbix_item_test.go#53 failed to find end of block
ERRO[0000] block 2 @ zabbix/resource_zabbix_item_test.go#53 failed to find end of block
ERRO[0000] block 1 @ zabbix/resource_zabbix_template_link_test.go#141 failed to find end of block
ERRO[0000] block 2 @ zabbix/resource_zabbix_template_link_test.go#141 failed to find end of block
ERRO[0000] block 3 @ zabbix/resource_zabbix_template_link_test.go#141 failed to find end of block
ERRO[0000] block 1 @ zabbix/resource_zabbix_template_test.go#151 failed to find end of block
ERRO[0000] block 2 @ zabbix/resource_zabbix_template_test.go#151 failed to find end of block
ERRO[0000] block 3 @ zabbix/resource_zabbix_template_test.go#151 failed to find end of block
ERRO[0000] block 4 @ zabbix/resource_zabbix_template_test.go#151 failed to find end of block
ERRO[0000] block 5 @ zabbix/resource_zabbix_template_test.go#151 failed to find end of block
ERRO[0000] block 6 @ zabbix/resource_zabbix_template_test.go#151 failed to find end of block
ERRO[0000] block 7 @ zabbix/resource_zabbix_template_test.go#151 failed to find end of block
ERRO[0000] block 8 @ zabbix/resource_zabbix_template_test.go#151 failed to find end of block

Example block triggering the error:

func testAccZabbixHostGroupConfig(groupName string) string {
	return fmt.Sprintf(`
		resource "zabbix_host_group" "zabbix" {
			name = "%s"
		}`, groupName,
	)
}

Note: this happens with the freshly released v0.1.0 compiled with go 1.13.8 and 1.14.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.