Skip to content

Commit

Permalink
feat: Enable to use directory as resources and patches (#22)
Browse files Browse the repository at this point in the history
* refactor func name

* add CollectHCLFilePaths func

* feat: enable to use directory

* fix overall typos
  • Loading branch information
tk3fftk authored Feb 27, 2024
1 parent 6ccd4ec commit 8259c74
Show file tree
Hide file tree
Showing 12 changed files with 135 additions and 27 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ tfustomize {
}
resources {
pathes = [
paths = [
"../../base/main.tf",
]
}
pathces {
pathes = [
patches {
paths = [
"./main.tf",
]
}
Expand Down
4 changes: 2 additions & 2 deletions api/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ type Tfustomize struct {
}

type Resource struct {
Pathes []string `hcl:"pathes,attr"`
Paths []string `hcl:"paths,attr"`
}

type Patch struct {
Pathes []string `hcl:"pathes,attr"`
Paths []string `hcl:"paths,attr"`
}

func LoadConfig(configPath string) (TfustomizeConfig, error) {
Expand Down
51 changes: 44 additions & 7 deletions api/hcl_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,48 @@ func (p HCLParser) ReadHCLFile(filename string) (*hclwrite.File, error) {
return file, nil
}

func (p HCLParser) ConcatFile(baseDir string, pathes []string) (*hclwrite.File, error) {
// CollectHCLFilePaths returns a list of .if files in the given paths.
// If a path is a directory, it returns all .if files in the directory.
// If a path is a file, it returns the file if it has a .tf extension.
// The baseDir parameter is used as the root directory when constructing the full path of each file.
func (p HCLParser) CollectHCLFilePaths(baseDir string, paths []string) ([]string, error) {
var collectedPaths []string

for _, path := range paths {
fullPath := filepath.Join(baseDir, path)
fileInfo, err := os.Stat(fullPath)
if err != nil {
return nil, err
}

if fileInfo.IsDir() {
fileInfos, err := os.ReadDir(fullPath)
if err != nil {
return nil, err
}
for _, fileInfo := range fileInfos {
if filepath.Ext(fileInfo.Name()) == ".tf" {
collectedPaths = append(collectedPaths, filepath.Join(fullPath, fileInfo.Name()))
}
}
} else {
if filepath.Ext(fileInfo.Name()) == ".tf" {
collectedPaths = append(collectedPaths, fullPath)
} else {
slog.Warn("Only .tf file extension is supported, so ignore the file", "filename", fileInfo.Name())
}
}
}

return collectedPaths, nil
}

// ConcatFiles concatenates the contents of the given .tf files.
func (p HCLParser) ConcatFiles(paths []string) (*hclwrite.File, error) {
outputFile := hclwrite.NewEmptyFile()

for _, path := range pathes {
file, err := p.ReadHCLFile(filepath.Join(baseDir, path))
for _, path := range paths {
file, err := p.ReadHCLFile(path)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -166,11 +203,11 @@ func mergeBlock(baseBlock *hclwrite.Block, overlayBlock *hclwrite.Block) (*hclwr

tmpAttributes := map[string]*hclwrite.Attribute{}

for name, baseBlockBodyArrtibute := range baseBlockBody.Attributes() {
tmpAttributes[name] = baseBlockBodyArrtibute
for name, baseBlockBodyAttribute := range baseBlockBody.Attributes() {
tmpAttributes[name] = baseBlockBodyAttribute
}
for name, overlayBlockBodyArrtibute := range overlayBlockBody.Attributes() {
tmpAttributes[name] = overlayBlockBodyArrtibute
for name, overlayBlockBodyAttribute := range overlayBlockBody.Attributes() {
tmpAttributes[name] = overlayBlockBodyAttribute
}

sortedNames := make([]string, 0, len(tmpAttributes))
Expand Down
67 changes: 63 additions & 4 deletions api/hcl_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,53 @@ import (

var regexpFormatNewLines = regexp.MustCompile(`\n{2,}`)

func TestConcatFile(t *testing.T) {
func TestCollectHCLFilePaths(t *testing.T) {
tests := []struct {
name string
baseDir string
paths []string
expect []string
wantErr bool
}{
{
name: "directory",
baseDir: "../test",
paths: []string{"./collect_hcl_file_paths"},
expect: []string{"../test/collect_hcl_file_paths/1.tf", "../test/collect_hcl_file_paths/2.tf"},
wantErr: false,
},
{
name: "file",
baseDir: "../test",
paths: []string{"./collect_hcl_file_paths/1.tf"},
expect: []string{"../test/collect_hcl_file_paths/1.tf"},
wantErr: false,
},
{
name: "not found",
baseDir: "../test",
paths: []string{"./collect_hcl_file_paths/not_found.tf"},
expect: nil,
wantErr: true,
},
}

parser := api.HCLParser{}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parser.CollectHCLFilePaths(tt.baseDir, tt.paths)
if (err != nil) != tt.wantErr {
t.Errorf("CollectHCLFilePaths() error = %v, wantErr %v", err, tt.wantErr)
return
}
assert.Equal(t, tt.expect, got)
})
}

}

func TestConcatFiles(t *testing.T) {
tests := []struct {
name string
contents []string
Expand Down Expand Up @@ -81,7 +127,12 @@ resource "aws_s3_bucket" "bar" {
fileNames = append(fileNames, fileName)
}

hclFile, err := parser.ConcatFile(dir, fileNames)
filePaths, err := parser.CollectHCLFilePaths(dir, fileNames)
if err != nil {
t.Fatal(err)
}

hclFile, err := parser.ConcatFiles(filePaths)
if err != nil && !tt.wantErr {
t.Errorf("%q. ConcatFile() error = %v, wantErr %v", tt.name, err, tt.wantErr)
assert.Fail(t, "unexpected error")
Expand Down Expand Up @@ -217,11 +268,19 @@ variable "image_id" {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
baseHCL, err := parser.ConcatFile(testDir, tt.base)
basePaths, err := parser.CollectHCLFilePaths(testDir, tt.base)
if err != nil {
t.Fatal(err)
}
baseHCL, err := parser.ConcatFiles(basePaths)
if err != nil {
t.Fatal(err)
}
overlayPaths, err := parser.CollectHCLFilePaths(testDir, tt.overlay)
if err != nil {
t.Fatal(err)
}
overlayHCL, err := parser.ConcatFile(testDir, tt.overlay)
overlayHCL, err := parser.ConcatFiles(overlayPaths)
if err != nil {
t.Fatal(err)
}
Expand Down
17 changes: 13 additions & 4 deletions cmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ The command concatenates files specified in the resources and patches blocks, me
}

conf, _ := api.LoadConfig(tfustomizationPath)
if len(conf.Resources.Pathes) == 0 {
if len(conf.Resources.Paths) == 0 {
err := fmt.Errorf("tfustomization.hcl must have a resources block")
return err
}
Expand All @@ -49,11 +49,20 @@ The command concatenates files specified in the resources and patches blocks, me

parser := api.NewHCLParser()

baseHCLFile, err := parser.ConcatFile(filepath.Dir(tfustomizationPath), conf.Resources.Pathes)
basePaths, err := parser.CollectHCLFilePaths(filepath.Dir(tfustomizationPath), conf.Resources.Paths)
if err != nil {
return err
}
overlayHCLFile, err := parser.ConcatFile(filepath.Dir(tfustomizationPath), conf.Patches.Pathes)
baseHCLFile, err := parser.ConcatFiles(basePaths)
if err != nil {
return err
}

overlayPaths, err := parser.CollectHCLFilePaths(filepath.Dir(tfustomizationPath), conf.Patches.Paths)
if err != nil {
return err
}
overlayHCLFile, err := parser.ConcatFiles(overlayPaths)
if err != nil {
return err
}
Expand Down Expand Up @@ -98,7 +107,7 @@ func init() {

// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
buildCmd.Flags().BoolVarP(&print, "print", "p", false, "Print the result to the console instaed of writing to a file")
buildCmd.Flags().BoolVarP(&print, "print", "p", false, "Print the result to the console instead of writing to a file")
buildCmd.Flags().StringVarP(&outputDir, "out", "o", "generated", "Output directory")
buildCmd.Flags().StringVarP(&outputFile, "outfile", "f", "main.tf", "Output filename")
}
4 changes: 2 additions & 2 deletions example/production/tfustomization.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ tfustomize {
}

resources {
pathes = [
paths = [
"../staging/main.tf",
]
}

patches {
pathes = [
paths = [
"main.tf",
]
}
4 changes: 2 additions & 2 deletions example/staging/tfustomization.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ tfustomize {
}

resources {
pathes = [
paths = [
"main.tf",
]
}

patches {
pathes = []
paths = []
}
1 change: 1 addition & 0 deletions test/collect_hcl_file_paths/1.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
provider "null" {}
1 change: 1 addition & 0 deletions test/collect_hcl_file_paths/2.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
resource "null_resource" "cluster" {}
1 change: 1 addition & 0 deletions test/collect_hcl_file_paths/3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
this file should not be included.
2 changes: 1 addition & 1 deletion test/invalid_cases/broken_schema_tfustomization.hcl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
bases {
pathes = [
paths = [
"../base/main.tf",
"../base/provider.tf",
]
Expand Down
4 changes: 2 additions & 2 deletions test/overlay/tfustomization.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ tfustomize {
}

resources {
pathes = [
paths = [
"../base/main.tf",
"../base/provider.tf",
]
}

patches {
pathes = [
paths = [
"./overlay.tf",
"./provider.tf",
]
Expand Down

0 comments on commit 8259c74

Please sign in to comment.