Skip to content

Commit

Permalink
feat: support data sources (#35)
Browse files Browse the repository at this point in the history
* feat: support data sources

* docs: update README

* chore: update example

* docs: update getting started

* docs: update example

* fix: fix a lint error

* chore: fix test data
  • Loading branch information
suzuki-shunsuke authored Dec 23, 2024
1 parent 034440a commit 9dd4527
Show file tree
Hide file tree
Showing 13 changed files with 172 additions and 35 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
.envrc
moved.tf
moved_blocks.tf
.terraform
.terraform.lock.hcl
102 changes: 92 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,62 @@

[![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/suzuki-shunsuke/tfmv/main/LICENSE) | [Install](docs/install.md)

CLI to rename Terraform resources and modules and generate moved blocks.
tfmv is a CLI to rename Terraform resources, data sources, and modules and generate moved blocks.

e.g. Replace `-` with `_`:

```sh
tfmv -r "-/_"
```

```diff
diff --git a/example/main.tf b/example/main.tf
index 48ef3bd..9110880 100644
--- a/example/main.tf
+++ b/example/main.tf
@@ -1,20 +1,20 @@
-resource "github_repository" "example-1" {
+resource "github_repository" "example_1" {
name = "example-1"
}

-data "github_branch" "example-2" {
- repository = github_repository.example-1.name
+data "github_branch" "example_2" {
+ repository = github_repository.example_1.name
branch = "example"
depends_on = [
- github_repository.example-1,
- module.example-3
+ github_repository.example_1,
+ module.example_3
]
}

-module "example-3" {
+module "example_3" {
source = "./foo/module"
}

output "branch_sha" {
- value = data.github_branch.example-2.sha
+ value = data.github_branch.example_2.sha
}
```

moved.tf is created:

```tf
moved {
from = github_repository.example-1
to = github_repository.example_1
}
moved {
from = module.example-3
to = module.example_3
}
```

## Getting Started

Expand All @@ -21,19 +76,28 @@ resource "github_repository" "example-1" {
name = "example-1"
}
resource "github_branch" "example" {
data "github_branch" "example-2" {
repository = github_repository.example-1.name
branch = "example"
depends_on = [
github_repository.example-1
github_repository.example-1,
module.example-3
]
}
module "example-3" {
source = "./foo/module"
}
output "branch_sha" {
value = data.github_branch.example-2.sha
}
```

Let's replace `-` with `_`.
You need to specify either `-r` or `--jsonnet (-j)`.
You must specify one of `--replace (-r)`, `--regexp`, or `--jsonnet (-j)`.
In this case, let's use `-r`.
[If you need more flexible renaming, you can use Jsonnet. For details, please see here](#jsonnet).
If you need more flexible renaming, you can use [regular expression](#rename-resources-by-regular-expression) or [Jsonnet](#jsonnet).

Run `tfmv -r "-/_"`.
You don't need to run `terraform init`.
Expand All @@ -49,24 +113,37 @@ main.tf:

```diff
diff --git a/example/main.tf b/example/main.tf
index 48ce91d..e618ab1 100644
index 48ef3bd..9110880 100644
--- a/example/main.tf
+++ b/example/main.tf
@@ -1,11 +1,11 @@
@@ -1,20 +1,20 @@
-resource "github_repository" "example-1" {
+resource "github_repository" "example_1" {
name = "example-1"
}

resource "github_branch" "example" {
-data "github_branch" "example-2" {
- repository = github_repository.example-1.name
+data "github_branch" "example_2" {
+ repository = github_repository.example_1.name
branch = "example"
depends_on = [
- github_repository.example-1
+ github_repository.example_1
- github_repository.example-1,
- module.example-3
+ github_repository.example_1,
+ module.example_3
]
}

-module "example-3" {
+module "example_3" {
source = "./foo/module"
}

output "branch_sha" {
- value = data.github_branch.example-2.sha
+ value = data.github_branch.example_2.sha
}
```

moved.tf:
Expand All @@ -76,6 +153,11 @@ moved {
from = github_repository.example-1
to = github_repository.example_1
}
moved {
from = module.example-3
to = module.example_3
}
```

### Pass *.tf via arguments
Expand Down
4 changes: 2 additions & 2 deletions example/foo/aws_s3_bucket.tf
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
resource "aws_s3_bucket" "example_1" {
resource "aws_s3_bucket" "example-1" {
bucket = "test-1"
}

resource "aws_s3_bucket" "example_2" {
resource "aws_s3_bucket" "example-2" {
bucket = "test-2"
}
2 changes: 1 addition & 1 deletion example/foo/module_foo.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module "foo_prod" {
module "foo_production" {
source = "./module"
}
3 changes: 3 additions & 0 deletions example/foo/module_foo.tf.after
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module "foo_prod" {
source = "./module"
}
13 changes: 11 additions & 2 deletions example/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,19 @@ resource "github_repository" "example-1" {
name = "example-1"
}

resource "github_branch" "example" {
data "github_branch" "example-2" {
repository = github_repository.example-1.name
branch = "example"
depends_on = [
github_repository.example-1
github_repository.example-1,
module.example-3
]
}

module "example-3" {
source = "./foo/module"
}

output "branch_sha" {
value = data.github_branch.example-2.sha
}
13 changes: 11 additions & 2 deletions example/main.tf.after
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,19 @@ resource "github_repository" "example_1" {
name = "example-1"
}

resource "github_branch" "example" {
data "github_branch" "example_2" {
repository = github_repository.example_1.name
branch = "example"
depends_on = [
github_repository.example_1
github_repository.example_1,
module.example_3
]
}

module "example_3" {
source = "./foo/module"
}

output "branch_sha" {
value = data.github_branch.example_2.sha
}
2 changes: 1 addition & 1 deletion pkg/cli/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func parseFlags(f *Flag) {
f.Args = flag.Args()
}

const help = `tfmv - Rename Terraform resources and modules and generate moved blocks.
const help = `tfmv - Rename Terraform resources, data sources, and modules and generate moved blocks.
https://github.com/suzuki-shunsuke/tfmv
Usage:
Expand Down
39 changes: 31 additions & 8 deletions pkg/controller/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import (
"regexp"
)

const wordResource = "resource"
const (
wordResource = "resource"
wordData = "data"
wordModule = "module"
)

type Block struct {
File string `json:"file"`
Expand All @@ -21,30 +25,49 @@ type Block struct {
NewHCLAddress string `json:"-"`
}

func isResource(blockType string) bool {
return blockType == wordResource
}

func (b *Block) IsResource() bool {
return b.BlockType == wordResource
return isResource(b.BlockType)
}

func hclAddress(blockType, resourceType, name string) string {
if blockType == wordResource {
switch blockType {
case wordResource:
return fmt.Sprintf("resource.%s.%s", resourceType, name)
case wordData:
return fmt.Sprintf("data.%s.%s", resourceType, name)
case wordModule:
return "module." + name
}
return "module." + name
return ""
}

func tfAddress(blockType, resourceType, name string) string {
if blockType == wordResource {
switch blockType {
case wordResource:
return fmt.Sprintf("%s.%s", resourceType, name)
case wordData:
return fmt.Sprintf("data.%s.%s", resourceType, name)
case wordModule:
return "module." + name
}
return "module." + name
return ""
}

func (b *Block) Regstr() string {
// A name must start with a letter or underscore and may contain only letters, digits, underscores, and dashes.
if b.IsResource() {
switch b.BlockType {
case wordResource:
return fmt.Sprintf(`\b%s\.%s\b`, b.ResourceType, b.Name)
case wordData:
return fmt.Sprintf(`\bdata\.%s\.%s\b`, b.ResourceType, b.Name)
case wordModule:
return fmt.Sprintf(`\bmodule\.%s\b`, b.Name)
}
return fmt.Sprintf(`\bmodule\.%s\b`, b.Name)
return ""
}

func (b *Block) SetNewName(newName string) {
Expand Down
1 change: 0 additions & 1 deletion pkg/controller/jsonnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ func SetNativeFunctions(vm *jsonnet.VM) {
"strings.Repeat": strings.Repeat,
"strings.Replace": strings.Replace,
"strings.TrimPrefix": strings.TrimPrefix,
"strings.TrimSpace": strings.TrimSpace, //nolint:staticcheck
"url.Parse": url.Parse,
}
for k, v := range m {
Expand Down
3 changes: 3 additions & 0 deletions pkg/controller/moved_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import (
)

func (c *Controller) writeMovedBlock(block *Block, dest, movedFile string) error {
if block.BlockType == wordData {
return nil
}
file, err := c.fs.OpenFile(movedFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644) //nolint:mnd
if err != nil {
return fmt.Errorf("open a file: %w", err)
Expand Down
9 changes: 7 additions & 2 deletions pkg/controller/parse_tf.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,13 @@ func parse(src []byte, filePath string, include, exclude *regexp.Regexp) ([]*Blo
return blocks, nil
}

func parseBlock(filePath string, block *hclsyntax.Block, include, exclude *regexp.Regexp) (*Block, error) { //nolint:cyclop
if block.Type != wordResource && block.Type != "module" {
func parseBlock(filePath string, block *hclsyntax.Block, include, exclude *regexp.Regexp) (*Block, error) {
types := map[string]struct{}{
wordResource: {},
wordData: {},
wordModule: {},
}
if _, ok := types[block.Type]; !ok {
return nil, nil //nolint:nilnil
}
b := &Block{
Expand Down
14 changes: 8 additions & 6 deletions pkg/controller/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,14 @@ func (c *Controller) handleFile(logE *logrus.Entry, renamer Renamer, input *Inpu

func (c *Controller) handleBlock(logE *logrus.Entry, editor *Editor, input *Input, block *Block) error {
// generate moved blocks
if input.DryRun {
logE.WithField("moved_file", block.MovedFile).Info("[DRY RUN] generate a moved block")
} else {
logE.WithField("moved_file", block.MovedFile).Info("writing a moved block")
if err := c.writeMovedBlock(block, block.NewName, block.MovedFile); err != nil {
return fmt.Errorf("write a moved block: %w", err)
if block.BlockType != wordData {
if input.DryRun {
logE.WithField("moved_file", block.MovedFile).Info("[DRY RUN] generate a moved block")
} else {
logE.WithField("moved_file", block.MovedFile).Info("writing a moved block")
if err := c.writeMovedBlock(block, block.NewName, block.MovedFile); err != nil {
return fmt.Errorf("write a moved block: %w", err)
}
}
}

Expand Down

0 comments on commit 9dd4527

Please sign in to comment.