├── .circleci ├── config.yml ├── install-golang.ps1 ├── install-opentofu.ps1 ├── install-terraform.ps1 └── install-terragrunt.ps1 ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── pull_request_template.md ├── .gitignore ├── .gon_amd64.hcl ├── .gon_arm64.hcl ├── CODEOWNERS ├── LICENSE ├── NOTICE ├── README.md ├── cli └── boilerplate_cli.go ├── config ├── config.go ├── config_test.go ├── get_variables.go └── get_variables_test.go ├── docs └── bp-validation.png ├── errors └── errors.go ├── examples ├── for-learning-and-testing │ ├── dependencies-dynamic │ │ ├── README.md │ │ └── boilerplate.yml │ ├── dependencies-for-each-reference-list-of-strings │ │ └── boilerplate.yml │ ├── dependencies-for-each-reference │ │ └── boilerplate.yml │ ├── dependencies-for-each │ │ └── boilerplate.yml │ ├── dependencies-recursive │ │ ├── README.md │ │ └── boilerplate.yml │ ├── dependencies-remote │ │ ├── README.md │ │ └── boilerplate.yml │ ├── dependencies-varfile-precedence │ │ ├── README.md │ │ ├── boilerplate.yml │ │ ├── docs_vars_default_vars.yml │ │ ├── website_vars.yml │ │ └── website_vars_override_vars.yml │ ├── dependencies-varfile │ │ ├── README.md │ │ ├── boilerplate.yml │ │ ├── docs_vars.yml │ │ └── website_vars.yml │ ├── dependencies │ │ ├── README.md │ │ └── boilerplate.yml │ ├── docs │ │ ├── README.md │ │ ├── boilerplate.yml │ │ └── interpolated-folder-{{.SubFolderName%7Cdasherize}} │ │ │ └── {{.FileName%7csnakeCase}}.py │ ├── hooks-working-dir │ │ ├── boilerplate.yml │ │ └── subdir │ │ │ └── test.txt │ ├── include │ │ ├── boilerplate.yml │ │ └── target.txt │ ├── java-project │ │ ├── boilerplate.yml │ │ └── com │ │ │ └── {{.CompanyName %7C dasherize %7C downcase}} │ │ │ └── example │ │ │ └── Example.java │ ├── json │ │ ├── boilerplate.yml │ │ ├── example1.json │ │ └── example2.json │ ├── jsonnet │ │ ├── boilerplate.yml │ │ ├── people.json │ │ └── people_jsonnet.json.jsonnet │ ├── kebab-case-bug-unix │ │ ├── boilerplate.yml │ │ └── template.txt │ ├── order │ │ ├── boilerplate.yml │ │ └── template.txt │ ├── partials │ │ ├── boilerplate.yml │ │ └── target.txt │ ├── regression-template-escape │ │ ├── boilerplate.yml │ │ └── config.yml │ ├── shell-disabled │ │ ├── README.md │ │ ├── boilerplate.yml │ │ └── example-script.sh │ ├── shell │ │ ├── boilerplate.yml │ │ ├── example-script-2.sh │ │ ├── example-script.sh │ │ └── hello-world.txt │ ├── skip-files-glob │ │ ├── a │ │ │ └── b │ │ │ │ ├── c │ │ │ │ ├── d.yml │ │ │ │ └── foo.txt │ │ │ │ └── e.yml │ │ └── boilerplate.yml │ ├── skip-files-mixed │ │ ├── boilerplate.yml │ │ ├── code.sh │ │ └── docs │ │ │ └── README.md │ ├── skip-files-multiple │ │ ├── a.yml │ │ ├── b.yml │ │ └── boilerplate.yml │ ├── skip-files-nested │ │ ├── a │ │ │ └── b │ │ │ │ └── c │ │ │ │ └── d.yml │ │ └── boilerplate.yml │ ├── skip-not-path-mixed-noskip │ │ ├── a │ │ │ └── foo.yml │ │ ├── boilerplate.yml │ │ └── docs │ │ │ ├── bar.txt │ │ │ └── foo.txt │ ├── skip-not-path-mixed-skip │ │ ├── a │ │ │ └── foo.yml │ │ ├── boilerplate.yml │ │ └── docs │ │ │ ├── bar.txt │ │ │ └── foo.txt │ ├── skip-not-path-multiple │ │ ├── a │ │ │ └── foo.yml │ │ ├── boilerplate.yml │ │ └── docs │ │ │ ├── bar.txt │ │ │ └── foo.txt │ ├── skip-not-path │ │ ├── a │ │ │ └── foo.yml │ │ ├── boilerplate.yml │ │ └── docs │ │ │ ├── bar.txt │ │ │ └── foo.txt │ ├── template-helpers │ │ ├── boilerplate.yml │ │ ├── sample.txt │ │ └── skipped.txt │ ├── terraform │ │ ├── boilerplate.yml │ │ └── main.tf │ ├── tofu-example │ │ ├── README.md │ │ ├── boilerplate.yml │ │ ├── main.tf │ │ └── outputs.tf │ ├── tofu-module-full │ │ └── boilerplate.yml │ ├── tofu-module │ │ ├── LICENSE.txt │ │ ├── README.md │ │ ├── boilerplate.yml │ │ ├── main.tf │ │ ├── outputs.tf │ │ └── variables.tf │ ├── tofu-test-unix │ │ ├── boilerplate.yml │ │ └── template_test.go │ ├── tofu-test │ │ ├── boilerplate.yml │ │ └── vpc_test.go │ ├── validations │ │ ├── boilerplate.yml │ │ └── template.txt │ ├── variables-recursive │ │ ├── README.md │ │ └── boilerplate.yml │ ├── variables │ │ ├── boilerplate.yml │ │ └── example.txt │ └── website │ │ ├── boilerplate.yml │ │ ├── index.html │ │ └── logo.png └── for-production │ └── terragrunt-architecture-catalog │ ├── README.md │ ├── blueprints │ ├── README.md │ ├── postgres │ │ └── boilerplate.yml │ ├── redis │ │ └── boilerplate.yml │ ├── reference-architecture-app-account │ │ └── boilerplate.yml │ ├── reference-architecture │ │ └── boilerplate.yml │ └── vpc-app │ │ └── boilerplate.yml │ ├── sample_reference_architecture_vars.yml │ └── templates │ ├── _root │ ├── _envcommon │ │ ├── README.md │ │ └── boilerplate.yml │ ├── account │ │ ├── account.hcl │ │ └── boilerplate.yml │ ├── infrastructure-live │ │ ├── .terraform-version │ │ ├── .tgswitchrc │ │ ├── accounts.json │ │ ├── boilerplate.yml │ │ ├── common.hcl │ │ └── terragrunt.hcl │ └── region │ │ ├── boilerplate.yml │ │ └── region.hcl │ ├── layouts │ ├── envcommon.hcl │ └── terragrunt.hcl │ └── services │ ├── data-stores │ ├── rds │ │ ├── boilerplate.yml │ │ ├── rds.hcl │ │ └── terragrunt.hcl │ └── redis │ │ ├── boilerplate.yml │ │ ├── redis.hcl │ │ └── terragrunt.hcl │ └── networking │ └── vpc │ ├── boilerplate.yml │ ├── terragrunt.hcl │ └── vpc-app.hcl ├── getter-helper ├── file_getter.go ├── getter_helper.go ├── getter_helper_unix_test.go ├── tmp_path_unix.go └── tmp_path_windows.go ├── go.mod ├── go.sum ├── integration-tests ├── envvars_test.go ├── error_message_test.go ├── examples_test.go ├── examples_unix_test.go ├── examples_windows_test.go ├── for_production_example_unix_test.go ├── required_version_test.go ├── slice_parsing_test.go ├── test_helpers_unix.go └── test_helpers_windows.go ├── main.go ├── options └── options.go ├── render ├── render_jsonnet.go ├── render_jsonnet_unix_test.go ├── render_template.go ├── render_template_test.go ├── template_helpers.go └── template_helpers_test.go ├── templates ├── engines_processor.go ├── skip_files_processor.go ├── template_processor.go └── template_processor_test.go ├── test-fixtures ├── config-test │ ├── full-config │ │ └── boilerplate.yml │ └── invalid-config │ │ └── boilerplate.yml ├── env-vars │ ├── boilerplate.yml │ └── target.txt ├── examples-expected-output-unix │ ├── kebab-case-bug-unix │ │ └── test-2-a │ └── tofu-test-unix │ │ └── vpc_test.go ├── examples-expected-output │ ├── dependencies-dynamic │ │ ├── README.md │ │ ├── docs │ │ │ ├── README.md │ │ │ └── interpolated-folder-example-folder │ │ │ │ └── my_example_file.py │ │ └── website │ │ │ ├── index.html │ │ │ └── logo.png │ ├── dependencies-for-each-reference-list-of-strings │ │ └── live │ │ │ ├── dev │ │ │ └── main.tf │ │ │ ├── prod │ │ │ └── main.tf │ │ │ └── stage │ │ │ └── main.tf │ ├── dependencies-for-each-reference │ │ └── live │ │ │ ├── dev │ │ │ └── main.tf │ │ │ ├── prod │ │ │ └── main.tf │ │ │ └── stage │ │ │ └── main.tf │ ├── dependencies-for-each │ │ └── live │ │ │ ├── dev │ │ │ └── main.tf │ │ │ ├── prod │ │ │ └── main.tf │ │ │ └── stage │ │ │ └── main.tf │ ├── dependencies-recursive │ │ ├── README.md │ │ ├── dependencies │ │ │ ├── README.md │ │ │ ├── docs │ │ │ │ ├── README.md │ │ │ │ └── interpolated-folder-example-folder │ │ │ │ │ └── my_example_file.py │ │ │ └── website │ │ │ │ ├── index.html │ │ │ │ └── logo.png │ │ └── java-project │ │ │ └── com │ │ │ └── acme │ │ │ └── example │ │ │ └── Example.java │ ├── dependencies-remote │ │ ├── README.md │ │ ├── docs │ │ │ ├── README.md │ │ │ └── interpolated-folder-example-folder │ │ │ │ └── my_example_file.py │ │ └── website │ │ │ ├── index.html │ │ │ └── logo.png │ ├── dependencies-varfile-precedence │ │ ├── README.md │ │ ├── docs │ │ │ ├── README.md │ │ │ └── interpolated-folder-example-folder │ │ │ │ └── reference_name.py │ │ └── website │ │ │ ├── index.html │ │ │ └── logo.png │ ├── dependencies-varfile │ │ ├── README.md │ │ ├── docs │ │ │ ├── README.md │ │ │ └── interpolated-folder-example-folder │ │ │ │ └── my_example_file.py │ │ └── website │ │ │ ├── index.html │ │ │ └── logo.png │ ├── dependencies │ │ ├── README.md │ │ ├── docs │ │ │ ├── README.md │ │ │ └── interpolated-folder-example-folder │ │ │ │ └── my_example_file.py │ │ └── website │ │ │ ├── index.html │ │ │ └── logo.png │ ├── docs │ │ ├── README.md │ │ └── interpolated-folder-example-folder │ │ │ └── my_example_file.py │ ├── hooks-working-dir │ │ └── subdir │ │ │ └── test.txt │ ├── include │ │ └── target.txt │ ├── java-project │ │ └── com │ │ │ └── acme │ │ │ └── example │ │ │ └── Example.java │ ├── json │ │ ├── example1.json │ │ └── example2.json │ ├── jsonnet │ │ ├── people.json │ │ └── people_jsonnet.json │ ├── order │ │ └── template.txt │ ├── partials │ │ └── target.txt │ ├── regression-template-escape │ │ └── config.yml │ ├── shell-disabled │ │ ├── README.md │ │ └── example-script.sh │ ├── shell │ │ ├── after-hook-example.txt │ │ ├── before-hook-example.txt │ │ ├── example-script-2.sh │ │ ├── example-script.sh │ │ └── hello-world.txt │ ├── skip-files-glob │ │ └── a │ │ │ └── b │ │ │ └── c │ │ │ └── foo.txt │ ├── skip-files-mixed │ │ └── docs │ │ │ └── README.md │ ├── skip-files-multiple │ │ └── b.yml │ ├── skip-files-nested │ │ └── a │ │ │ └── b │ │ │ └── c │ │ │ └── .keep-dir │ ├── skip-not-path-mixed-noskip │ │ └── docs │ │ │ ├── bar.txt │ │ │ └── foo.txt │ ├── skip-not-path-mixed-skip │ │ └── a │ │ │ └── foo.yml │ ├── skip-not-path-multiple │ │ └── docs │ │ │ ├── bar.txt │ │ │ └── foo.txt │ ├── skip-not-path │ │ └── docs │ │ │ ├── bar.txt │ │ │ └── foo.txt │ ├── template-helpers │ │ ├── docs │ │ │ ├── README.md │ │ │ └── interpolated-folder-example-folder │ │ │ │ └── my_example_file.py │ │ ├── sample.txt │ │ └── website │ │ │ ├── index.html │ │ │ └── logo.png │ ├── terraform │ │ └── main.tf │ ├── tofu-example │ │ ├── README.md │ │ ├── main.tf │ │ └── outputs.tf │ ├── tofu-module-full │ │ ├── examples │ │ │ └── vpc │ │ │ │ ├── README.md │ │ │ │ ├── main.tf │ │ │ │ └── outputs.tf │ │ ├── modules │ │ │ └── vpc │ │ │ │ ├── LICENSE.txt │ │ │ │ ├── README.md │ │ │ │ ├── main.tf │ │ │ │ ├── outputs.tf │ │ │ │ └── variables.tf │ │ └── test │ │ │ └── vpc_test.go │ ├── tofu-module │ │ ├── LICENSE.txt │ │ ├── README.md │ │ ├── main.tf │ │ ├── outputs.tf │ │ └── variables.tf │ ├── tofu-test │ │ └── vpc_test.go │ ├── validations │ │ └── template.txt │ ├── variables-recursive │ │ ├── README.md │ │ └── example.txt │ └── website │ │ ├── index.html │ │ └── logo.png ├── examples-var-files │ ├── dependencies-dynamic │ │ └── vars.yml │ ├── dependencies-for-each-reference-list-of-strings │ │ └── vars.yml │ ├── dependencies-for-each-reference │ │ └── vars.yml │ ├── dependencies-for-each │ │ └── vars.yml │ ├── dependencies-recursive │ │ └── vars.yml │ ├── dependencies-remote │ │ └── vars.yml │ ├── dependencies-varfile-precedence │ │ └── vars.yml │ ├── dependencies-varfile │ │ └── vars.yml │ ├── dependencies │ │ └── vars.yml │ ├── docs │ │ └── vars.yml │ ├── hooks-working-dir │ │ └── vars.yml │ ├── include │ │ └── vars.yml │ ├── java-project │ │ └── vars.yml │ ├── json │ │ └── vars.yml │ ├── jsonnet │ │ └── vars.yml │ ├── kebab-case-bug-unix │ │ └── vars.yml │ ├── order │ │ └── vars.yml │ ├── partials │ │ └── vars.yml │ ├── regression-template-escape │ │ └── vars.yml │ ├── shell-disabled │ │ └── vars.yml │ ├── shell │ │ └── vars.yml │ ├── skip-files-glob │ │ └── vars.yml │ ├── skip-files-mixed │ │ └── vars.yml │ ├── skip-files-multiple │ │ └── vars.yml │ ├── skip-files-nested │ │ └── vars.yml │ ├── skip-not-path-mixed-noskip │ │ └── vars.yml │ ├── skip-not-path-mixed-skip │ │ └── vars.yml │ ├── skip-not-path-multiple │ │ └── vars.yml │ ├── skip-not-path │ │ └── vars.yml │ ├── template-helpers │ │ └── vars.yml │ ├── terraform │ │ └── vars.yml │ ├── tofu-example │ │ └── vars.yml │ ├── tofu-module-full │ │ └── vars.yml │ ├── tofu-module │ │ └── vars.yml │ ├── tofu-test-unix │ │ └── vars.yml │ ├── tofu-test │ │ └── vars.yml │ ├── validations │ │ └── vars.yml │ ├── variables-recursive │ │ └── vars.yml │ └── website │ │ └── vars.yml ├── include-test │ └── template.txt ├── jsonnet-unit-test │ ├── externalVars │ │ ├── expected.json │ │ ├── template.jsonnet │ │ └── variables.json │ ├── functions │ │ ├── expected.json │ │ ├── template.jsonnet │ │ └── variables.json │ └── imports │ │ ├── expected.json │ │ ├── funcdef.libsonnet │ │ ├── template.jsonnet │ │ └── variables.json ├── marshal-yaml-test │ ├── shell │ │ └── expected.yml │ └── variables-recursive │ │ └── expected.yml ├── partials-test │ ├── first.txt │ └── second.txt ├── regression-test │ ├── misspelled-git │ │ └── boilerplate.yml │ ├── required-version │ │ ├── match │ │ │ └── boilerplate.yml │ │ ├── over-test │ │ │ └── boilerplate.yml │ │ └── under-test │ │ │ └── boilerplate.yml │ └── slice-parsing │ │ ├── boilerplate.yml │ │ └── output.txt ├── templates-test │ └── full-file-snippet.txt └── util-test │ └── is-text-file │ ├── binary-file │ ├── binary-file.jpg │ ├── binary-file.pdf │ ├── binary-file.png │ ├── binary-file.zip │ ├── empty-file │ ├── file-go.go │ ├── file-hcl.hcl │ ├── file-java.java │ ├── file-xml.xml │ ├── json-file.json │ ├── text-file.html │ ├── text-file.js │ ├── text-file.md │ ├── text-file.tf │ ├── text-file.txt │ └── yaml-file.yaml ├── util ├── collections.go ├── file.go ├── file_test.go ├── logger.go ├── marshal.go ├── prompt.go └── shell.go └── variables ├── dependencies.go ├── dependencies_test.go ├── engines.go ├── engines_test.go ├── hooks.go ├── skip_files.go ├── types.go ├── variables.go ├── variables_test.go ├── yaml_helpers.go └── yaml_helpers_test.go /.circleci/install-golang.ps1: -------------------------------------------------------------------------------- 1 | # Install golang using Chocolatey 2 | choco install golang --version 1.23.1 -y 3 | # Verify installation 4 | Get-Command go 5 | go version 6 | -------------------------------------------------------------------------------- /.circleci/install-opentofu.ps1: -------------------------------------------------------------------------------- 1 | OpenTofuInstallPath = "C:\Program Files\tofu\tofu.exe" 2 | $OpenTofuTmpPath = "C:\OpenTofutmp" 3 | $OpenTofuTmpBinaryPath = "C:\OpenTofutmp\tofu.exe" 4 | $OpenTofuPath = "C:\Program Files\tofu" 5 | if (Test-Path -Path $OpenTofuInstallPath) 6 | { 7 | Remove-Item $OpenTofuInstallPath -Recurse 8 | } 9 | # Download OpenTofu and unpack it 10 | $OpenTofuURI = "https://github.com/opentofu/opentofu/releases/download/v1.6.2/tofu_1.6.2_windows_amd64.zip" 11 | $output = "tofu_1.6.2_windows_amd64.zip" 12 | $ProgressPreference = "SilentlyContinue" 13 | Invoke-WebRequest -Uri $OpenTofuURI -OutFile $output 14 | New-Item -ItemType "directory" -Path $OpenTofuTmpPath 15 | Expand-Archive -LiteralPath $output -DestinationPath $OpenTofuTmpPath 16 | New-Item -ItemType "directory" -Path $OpenTofuPath 17 | Move-Item $OpenTofuTmpBinaryPath $OpenTofuPath 18 | $OldPath = [System.Environment]::GetEnvironmentVariable('PATH', "Machine") 19 | $NewPath = "$OldPath;$OpenTofuPath" 20 | [Environment]::SetEnvironmentVariable("PATH", "$NewPath", "Machine") 21 | $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") 22 | tofu version 23 | -------------------------------------------------------------------------------- /.circleci/install-terraform.ps1: -------------------------------------------------------------------------------- 1 | # Install terraform using Chocolatey 2 | choco install terraform --version 1.5.0 -y 3 | # Verify installation 4 | Get-Command terraform 5 | terraform version 6 | -------------------------------------------------------------------------------- /.circleci/install-terragrunt.ps1: -------------------------------------------------------------------------------- 1 | # Install Terragrunt using Chocolatey 2 | choco install terragrunt --version 0.55.10 -y 3 | # Verify installation 4 | Get-Command terragrunt 5 | terragrunt version 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a bug report to help us improve. 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | 14 | 15 | **Describe the bug** 16 | A clear and concise description of what the bug is. 17 | 18 | **To Reproduce** 19 | Steps to reproduce the behavior including the relevant Terraform/Terragrunt/Packer version number and any code snippets and module inputs you used. 20 | 21 | ```hcl 22 | // paste code snippets here 23 | ``` 24 | 25 | **Expected behavior** 26 | A clear and concise description of what you expected to happen. 27 | 28 | **Nice to have** 29 | - [ ] Terminal output 30 | - [ ] Screenshots 31 | 32 | **Additional context** 33 | Add any other context about the problem here. 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Submit a feature request for this repo. 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | 14 | 15 | **Describe the solution you'd like** 16 | A clear and concise description of what you want to happen. 17 | 18 | **Describe alternatives you've considered** 19 | A clear and concise description of any alternative solutions or features you've considered. 20 | 21 | **Additional context** 22 | Add any other context or screenshots about the feature request here. 23 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description 4 | 5 | Fixes #000. 6 | 7 | 8 | 9 | ## TODOs 10 | 11 | Read the [Gruntwork contribution guidelines](https://gruntwork.notion.site/Gruntwork-Coding-Methodology-02fdcd6e4b004e818553684760bf691e). 12 | 13 | - [ ] Update the docs. 14 | - [ ] Run the relevant tests successfully, including pre-commit checks. 15 | - [ ] Ensure any 3rd party code adheres with our [license policy](https://www.notion.so/gruntwork/Gruntwork-licenses-and-open-source-usage-policy-f7dece1f780341c7b69c1763f22b1378) or delete this line if its not applicable. 16 | - [ ] Include release notes. If this PR is backward incompatible, include a migration guide. 17 | 18 | ## Release Notes (draft) 19 | 20 | 21 | Added / Removed / Updated [X]. 22 | 23 | ### Migration Guide 24 | 25 | 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | vendor 3 | .terragrunt 4 | .DS_Store 5 | *.iml 6 | boilerplate 7 | -------------------------------------------------------------------------------- /.gon_amd64.hcl: -------------------------------------------------------------------------------- 1 | # See https://github.com/gruntwork-io/terraform-aws-ci/blob/main/modules/sign-binary-helpers/ 2 | # for further instructions on how to sign the binary + submitting for notarization. 3 | 4 | source = ["./bin/boilerplate_darwin_amd64"] 5 | 6 | bundle_id = "io.gruntwork.app.boilerplate" 7 | 8 | apple_id { 9 | username = "machine.apple@gruntwork.io" 10 | } 11 | 12 | sign { 13 | application_identity = "Developer ID Application: Gruntwork, Inc." 14 | } 15 | 16 | zip { 17 | output_path = "boilerplate_darwin_amd64.zip" 18 | } 19 | -------------------------------------------------------------------------------- /.gon_arm64.hcl: -------------------------------------------------------------------------------- 1 | # See https://github.com/gruntwork-io/terraform-aws-ci/blob/main/modules/sign-binary-helpers/ 2 | # for further instructions on how to sign the binary + submitting for notarization. 3 | 4 | source = ["./bin/boilerplate_darwin_arm64"] 5 | 6 | bundle_id = "io.gruntwork.app.boilerplate" 7 | 8 | apple_id { 9 | username = "machine.apple@gruntwork.io" 10 | } 11 | 12 | sign { 13 | application_identity = "Developer ID Application: Gruntwork, Inc." 14 | } 15 | 16 | zip { 17 | output_path = "boilerplate_darwin_arm64.zip" 18 | } 19 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # GRUNTWORK CODEOWNERS FILE 2 | # Gruntwork sets the codeowner for its repositories to the machine user `gruntwork-codeowner`. 3 | # We use an internal process for triaging all incoming issues and pull requests and that process will end up setting an assignee for any new issues. 4 | 5 | * @gruntwork-codeowner 6 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | boilerplate 2 | Copyright 2016 Gruntwork, Inc. 3 | 4 | This product includes software developed at Gruntwork (https://www.gruntwork.io/). -------------------------------------------------------------------------------- /docs/bp-validation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/docs/bp-validation.png -------------------------------------------------------------------------------- /errors/errors.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "fmt" 5 | 6 | goerrors "github.com/go-errors/errors" 7 | ) 8 | 9 | // Wrap the given error in an Error type that contains the stack trace. If the given error already has a stack trace, 10 | // it is used directly. If the given error is nil, return nil. 11 | func WithStackTrace(err error) error { 12 | if err == nil { 13 | return nil 14 | } 15 | 16 | return goerrors.Wrap(err, 1) 17 | } 18 | 19 | // Wrap the given error in an Error type that contains the stack trace and has the given message prepended as part of 20 | // the error message. If the given error already has a stack trace, it is used directly. If the given error is nil, 21 | // return nil. 22 | func WithStackTraceAndPrefix(err error, message string, args ...interface{}) error { 23 | if err == nil { 24 | return nil 25 | } 26 | 27 | return goerrors.WrapPrefix(err, fmt.Sprintf(message, args...), 1) 28 | } 29 | 30 | // Returns true if actual is the same type of error as expected. This method unwraps the given error objects (if they 31 | // are wrapped in objects with a stacktrace) and then does a simple equality check on them. 32 | func IsError(actual error, expected error) bool { 33 | return goerrors.Is(Unwrap(actual), expected) 34 | } 35 | 36 | // If the given error is a wrapper that contains a stacktrace, unwrap it and return the original, underlying error. 37 | // In all other cases, return the error unchanged 38 | func Unwrap(err error) error { 39 | if err == nil { 40 | return nil 41 | } 42 | 43 | goError, isGoError := err.(*goerrors.Error) 44 | if isGoError { 45 | return goError.Err 46 | } 47 | 48 | return err 49 | } 50 | 51 | // Convert the given error to a string, including the stack trace if available 52 | func PrintErrorWithStackTrace(err error) string { 53 | if err == nil { 54 | return "" 55 | } 56 | 57 | switch underlyingErr := err.(type) { 58 | case *goerrors.Error: 59 | return underlyingErr.ErrorStack() 60 | default: 61 | return err.Error() 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/dependencies-dynamic/README.md: -------------------------------------------------------------------------------- 1 | # {{ .Title }} 2 | 3 | {{ .Description }}. It specifies both the 4 | [docs](/examples/for-learning-and-testing/docs) and [website](/examples/for-learning-and-testing/website) examples as 5 | dependencies to show how one boilerplate template can pull in another, and that you can use interpolation in the 6 | `template-url` and `output-folder` parameters of dependencies to dynamically specify where to read the template and 7 | where to write the output. It also defines all the variables needed for both of those dependencies at the top level to 8 | show how variable inheritance works. 9 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/dependencies-dynamic/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: Description 3 | description: Enter the description of this template 4 | 5 | - name: Version 6 | description: Enter the version number that will be used by the docs dependency 7 | 8 | - name: Title 9 | description: Enter the title for the dependencies example 10 | 11 | - name: WelcomeText 12 | description: Enter the welcome text used by the website dependency 13 | 14 | - name: ShowLogo 15 | description: Should the webiste show the logo (true or false)? 16 | type: bool 17 | default: true 18 | 19 | - name: WebsiteTemplateFolder 20 | description: The path to the website templates folder. This is used to check that interpolations work in the template-url parameter of dependencies. 21 | 22 | - name: WebsiteOutputFolder 23 | description: The path to the website output folder. This is used to check that interpolations work in the output-folder parameter of dependencies. 24 | 25 | - name: SkipAllDependencies 26 | description: Set to true to skip all dependencies 27 | type: bool 28 | default: false 29 | 30 | - name: SkipFirstWebsiteDependency 31 | description: Set to true to skip the first website dependency 32 | type: bool 33 | default: false 34 | 35 | - name: SkipSecondWebsiteDependency 36 | description: Set to true to skip the second website dependency 37 | type: bool 38 | default: true 39 | 40 | dependencies: 41 | - name: docs 42 | template-url: ../docs 43 | output-folder: ./docs 44 | skip: "{{ .SkipAllDependencies }}" 45 | variables: 46 | - name: Title 47 | description: Enter the title of the docs page 48 | 49 | - name: website 50 | template-url: "{{ .WebsiteTemplateFolder }}" 51 | output-folder: "{{ .WebsiteOutputFolder }}" 52 | skip: "{{ or .SkipAllDependencies .SkipFirstWebsiteDependency }}" 53 | variables: 54 | - name: Title 55 | description: Enter the title of the website 56 | 57 | - name: skip-website 58 | template-url: "{{ .WebsiteTemplateFolder }}" 59 | output-folder: "{{ .WebsiteOutputFolder }}" 60 | skip: "{{ or .SkipAllDependencies .SkipSecondWebsiteDependency }}" 61 | variables: 62 | - name: Title 63 | description: Enter the title of the website 64 | default: This website dependency should be skipped 65 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/dependencies-for-each-reference-list-of-strings/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: accounts 3 | description: The AWS accounts 4 | type: map 5 | default: 6 | dev: 7 | email: dev@example.com 8 | id: 1111 9 | stage: 10 | email: stage@example.com 11 | id: 2222 12 | prod: 13 | email: prod@example.com 14 | id: 3333 15 | - name: accountNames 16 | description: The names of the accounts in the accounts variable 17 | type: list 18 | default: "{{ keysSorted .accounts }}" 19 | 20 | dependencies: 21 | - name: loop-dependency-example 22 | template-url: ../terraform 23 | # Render this dependency once for each environment the user specifies 24 | for_each_reference: accountNames 25 | # Render the dependency to an output folder that includes the environment name 26 | output-folder: "live/{{ .__each__ }}" 27 | variables: 28 | - name: ServerName 29 | description: The name to use for the EC2 instance (for its Name tag) 30 | type: string 31 | # Use the environment name in the server name 32 | default: "example-{{ .__each__ }}" -------------------------------------------------------------------------------- /examples/for-learning-and-testing/dependencies-for-each-reference/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: environments 3 | description: The environments to deploy into (e.g., dev, stage, prod) 4 | type: list 5 | default: 6 | - dev 7 | - stage 8 | - prod 9 | 10 | dependencies: 11 | - name: loop-dependency-example 12 | template-url: ../terraform 13 | # Render this dependency once for each environment the user specifies 14 | for_each_reference: environments 15 | # Render the dependency to an output folder that includes the environment name 16 | output-folder: "live/{{ .__each__ }}" 17 | variables: 18 | - name: ServerName 19 | description: The name to use for the EC2 instance (for its Name tag) 20 | type: string 21 | # Use the environment name in the server name 22 | default: "example-{{ .__each__ }}" -------------------------------------------------------------------------------- /examples/for-learning-and-testing/dependencies-for-each/boilerplate.yml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: loop-dependency-example 3 | template-url: ../terraform 4 | # Render this dependency once for each environment the user specifies 5 | for_each: 6 | - dev 7 | - stage 8 | - prod 9 | # Render the dependency to an output folder that includes the environment name 10 | output-folder: "live/{{ .__each__ }}" 11 | variables: 12 | - name: ServerName 13 | description: The name to use for the EC2 instance (for its Name tag) 14 | type: string 15 | # Use the environment name in the server name 16 | default: "example-{{ .__each__ }}" -------------------------------------------------------------------------------- /examples/for-learning-and-testing/dependencies-recursive/README.md: -------------------------------------------------------------------------------- 1 | # {{ .Title }} 2 | 3 | This is a boilerplate template that shows an example of using recursive dependencies. This template depends on the 4 | [dependencies](/examples/for-learning-and-testing/dependencies) example, which, in turn has its own dependencies. This 5 | template also defines all the variables needed for all dependencies to show how variable inheritance works. 6 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/dependencies-recursive/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: Description 3 | description: Enter the description of the recursive dependencies template 4 | 5 | - name: Version 6 | description: Enter the version number that will be used by the docs dependency 7 | 8 | - name: Title 9 | description: Enter the title for the dependencies recursive example 10 | 11 | - name: WelcomeText 12 | description: Enter the welcome text used by the website dependency 13 | 14 | - name: ShowLogo 15 | description: Should the webiste show the logo (true or false)? 16 | type: bool 17 | default: true 18 | 19 | dependencies: 20 | - name: dependencies 21 | template-url: ../dependencies 22 | output-folder: ./dependencies 23 | 24 | - name: java-project 25 | template-url: ../java-project 26 | output-folder: ./java-project 27 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/dependencies-remote/README.md: -------------------------------------------------------------------------------- 1 | # {{ .Title }} 2 | 3 | {{ .Description }}. It specifies both the 4 | [docs](/examples/for-learning-and-testing/docs) and [website](/examples/for-learning-and-testing/website) examples as 5 | dependencies to show how one boilerplate template can pull in another. It also defines all the variables needed for both 6 | of those dependencies at the top level to show how variable inheritance works. 7 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/dependencies-remote/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: Description 3 | description: Enter the description of this template 4 | 5 | - name: Version 6 | description: Enter the version number that will be used by the docs dependency 7 | 8 | - name: Title 9 | description: Enter the title for the dependencies example 10 | 11 | - name: WelcomeText 12 | description: Enter the welcome text used by the website dependency 13 | 14 | - name: ShowLogo 15 | description: Should the webiste show the logo (true or false)? 16 | type: bool 17 | default: true 18 | 19 | - name: RemoteBranch 20 | description: The branch of boilerplate repo to use when pulling down remote dependencies. 21 | default: "main" 22 | 23 | dependencies: 24 | - name: docs 25 | template-url: "git@github.com:gruntwork-io/boilerplate.git//examples/for-learning-and-testing/docs?ref={{ .RemoteBranch }}" 26 | output-folder: ./docs 27 | variables: 28 | - name: Title 29 | description: Enter the title of the docs page 30 | 31 | - name: website 32 | template-url: "git@github.com:gruntwork-io/boilerplate.git//examples/for-learning-and-testing/website?ref={{ .RemoteBranch }}" 33 | output-folder: ./website 34 | variables: 35 | - name: Title 36 | description: Enter the title of the website 37 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/dependencies-varfile-precedence/README.md: -------------------------------------------------------------------------------- 1 | # {{ .Title }} 2 | 3 | {{ .Description }}. It specifies both the 4 | [docs](/examples/for-learning-and-testing/docs) and [website](/examples/for-learning-and-testing/website) examples as 5 | dependencies to show how one boilerplate template can pull in another. It also defines all the variables needed for both 6 | of those dependencies at the top level to show how variable inheritance works. 7 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/dependencies-varfile-precedence/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: Description 3 | description: Enter the description of this template 4 | 5 | - name: Version 6 | description: Enter the version number that will be used by the docs dependency 7 | 8 | - name: Title 9 | description: Enter the title for the dependencies example 10 | 11 | - name: FileNameReference 12 | description: This variable will be used to create the name of a file dynamically 13 | default: reference name 14 | 15 | - name: ShowLogo 16 | description: Should the webiste show the logo (true or false)? 17 | type: bool 18 | default: true 19 | 20 | dependencies: 21 | - name: docs 22 | template-url: ../docs 23 | output-folder: ./docs 24 | var_files: 25 | - "{{ templateFolder }}/docs_vars_default_vars.yml" 26 | variables: 27 | - name: FileName 28 | reference: FileNameReference 29 | 30 | - name: website 31 | template-url: ../website 32 | output-folder: ./website 33 | var_files: 34 | - "{{ templateFolder }}/website_vars.yml" 35 | - "{{ templateFolder }}/website_vars_override_vars.yml" 36 | variables: 37 | - name: WelcomeText 38 | default: "Title from variable default" 39 | 40 | skip_files: 41 | - path: "*_vars.yml" 42 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/dependencies-varfile-precedence/docs_vars_default_vars.yml: -------------------------------------------------------------------------------- 1 | Title: "I am default vars for docs" 2 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/dependencies-varfile-precedence/website_vars.yml: -------------------------------------------------------------------------------- 1 | Title: "website vars!" 2 | WelcomeText: "Title from varfile" 3 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/dependencies-varfile-precedence/website_vars_override_vars.yml: -------------------------------------------------------------------------------- 1 | WelcomeText: "Title from varfile override" 2 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/dependencies-varfile/README.md: -------------------------------------------------------------------------------- 1 | # {{ .Title }} 2 | 3 | {{ .Description }}. It specifies both the 4 | [docs](/examples/for-learning-and-testing/docs) and [website](/examples/for-learning-and-testing/website) examples as 5 | dependencies to show how one boilerplate template can pull in another. It also defines all the variables needed for both 6 | of those dependencies at the top level to show how variable inheritance works. 7 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/dependencies-varfile/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: Description 3 | description: Enter the description of this template 4 | 5 | - name: Version 6 | description: Enter the version number that will be used by the docs dependency 7 | 8 | - name: Title 9 | description: Enter the title for the dependencies example 10 | default: Dependencies example 11 | 12 | - name: WelcomeText 13 | description: Enter the welcome text used by the website dependency 14 | 15 | - name: ShowLogo 16 | description: Should the webiste show the logo (true or false)? 17 | type: bool 18 | default: true 19 | 20 | dependencies: 21 | - name: docs 22 | template-url: ../docs 23 | output-folder: ./docs 24 | var_files: 25 | - "{{ templateFolder }}/docs_vars.yml" 26 | 27 | - name: website 28 | template-url: ../website 29 | output-folder: ./website 30 | var_files: 31 | - "{{ templateFolder }}/website_vars.yml" 32 | 33 | skip_files: 34 | - path: "*_vars.yml" 35 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/dependencies-varfile/docs_vars.yml: -------------------------------------------------------------------------------- 1 | Title: "I am vars for docs" 2 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/dependencies-varfile/website_vars.yml: -------------------------------------------------------------------------------- 1 | Title: "website vars!" 2 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/dependencies/README.md: -------------------------------------------------------------------------------- 1 | # {{ .Title }} 2 | 3 | {{ .Description }}. It specifies both the 4 | [docs](/examples/for-learning-and-testing/docs) and [website](/examples/for-learning-and-testing/website) examples as 5 | dependencies to show how one boilerplate template can pull in another. It also defines all the variables needed for both 6 | of those dependencies at the top level to show how variable inheritance works. 7 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/dependencies/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: Description 3 | description: Enter the description of this template 4 | 5 | - name: Version 6 | description: Enter the version number that will be used by the docs dependency 7 | 8 | - name: Title 9 | description: Enter the title for the dependencies example 10 | 11 | - name: WelcomeText 12 | description: Enter the welcome text used by the website dependency 13 | 14 | - name: ShowLogo 15 | description: Should the webiste show the logo (true or false)? 16 | type: bool 17 | default: true 18 | 19 | dependencies: 20 | - name: docs 21 | template-url: ../docs 22 | output-folder: ./docs 23 | variables: 24 | - name: Title 25 | description: Enter the title of the docs page 26 | 27 | - name: website 28 | template-url: ../website 29 | output-folder: ./website 30 | variables: 31 | - name: Title 32 | description: Enter the title of the website 33 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/docs/README.md: -------------------------------------------------------------------------------- 1 | # {{ .Title }} 2 | 3 | This shows an example of how to use boilerplate to fill in parts of your documentation. 4 | 5 | ## Variables 6 | 7 | Here is how you can use a variable: 8 | 9 | The latest version of my app is {{.Version}}. 10 | 11 | You could create a CI job that, for each release, regenerates your docs with the latest value of the `Version` variable 12 | passed in using the `--var` option. 13 | 14 | ## Snippets 15 | 16 | Here is how to use the `snippet` helper to embed files or parts of files from source code: 17 | 18 | ```html 19 | {{snippet "../website/index.html" | trim}} 20 | ``` 21 | 22 | ## Arithmetic 23 | 24 | Here is how you can use the arithmetic helpers to create a numbered list: 25 | 26 | {{ with $index := "0" -}} 27 | {{plus $index 1}}. Item 28 | {{plus $index 2}}. Item 29 | {{plus $index 3}}. Item 30 | {{- end }} 31 | 32 | And here is another way to do it using the slice helper: 33 | 34 | {{ range $i := (slice 1 4 1) -}} 35 | {{$i}}. Item 36 | {{ end -}} 37 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/docs/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: Title 3 | 4 | - name: Version 5 | 6 | - name: SubFolderName 7 | description: This variable will be used to create the name of a subfolder dynamically 8 | default: example folder 9 | 10 | - name: FileName 11 | description: This variable will be used to create the name of a file dynamically 12 | default: my example file 13 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/docs/interpolated-folder-{{.SubFolderName%7Cdasherize}}/{{.FileName%7csnakeCase}}.py: -------------------------------------------------------------------------------- 1 | # This file and its parent folder both show an example of using Go template syntax and boilerplate variables in their names -------------------------------------------------------------------------------- /examples/for-learning-and-testing/hooks-working-dir/boilerplate.yml: -------------------------------------------------------------------------------- 1 | hooks: 2 | after: 3 | # Replace the contents of test.txt as a check this hook ran in the proper working dir 4 | - command: bash 5 | args: 6 | - "-c" 7 | - "echo hook > test.txt" 8 | dir: "{{ outputFolder }}/subdir" 9 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/hooks-working-dir/subdir/test.txt: -------------------------------------------------------------------------------- 1 | # Intentionally empty -------------------------------------------------------------------------------- /examples/for-learning-and-testing/include/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: RandomVal 3 | description: Any random value that can be rendered as a unique string 4 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/include/target.txt: -------------------------------------------------------------------------------- 1 | {{ include "../../../test-fixtures/include-test/template.txt" . }} 2 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/java-project/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: CompanyName 3 | description: Enter the name of the company 4 | type: string 5 | 6 | - name: ExampleIntConstant 7 | description: Enter the value for an integer constant in the Java file 8 | type: int 9 | 10 | - name: IncludeEnum 11 | description: Should we create an example Enum in the Java file? 12 | type: bool 13 | 14 | - name: EnumNames 15 | description: Enter the names of the Enums in the Java file 16 | type: list 17 | 18 | - name: ExampleMap 19 | description: Enter some example values to store in a HashMap 20 | type: map 21 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/java-project/com/{{.CompanyName %7C dasherize %7C downcase}}/example/Example.java: -------------------------------------------------------------------------------- 1 | package com.{{.CompanyName | dasherize | downcase}}.example 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | 5 | public class Example { 6 | public static final int EXAMPLE_INT_CONSTANT = {{.ExampleIntConstant}} 7 | public static final Map<> EXAMPLE_MAP = ImmutableMap.of({{range $index, $key := .ExampleMap | keys}}{{if gt $index 0}}, {{end}}"{{$key}}", "{{index $.ExampleMap $key}}"{{end}}); 8 | 9 | {{- if .IncludeEnum}} 10 | 11 | public enum ExampleEnum { 12 | {{range $index, $enumName := .EnumNames -}} 13 | {{if gt $index 0}}, {{end}}{{$enumName}} 14 | {{- end }} 15 | } 16 | {{- end }} 17 | } -------------------------------------------------------------------------------- /examples/for-learning-and-testing/json/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: Foo 3 | type: string 4 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/json/example1.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "{{ .Foo }}" 3 | } 4 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/json/example2.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo: "{{ .Foo }}" 3 | } 4 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/jsonnet/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: Name 3 | type: string 4 | 5 | - name: IncludeAge 6 | type: bool 7 | 8 | - name: AgeMap 9 | type: map 10 | 11 | - name: FavoriteFoods 12 | type: list 13 | 14 | engines: 15 | - path: "*.jsonnet" 16 | template_engine: "jsonnet" 17 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/jsonnet/people.json: -------------------------------------------------------------------------------- 1 | { 2 | "people": [ 3 | { 4 | "name": "{{ .Name }}", 5 | {{- if .IncludeAge }} 6 | "age": {{ index .AgeMap .Name }}, 7 | {{- end }} 8 | "favoriteFoods": {{ .FavoriteFoods | toPrettyJson }} 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/jsonnet/people_jsonnet.json.jsonnet: -------------------------------------------------------------------------------- 1 | function(boilerplateVars) { 2 | local personAge = { 3 | age: boilerplateVars.AgeMap[boilerplateVars.Name], 4 | }, 5 | 6 | people: [ 7 | { 8 | name: boilerplateVars.Name, 9 | favoriteFoods: boilerplateVars.FavoriteFoods, 10 | } + ( 11 | if boilerplateVars.IncludeAge then personAge else {} 12 | ), 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/kebab-case-bug-unix/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: Name 3 | type: string 4 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/kebab-case-bug-unix/template.txt: -------------------------------------------------------------------------------- 1 | {{ .Name | kebabcase }} 2 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/order/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: CompanyName 3 | description: The name of your company 4 | order: 0 5 | - name: CountryCode 6 | order: 1 7 | description: The ISO3166 Alpha 2 code for the country you operate in 8 | - name: URL 9 | order: 2 10 | description: The URL to your website 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/order/template.txt: -------------------------------------------------------------------------------- 1 | "{{ .CompanyName }}" 2 | "{{ .CountryCode }}" 3 | "{{ .URL }}" 4 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/partials/boilerplate.yml: -------------------------------------------------------------------------------- 1 | partials: 2 | - ../../../test-fixtures/partials-test/*.txt 3 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/partials/target.txt: -------------------------------------------------------------------------------- 1 | {{- define "target" -}} 2 | This is the target. 3 | {{- end -}} 4 | {{- template "first_template" . }} 5 | {{ template "second_template" . -}} 6 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/regression-template-escape/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: SettingValue 3 | type: string 4 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/regression-template-escape/config.yml: -------------------------------------------------------------------------------- 1 | setting: 2 | name: "{{ .SettingValue }}" 3 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/shell-disabled/README.md: -------------------------------------------------------------------------------- 1 | This example is executed with shell helpers and hooks disabled, so neither the hooks or shell helpers should execute. 2 | 3 | {{ shell "./example-script.sh" "This should not execute and instead be replaced with a placeholder" }} -------------------------------------------------------------------------------- /examples/for-learning-and-testing/shell-disabled/boilerplate.yml: -------------------------------------------------------------------------------- 1 | hooks: 2 | before: 3 | - command: ./example-script.sh 4 | args: 5 | - "Hooks are disabled for this example, so this should NOT be written!" 6 | - "{{ outputFolder }}/before-hook-example.txt" 7 | 8 | after: 9 | - command: ./example-script.sh 10 | args: 11 | - "Hooks are disabled for this example, so this should NOT be written!" 12 | - "{{ outputFolder }}/after-hook-example.txt" 13 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/shell-disabled/example-script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # An example script that will be executed via the 'shell' command in a boilerplate template. This script simply writes 3 | # the text in the first argument into the path in the second argument. 4 | 5 | echo "$1" > "$2" -------------------------------------------------------------------------------- /examples/for-learning-and-testing/shell/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: Text 3 | description: Enter the text to display 4 | 5 | hooks: 6 | before: 7 | - command: echo 8 | args: 9 | - Running before hooks 10 | 11 | - command: ./example-script-2.sh 12 | args: 13 | - "{{ outputFolder }}/before-hook-example.txt" 14 | env: 15 | TEXT: "{{ .Text }} - executed via a before hook" 16 | 17 | - command: ./example-script-2.sh 18 | args: 19 | - "{{ outputFolder }}/before-hook-should-be-skipped.txt" 20 | env: 21 | TEXT: "this hook should be skipped" 22 | skip: "true" 23 | 24 | after: 25 | - command: echo 26 | args: 27 | - Running after hooks 28 | 29 | - command: ./example-script-2.sh 30 | args: 31 | - "{{ outputFolder }}/after-hook-example.txt" 32 | env: 33 | TEXT: "{{ .Text }} - executed via an after hook" 34 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/shell/example-script-2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # An example script that will be executed via the 'shell' command in a boilerplate template. This script simply writes 3 | # the environment variable TEXT into the path in the first argument. 4 | 5 | echo "$TEXT" > "$1" -------------------------------------------------------------------------------- /examples/for-learning-and-testing/shell/example-script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # An example script that will be executed via the 'shell' command in a boilerplate template. This script simply echoes 3 | # back the arguments you pass to it. 4 | 5 | echo "$@" -------------------------------------------------------------------------------- /examples/for-learning-and-testing/shell/hello-world.txt: -------------------------------------------------------------------------------- 1 | Example of executing an arbitrary shell command using the shell helper: 2 | 3 | {{ shell "./example-script.sh" .Text }} -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-files-glob/a/b/c/d.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/examples/for-learning-and-testing/skip-files-glob/a/b/c/d.yml -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-files-glob/a/b/c/foo.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/examples/for-learning-and-testing/skip-files-glob/a/b/c/foo.txt -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-files-glob/a/b/e.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/examples/for-learning-and-testing/skip-files-glob/a/b/e.yml -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-files-glob/boilerplate.yml: -------------------------------------------------------------------------------- 1 | skip_files: 2 | - path: a/**/*.yml 3 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-files-mixed/boilerplate.yml: -------------------------------------------------------------------------------- 1 | skip_files: 2 | - path: code.sh 3 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-files-mixed/code.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "This is some important code" 4 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-files-mixed/docs/README.md: -------------------------------------------------------------------------------- 1 | # This is some README 2 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-files-multiple/a.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/examples/for-learning-and-testing/skip-files-multiple/a.yml -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-files-multiple/b.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/examples/for-learning-and-testing/skip-files-multiple/b.yml -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-files-multiple/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: ExcludeA 3 | type: bool 4 | default: true 5 | 6 | - name: ExcludeB 7 | type: bool 8 | default: false 9 | 10 | skip_files: 11 | - path: a.yml 12 | if: "{{ .ExcludeA }}" 13 | - path: b.yml 14 | if: "{{ .ExcludeB }}" 15 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-files-nested/a/b/c/d.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/examples/for-learning-and-testing/skip-files-nested/a/b/c/d.yml -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-files-nested/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: ExcludeD 3 | type: bool 4 | default: true 5 | 6 | skip_files: 7 | - path: a/b/c/d.yml 8 | if: "{{ .ExcludeD }}" 9 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-not-path-mixed-noskip/a/foo.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/examples/for-learning-and-testing/skip-not-path-mixed-noskip/a/foo.yml -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-not-path-mixed-noskip/boilerplate.yml: -------------------------------------------------------------------------------- 1 | skip_files: 2 | - path: docs 3 | if: "{{ not .DocsOnly }}" 4 | - path: docs/**/* 5 | if: "{{ not .DocsOnly }}" 6 | - not_path: docs/**/* 7 | if: "{{ .DocsOnly }}" 8 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-not-path-mixed-noskip/docs/bar.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/examples/for-learning-and-testing/skip-not-path-mixed-noskip/docs/bar.txt -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-not-path-mixed-noskip/docs/foo.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/examples/for-learning-and-testing/skip-not-path-mixed-noskip/docs/foo.txt -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-not-path-mixed-skip/a/foo.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/examples/for-learning-and-testing/skip-not-path-mixed-skip/a/foo.yml -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-not-path-mixed-skip/boilerplate.yml: -------------------------------------------------------------------------------- 1 | skip_files: 2 | - path: docs 3 | if: "{{ not .DocsOnly }}" 4 | - path: docs/**/* 5 | if: "{{ not .DocsOnly }}" 6 | - not_path: docs/**/* 7 | if: "{{ .DocsOnly }}" 8 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-not-path-mixed-skip/docs/bar.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/examples/for-learning-and-testing/skip-not-path-mixed-skip/docs/bar.txt -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-not-path-mixed-skip/docs/foo.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/examples/for-learning-and-testing/skip-not-path-mixed-skip/docs/foo.txt -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-not-path-multiple/a/foo.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/examples/for-learning-and-testing/skip-not-path-multiple/a/foo.yml -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-not-path-multiple/boilerplate.yml: -------------------------------------------------------------------------------- 1 | skip_files: 2 | - not_path: docs/bar.txt 3 | - not_path: docs/foo.txt 4 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-not-path-multiple/docs/bar.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/examples/for-learning-and-testing/skip-not-path-multiple/docs/bar.txt -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-not-path-multiple/docs/foo.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/examples/for-learning-and-testing/skip-not-path-multiple/docs/foo.txt -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-not-path/a/foo.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/examples/for-learning-and-testing/skip-not-path/a/foo.yml -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-not-path/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: SkipNotPath 3 | default: "docs" 4 | 5 | skip_files: 6 | - not_path: "{{ .SkipNotPath }}/**" 7 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-not-path/docs/bar.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/examples/for-learning-and-testing/skip-not-path/docs/bar.txt -------------------------------------------------------------------------------- /examples/for-learning-and-testing/skip-not-path/docs/foo.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/examples/for-learning-and-testing/skip-not-path/docs/foo.txt -------------------------------------------------------------------------------- /examples/for-learning-and-testing/template-helpers/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: SomeGlobalVar 3 | type: string 4 | default: Inazagi 5 | 6 | dependencies: 7 | - name: docs 8 | template-url: ../docs 9 | output-folder: ./docs 10 | 11 | - name: website 12 | template-url: ../website 13 | output-folder: ./website 14 | 15 | skip_files: 16 | - path: skipped.txt 17 | if: '{{ list templateFolder "skipped.txt" | join "/" | pathExists }}' 18 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/template-helpers/sample.txt: -------------------------------------------------------------------------------- 1 | {{ .BoilerplateConfigDeps.docs.TemplateUrl }} 2 | {{ .BoilerplateConfigDeps.docs.OutputFolder }} 3 | {{ .BoilerplateConfigDeps.website.TemplateUrl }} 4 | {{ .BoilerplateConfigDeps.website.OutputFolder }} 5 | 6 | {{ .SomeGlobalVar }} 7 | {{ .BoilerplateConfigVars.SomeGlobalVar.Default }} 8 | 9 | {{ trimPrefix "hello-world" "hello" }} 10 | 11 | {{ relPath "/a/b/c" "/a/d" }} 12 | 13 | {{ .BoilerplateConfigVars.SomeGlobalVar.Default }} 14 | 15 | {{ true | ternary "foo" "bar" }} 16 | 17 | {{ $myList := list 1 2 3 4 5 -}} 18 | {{ listSlice $myList 1 3 }} 19 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/template-helpers/skipped.txt: -------------------------------------------------------------------------------- 1 | # This file should always be skipped 2 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/terraform/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: ServerName 3 | description: The name to use for the EC2 instance (for its Name tag) 4 | type: string 5 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/terraform/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | resource "aws_instance" "example" { 6 | ami = "ami-abcd1234" 7 | instance_type = "t3.micro" 8 | 9 | tags = { 10 | Name = "{{ .ServerName }}" 11 | } 12 | } -------------------------------------------------------------------------------- /examples/for-learning-and-testing/tofu-example/README.md: -------------------------------------------------------------------------------- 1 | # {{ .ModuleName | title }} example 2 | 3 | An example of how to use the [{{ .ModuleName | kebabcase }} module]({{ .ModuleSource }}). 4 | 5 | ## Quick start 6 | 7 | 1. Open `variables.tf` and fill in the values you want. 8 | 2. `tofu init`. 9 | 3. `tofu apply`. 10 | 4. When you're done testing: `tofu destroy`. -------------------------------------------------------------------------------- /examples/for-learning-and-testing/tofu-example/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: ModuleName 3 | description: The name of the module 4 | type: string 5 | 6 | - name: ModuleSource 7 | description: The source URL (or file path) to use for the module 8 | type: string 9 | 10 | - name: TofuVersion 11 | description: The version of OpenTOfu to use 12 | type: string 13 | default: 1.6.2 14 | 15 | hooks: 16 | after: 17 | # Format the code 18 | - command: tofu 19 | args: 20 | - fmt 21 | dir: "{{ outputFolder }}" -------------------------------------------------------------------------------- /examples/for-learning-and-testing/tofu-example/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "{{ .TofuVersion }}" 3 | } 4 | 5 | module "{{ .ModuleName | snakecase }}" { 6 | source = "{{ .ModuleSource }}" 7 | 8 | example_required_input = "Hello" 9 | example_optional_input = "World" 10 | } -------------------------------------------------------------------------------- /examples/for-learning-and-testing/tofu-example/outputs.tf: -------------------------------------------------------------------------------- 1 | output "example_output" { 2 | description = "example output" 3 | value = module.{{ .ModuleName | snakecase }}.example_output 4 | } -------------------------------------------------------------------------------- /examples/for-learning-and-testing/tofu-module-full/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: ModuleName 3 | description: The name of the module 4 | type: string 5 | 6 | - name: CopyrightInfo 7 | description: Copyright information to put in the README. Typically "Copyright ." 8 | type: string 9 | default: "" 10 | 11 | - name: TofuVersion 12 | description: The version of OpenTofu to use 13 | type: string 14 | default: 1.6.2 15 | 16 | dependencies: 17 | - name: module 18 | template-url: ../tofu-module 19 | output-folder: "modules/{{ .ModuleName | kebabcase }}" 20 | 21 | - name: example 22 | template-url: ../tofu-example 23 | output-folder: "examples/{{ .ModuleName | kebabcase }}" 24 | variables: 25 | - name: ModuleSource 26 | description: The source URL (or file path) to use for the module 27 | type: string 28 | default: "../../modules/{{ .ModuleName | kebabcase }}" 29 | 30 | - name: test 31 | template-url: ../tofu-test 32 | output-folder: "test" 33 | variables: 34 | - name: ExamplePath 35 | description: The source URL (or file path) to use for the module 36 | type: string 37 | default: "../examples/{{ .ModuleName | kebabcase }}" 38 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/tofu-module/README.md: -------------------------------------------------------------------------------- 1 | # {{ .ModuleName | title }} module 2 | 3 | TODO: fill in documentation for the {{ .ModuleName | kebabcase }} module. 4 | 5 | ## License 6 | 7 | {{ if .CopyrightInfo -}} 8 | {{ .CopyrightInfo }} 9 | 10 | {{ end -}} 11 | 12 | Please see [LICENSE.txt](LICENSE.txt) for details on how the code in this repo is licensed. -------------------------------------------------------------------------------- /examples/for-learning-and-testing/tofu-module/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: ModuleName 3 | description: The name of the module 4 | type: string 5 | 6 | - name: CopyrightInfo 7 | description: Copyright information to put in the README. Typically "Copyright ." 8 | type: string 9 | default: "" 10 | 11 | - name: TofuVersion 12 | description: The version of OpenTofu to use 13 | type: string 14 | default: 1.6.2 15 | 16 | hooks: 17 | after: 18 | # Format the code 19 | - command: tofu 20 | args: 21 | - fmt 22 | dir: "{{ outputFolder }}" -------------------------------------------------------------------------------- /examples/for-learning-and-testing/tofu-module/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "{{ .TofuVersion }}" 3 | } 4 | 5 | # --------------------------------------------------------------------------------------------------------------------- 6 | # TODO: DEFINE YOUR RESOURCES HERE 7 | # --------------------------------------------------------------------------------------------------------------------- 8 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/tofu-module/outputs.tf: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------------------------------------------------- 2 | # TODO: DEFINE YOUR OUTPUTS HERE 3 | # --------------------------------------------------------------------------------------------------------------------- 4 | 5 | output "example_output" { 6 | description = "example output" 7 | value = "${var.example_required_input} ${var.example_optional_input}" 8 | } -------------------------------------------------------------------------------- /examples/for-learning-and-testing/tofu-module/variables.tf: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------------------------------------------------- 2 | # REQUIRED VARIABLES 3 | # TODO: define your required variables here 4 | # --------------------------------------------------------------------------------------------------------------------- 5 | 6 | variable "example_required_input" { 7 | description = "Example required input variable" 8 | type = string 9 | } 10 | 11 | # --------------------------------------------------------------------------------------------------------------------- 12 | # OPTIONAL VARIABLES 13 | # TODO: define your optional variables here 14 | # --------------------------------------------------------------------------------------------------------------------- 15 | 16 | variable "example_optional_input" { 17 | description = "Example optional input variable" 18 | type = string 19 | default = "example-optional" 20 | } 21 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/tofu-test-unix/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: ModuleName 3 | description: The name of the module 4 | type: string 5 | 6 | - name: ExamplePath 7 | description: The folder path to to the example usage of the module to test 8 | type: string 9 | 10 | hooks: 11 | after: 12 | # Format the Go code 13 | - command: goimports 14 | args: 15 | - "-w" 16 | - "." 17 | dir: "{{ outputFolder }}" -------------------------------------------------------------------------------- /examples/for-learning-and-testing/tofu-test-unix/template_test.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | // +build ignore 3 | 4 | package test 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/gruntwork-io/terratest/modules/terraform" 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func Test{{ .ModuleName | camelcase }}(t *testing.T) { 14 | t.Parallel() 15 | 16 | opts := &terraform.Options{ 17 | TerraformDir: "{{ .ExamplePath }}", 18 | TerraformBinary: "tofu", 19 | } 20 | 21 | defer terraform.Destroy(t, opts) 22 | 23 | terraform.InitAndApply(t, opts) 24 | 25 | actualOutput := terraform.OutputRequired(t, opts, "example_output") 26 | assert.Equal(t, "Hello World", actualOutput) 27 | } -------------------------------------------------------------------------------- /examples/for-learning-and-testing/tofu-test/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: ModuleName 3 | description: The name of the module 4 | type: string 5 | 6 | - name: ExamplePath 7 | description: The folder path to to the example usage of the module to test 8 | type: string 9 | 10 | hooks: 11 | after: 12 | # Format the Go code 13 | - command: goimports 14 | args: 15 | - "-w" 16 | - "." 17 | dir: "{{ outputFolder }}" -------------------------------------------------------------------------------- /examples/for-learning-and-testing/tofu-test/vpc_test.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | // +build ignore 3 | 4 | package test 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/gruntwork-io/terratest/modules/terraform" 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func Test{{ .ModuleName | camelcase }}(t *testing.T) { 14 | t.Parallel() 15 | 16 | opts := &terraform.Options{ 17 | TerraformDir: "{{ .ExamplePath }}", 18 | TerraformBinary: "tofu", 19 | } 20 | 21 | defer terraform.Destroy(t, opts) 22 | 23 | terraform.InitAndApply(t, opts) 24 | 25 | actualOutput := terraform.OutputRequired(t, opts, "example_output") 26 | assert.Equal(t, "Hello World", actualOutput) 27 | } -------------------------------------------------------------------------------- /examples/for-learning-and-testing/validations/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: CompanyName 3 | description: The name of your company 4 | validations: 5 | - required 6 | - alphanumeric 7 | - length-5-20 8 | default: Gruntwork 9 | - name: CountryCode 10 | description: The ISO3166 Alpha 2 code for the country you operate in 11 | validations: 12 | - required 13 | - CountryCode2 14 | default: US 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/validations/template.txt: -------------------------------------------------------------------------------- 1 | "{{ .CompanyName }}" 2 | "{{ .CountryCode }}" 3 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/variables-recursive/README.md: -------------------------------------------------------------------------------- 1 | # Recursive variables 2 | 3 | This shows an example of variables that reference other variables. 4 | 5 | Foo = {{ .Foo }} 6 | Bar = {{ .Bar }} 7 | Baz = {{ .Baz }} 8 | 9 | FooList = {{ range $index, $element := .FooList }}{{ if gt $index 0 }}, {{ end }}{{ $element }}{{ end }} 10 | BarList = {{ range $index, $element := .BarList }}{{ if gt $index 0 }}, {{ end }}{{ $element }}{{ end }} 11 | FooMap = {{ range $index, $key := (.FooMap | keys) }}{{ if gt $index 0 }}, {{ end }}{{ $key }}: {{ index $.FooMap $key }}{{ end }} 12 | BarMap = {{ range $index, $key := (.BarMap | keys) }}{{ if gt $index 0 }}, {{ end }}{{ $key }}: {{ index $.BarMap $key }}{{ end }} 13 | 14 | ListWithTemplates = {{ range $index, $element := .ListWithTemplates }}{{ if gt $index 0 }}, {{ end }}{{ $element }}{{ end }} 15 | MapWithTemplates = {{ range $index, $key := (.MapWithTemplates | keys) }}{{ if gt $index 0 }}, {{ end }}{{ $key }}: {{ index $.MapWithTemplates $key }}{{ end }} 16 | ListWithNestedMap = {{ range $index, $item := .ListWithNestedMap }}{{ if gt $index 0 }}, {{ end }}(name: {{ $item.name }}, value: {{ $item.value }}){{ end }} 17 | MapWithNestedList = {{ range $index, $key := (.MapWithNestedList | keys) }}{{ if gt $index 0 }}, {{ end }}(key: {{ $key }}, value: {{ range $index2, $value := (index $.MapWithNestedList $key) }}{{ if gt $index2 0 }}, {{ end }}{{ $value }}{{ end }}){{ end }} 18 | 19 | IntValue: {{ .IntValue }} 20 | IntValueInterpolation: {{ .IntValueInterpolation }} 21 | FloatValue: {{ .FloatValue }} 22 | FloatValueInterpolation: {{ .FloatValueInterpolation }} 23 | BoolValue: {{ .BoolValue }} 24 | BoolValueInterpolationSimple: {{ .BoolValueInterpolationSimple }} 25 | BoolValueInterpolationSimpleComplex: {{ .BoolValueInterpolationSimpleComplex }} 26 | ListValue: {{ range $index, $element := .ListValue }}{{ if gt $index 0 }}, {{ end }}{{ $element }}{{ end }} 27 | ListValueInterpolation: {{ range $index, $element := .ListValueInterpolation }}{{ if gt $index 0 }}, {{ end }}{{ $element }}{{ end }} 28 | MapValue: {{ range $index, $key := (.MapValue | keys) }}{{ if gt $index 0 }}, {{ end }}{{ $key }}: {{ index $.MapValue $key }}{{ end }} 29 | MapValueInterpolation: {{ range $index, $key := (.MapValueInterpolation | keys) }}{{ if gt $index 0 }}, {{ end }}{{ $key }}: {{ index $.MapValueInterpolation $key }}{{ end }} 30 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/variables-recursive/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: Foo 3 | 4 | - name: Bar 5 | default: "{{ .Foo }}-bar" 6 | 7 | - name: Baz 8 | default: "{{ .Bar }}-baz" 9 | 10 | - name: FooList 11 | type: list 12 | default: 13 | - foo 14 | - bar 15 | - baz 16 | 17 | - name: BarList 18 | type: list 19 | reference: FooList 20 | 21 | - name: FooMap 22 | type: map 23 | default: 24 | foo: 1 25 | bar: 2 26 | baz: 3 27 | 28 | - name: BarMap 29 | type: map 30 | reference: FooMap 31 | 32 | - name: ListWithTemplates 33 | type: list 34 | default: 35 | - "{{ .Foo }}" 36 | - "{{ .Bar }}" 37 | - "{{ .Baz }}" 38 | 39 | - name: MapWithTemplates 40 | type: map 41 | default: 42 | "{{ .Foo }}": "{{ .Foo }}" 43 | "{{ .Bar }}": "{{ .Bar }}" 44 | "{{ .Baz }}": "{{ .Baz }}" 45 | 46 | - name: ListWithNestedMap 47 | type: list 48 | default: 49 | - name: foo 50 | value: foo 51 | 52 | - name: bar 53 | value: bar 54 | 55 | - name: MapWithNestedList 56 | type: map 57 | default: 58 | foo: [1, 2, 3] 59 | bar: [4, 5, 6] 60 | 61 | - name: IntValue 62 | type: int 63 | default: 42 64 | 65 | - name: IntValueInterpolation 66 | type: int 67 | default: "{{ .IntValue }}" 68 | 69 | - name: FloatValue 70 | type: float 71 | default: 3.14 72 | 73 | - name: FloatValueInterpolation 74 | type: float 75 | default: "{{ .FloatValue }}" 76 | 77 | - name: BoolValue 78 | type: bool 79 | default: true 80 | 81 | - name: BoolValueInterpolationSimple 82 | type: bool 83 | default: "{{ .BoolValue }}" 84 | 85 | - name: BoolValueInterpolationSimpleComplex 86 | type: bool 87 | default: "{{ eq .IntValue 42 }}" 88 | 89 | - name: ListValue 90 | type: list 91 | default: 92 | - 1 93 | - 2 94 | - 3 95 | 96 | - name: ListValueInterpolation 97 | type: list 98 | default: "{{ .ListValue }}" 99 | 100 | - name: MapValue 101 | type: map 102 | default: 103 | foo: 1 104 | bar: 2 105 | baz: 3 106 | 107 | - name: MapValueInterpolation 108 | type: map 109 | default: "{{ .MapValue }}" 110 | 111 | dependencies: 112 | - name: variables 113 | template-url: ../variables 114 | output-folder: . 115 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/variables/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: BazMap 3 | type: map 4 | reference: FooMap 5 | 6 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/variables/example.txt: -------------------------------------------------------------------------------- 1 | BazMap = {{ range $index, $key := (.BazMap | keys) }}{{ if gt $index 0 }}, {{ end }}{{ $key }}: {{ index $.BazMap $key }}{{ end }} -------------------------------------------------------------------------------- /examples/for-learning-and-testing/website/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: Title 3 | 4 | - name: WelcomeText 5 | description: Enter the welcome text for the website 6 | 7 | - name: ShowLogo 8 | description: Should the website show the logo? 9 | type: bool 10 | default: true 11 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/website/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{.Title}} 4 | 5 | 6 |

{{.WelcomeText}}

7 | {{if .ShowLogo}}{{end}} 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/for-learning-and-testing/website/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/examples/for-learning-and-testing/website/logo.png -------------------------------------------------------------------------------- /examples/for-production/terragrunt-architecture-catalog/blueprints/README.md: -------------------------------------------------------------------------------- 1 | # Blueprints 2 | 3 | This folder contains boilerplate blueprints as defined in the [Terminology 4 | section](/examples/for-production/terragrunt-architecture-catalog/README.md#terminology) of the root README. 5 | 6 | Each blueprint provides a standalone template that configures the entire `infrastructure-live` repository with all the 7 | necessary infrastructure components that are required to deploy it. For example, the `vpc-app` blueprint not only 8 | includes the templates for setting up the App VPC in the specific account, but it also sets up the envcommon folder with 9 | the common configurations for any App VPC. 10 | 11 | Note that some of the blueprints may call other blueprints to setup what the dependencies. For example, the `postgres` 12 | blueprint will call the `vpc-app` blueprint to ensure an App VPC exists in the architecture to house the RDS database. 13 | 14 | This allows you to compose the blueprints together into a full scale customized architecture, as is done in the 15 | `reference-architecture` blueprint: 16 | 17 | - The `reference-architecture` blueprint sets up the folder structure of an `infrastructure-live` repository. 18 | - It then uses the `reference-architecture-app-account` blueprint to set up three copies of the infrastructure in a 19 | `dev`, `stage`, and `prod` account. 20 | - The `reference-architecture-app-account` blueprint in turn calls the `vpc-app`, `postgres`, and `redis` blueprints to 21 | setup those components within the scope of a single account. 22 | -------------------------------------------------------------------------------- /examples/for-production/terragrunt-architecture-catalog/blueprints/redis/boilerplate.yml: -------------------------------------------------------------------------------- 1 | # This blueprint creates the terragrunt modules necessary to deploy Redis into a single region in a single account. 2 | 3 | variables: 4 | - name: AWSAccountName 5 | description: The name of the AWS account. 6 | 7 | - name: AWSRegion 8 | description: The name of the AWS region. 9 | 10 | # Optional variables 11 | - name: IncludeVPCApp 12 | type: bool 13 | description: Whether or not to render the vpc template as a dependency. 14 | default: true 15 | 16 | # The following are convenience variables for DRY-ing up the dependencies. These are not intended to be 17 | # updated/provided by users. We follow the Go convention of camelCase instead of TitleCase. 18 | - name: accountOutputFolder 19 | description: "The output folder that denotes the account in the infrastructure-live folder structure." 20 | default: "{{ outputFolder }}/{{ .AWSAccountName }}/" 21 | - name: accountRegionOutputFolder 22 | description: "The output folder that denotes the region in the infrastructure-live folder structure." 23 | default: "{{ .accountOutputFolder }}/{{ .AWSRegion }}/" 24 | 25 | dependencies: 26 | - name: redis 27 | template-url: "{{ templateFolder }}/../../templates/services/data-stores/redis" 28 | output-folder: "{{ .accountRegionOutputFolder }}/data-stores/redis" 29 | variables: 30 | - name: IsEnvCommon 31 | type: bool 32 | default: false 33 | # Use special override settings when deploying the cache in the prod account. 34 | - name: RedisInstanceType 35 | default: "{{ if eq .AWSAccountName \"prod\" }}cache.t3.medium{{ else }}cache.t3.micro{{ end }}" 36 | - name: RedisReplicationGroupSize 37 | default: "{{ if eq .AWSAccountName \"prod\" }}2{{ else }}1{{ end }}" 38 | 39 | - name: redis-envcommon 40 | template-url: "{{ templateFolder }}/../../templates/services/data-stores/redis" 41 | output-folder: "{{ outputFolder }}/_envcommon/data-stores" 42 | variables: 43 | - name: IsEnvCommon 44 | type: bool 45 | default: true 46 | 47 | # The following are additional blueprints to include. We use blueprints instead of templates for these dependencies so 48 | # that we can include everything necessary for each component. 49 | - name: vpc-app 50 | template-url: "{{ templateFolder }}/../vpc-app" 51 | output-folder: "{{ outputFolder }}" 52 | skip: "{{ not .IncludeVPCApp }}" 53 | 54 | 55 | hooks: 56 | after: 57 | # Format the rendered HCL files 58 | - command: terragrunt 59 | args: 60 | - "hclfmt" 61 | - "--terragrunt-working-dir" 62 | - "{{ outputFolder }}" 63 | -------------------------------------------------------------------------------- /examples/for-production/terragrunt-architecture-catalog/blueprints/reference-architecture-app-account/boilerplate.yml: -------------------------------------------------------------------------------- 1 | # This blueprint creates an account tree in the infrastructure-live repo for a single app account that 2 | # has a single App VPC with an Elasticache Redis Cluster and an RDS Postgres Database. 3 | 4 | variables: 5 | - name: AWSAccountName 6 | description: The name of the AWS Account being deployed to. 7 | 8 | - name: AWSAccountID 9 | description: The ID of the AWS Account being deployed to. 10 | 11 | - name: AWSRegion 12 | description: The name of the AWS Region being deployed to. 13 | 14 | # The following are convenience variables for DRY-ing up the dependencies. These are not intended to be 15 | # updated/provided by users. We follow the Go convention of camelCase instead of TitleCase. 16 | - name: accountOutputFolder 17 | description: "The output folder that denotes the account in the infrastructure-live folder structure." 18 | default: "{{ outputFolder }}/{{ .AWSAccountName }}/" 19 | - name: accountRegionOutputFolder 20 | description: "The output folder that denotes the region in the infrastructure-live folder structure." 21 | default: "{{ .accountOutputFolder }}/{{ .AWSRegion }}/" 22 | 23 | dependencies: 24 | - name: account-root 25 | template-url: "{{ templateFolder }}/../../templates/_root/account" 26 | output-folder: "{{ .accountOutputFolder }}" 27 | 28 | - name: region-root 29 | template-url: "{{ templateFolder }}/../../templates/_root/region" 30 | output-folder: "{{ .accountRegionOutputFolder }}" 31 | 32 | - name: redis-blueprint 33 | template-url: "{{ templateFolder }}/../redis" 34 | output-folder: "{{ outputFolder }}" 35 | 36 | - name: postgres-blueprint 37 | template-url: "{{ templateFolder }}/../postgres" 38 | output-folder: "{{ outputFolder }}" 39 | -------------------------------------------------------------------------------- /examples/for-production/terragrunt-architecture-catalog/blueprints/reference-architecture/boilerplate.yml: -------------------------------------------------------------------------------- 1 | # This blueprint creates a sample infrastructure-live repo containing three accounts (dev, stage, and prod) that each 2 | # have a single App VPC with an Elasticache Redis Cluster and an RDS Postgres Database. 3 | 4 | variables: 5 | - name: ResourceNamePrefix 6 | description: A name to prefix to resources in this configuration 7 | 8 | - name: DevAWSAccountID 9 | description: The AWS Account ID of the dev account. 10 | 11 | - name: StageAWSAccountID 12 | description: The AWS Account ID of the stage account. 13 | 14 | - name: ProdAWSAccountID 15 | description: The AWS Account ID of the prod account. 16 | 17 | # Optional variables 18 | - name: AWSRegion 19 | description: The name of the AWS Region to use for each of the accounts. 20 | default: "us-east-2" 21 | 22 | - name: DevAppVPCCIDRBlock 23 | description: Enter the CIDR block should we use for the app VPC in the dev account (e.g. 172.31.80.0/20). 24 | default: 10.0.0.0/16 25 | 26 | - name: StageAppVPCCIDRBlock 27 | description: Enter the CIDR block should we use for the app VPC in the stage account (e.g. 172.31.80.0/20). 28 | default: 10.2.0.0/16 29 | 30 | - name: ProdAppVPCCIDRBlock 31 | description: Enter the CIDR block should we use for the app VPC in the prod account (e.g. 172.31.80.0/20). 32 | default: 10.3.0.0/16 33 | 34 | 35 | dependencies: 36 | - name: infrastructure-live-root 37 | template-url: "{{ templateFolder }}/../../templates/_root/infrastructure-live" 38 | output-folder: "{{ outputFolder }}" 39 | variables: 40 | - name: AWSAccounts 41 | type: map 42 | default: 43 | dev: "{{ .DevAWSAccountID }}" 44 | stage: "{{ .StageAWSAccountID }}" 45 | prod: "{{ .ProdAWSAccountID }}" 46 | 47 | - name: envcommon-root 48 | template-url: "{{ templateFolder }}/../../templates/_root/_envcommon" 49 | output-folder: "{{ outputFolder }}/_envcommon" 50 | 51 | - name: dev-blueprint 52 | template-url: "{{ templateFolder }}/../reference-architecture-app-account" 53 | output-folder: "{{ outputFolder }}" 54 | variables: 55 | - name: AWSAccountName 56 | default: "dev" 57 | - name: AWSAccountID 58 | default: "{{ .DevAWSAccountID }}" 59 | - name: AppVPCCIDRBlock 60 | default: "{{ .DevAppVPCCIDRBlock }}" 61 | 62 | - name: stage-blueprint 63 | template-url: "{{ templateFolder }}/../reference-architecture-app-account" 64 | output-folder: "{{ outputFolder }}" 65 | variables: 66 | - name: AWSAccountName 67 | default: "stage" 68 | - name: AWSAccountID 69 | default: "{{ .StageAWSAccountID }}" 70 | - name: AppVPCCIDRBlock 71 | default: "{{ .StageAppVPCCIDRBlock }}" 72 | 73 | - name: prod-blueprint 74 | template-url: "{{ templateFolder }}/../reference-architecture-app-account" 75 | output-folder: "{{ outputFolder }}" 76 | variables: 77 | - name: AWSAccountName 78 | default: "prod" 79 | - name: AWSAccountID 80 | default: "{{ .ProdAWSAccountID }}" 81 | - name: AppVPCCIDRBlock 82 | default: "{{ .ProdAppVPCCIDRBlock }}" 83 | -------------------------------------------------------------------------------- /examples/for-production/terragrunt-architecture-catalog/blueprints/vpc-app/boilerplate.yml: -------------------------------------------------------------------------------- 1 | # This blueprint creates the terragrunt modules necessary to deploy an App VPC into a single region in a single account. 2 | 3 | variables: 4 | - name: AWSAccountName 5 | description: The name of the AWS account. 6 | 7 | - name: AWSRegion 8 | description: The name of the AWS region. 9 | 10 | # The following are convenience variables for DRY-ing up the dependencies. These are not intended to be 11 | # updated/provided by users. We follow the Go convention of camelCase instead of TitleCase. 12 | - name: accountOutputFolder 13 | description: "The output folder that denotes the account in the infrastructure-live folder structure." 14 | default: "{{ outputFolder }}/{{ .AWSAccountName }}//" 15 | - name: accountRegionOutputFolder 16 | description: "The output folder that denotes the region in the infrastructure-live folder structure." 17 | default: "{{ .accountOutputFolder }}/{{ .AWSRegion }}/" 18 | 19 | 20 | dependencies: 21 | - name: vpc-app 22 | template-url: "{{ templateFolder }}/../../templates/services/networking/vpc" 23 | output-folder: "{{ .accountRegionOutputFolder }}/networking/vpc" 24 | variables: 25 | - name: IsEnvCommon 26 | type: bool 27 | default: false 28 | 29 | - name: vpc-app-envcommon 30 | template-url: "{{ templateFolder }}/../../templates/services/networking/vpc" 31 | output-folder: "{{ outputFolder }}/_envcommon/networking" 32 | variables: 33 | - name: IsEnvCommon 34 | type: bool 35 | default: true 36 | 37 | hooks: 38 | after: 39 | # Format the rendered HCL files 40 | - command: terragrunt 41 | args: 42 | - "hclfmt" 43 | - "--terragrunt-working-dir" 44 | - "{{ outputFolder }}" 45 | -------------------------------------------------------------------------------- /examples/for-production/terragrunt-architecture-catalog/sample_reference_architecture_vars.yml: -------------------------------------------------------------------------------- 1 | ResourceNamePrefix: gruntwork 2 | DevAWSAccountID: "1111111111111" 3 | StageAWSAccountID: "2222222222222" 4 | ProdAWSAccountID: "3333333333333" 5 | DBSecretsManagerArn: SomeArn 6 | -------------------------------------------------------------------------------- /examples/for-production/terragrunt-architecture-catalog/templates/_root/_envcommon/README.md: -------------------------------------------------------------------------------- 1 | # Common configurations for service components 2 | 3 | This directory holds common configurations for each component that is shared across the environments. Each file 4 | will be included and merged into the live configuration for the service component in each environment. 5 | 6 | Refer to [the Terragrunt 7 | documentation](https://terragrunt.gruntwork.io/docs/features/keep-your-terragrunt-architecture-dry/) for more details. 8 | -------------------------------------------------------------------------------- /examples/for-production/terragrunt-architecture-catalog/templates/_root/_envcommon/boilerplate.yml: -------------------------------------------------------------------------------- 1 | # This template sets up the root directory of _envcommon. This file is intentionally blank as boilerplate requires a 2 | # boilerplate.yml file to recognize templates. 3 | -------------------------------------------------------------------------------- /examples/for-production/terragrunt-architecture-catalog/templates/_root/account/account.hcl: -------------------------------------------------------------------------------- 1 | # Set account-wide variables 2 | locals { 3 | account_name = "{{ .AWSAccountName }}" 4 | account_id = "{{ .AWSAccountID }}" 5 | } 6 | -------------------------------------------------------------------------------- /examples/for-production/terragrunt-architecture-catalog/templates/_root/account/boilerplate.yml: -------------------------------------------------------------------------------- 1 | # This template sets up the root directory of an account. 2 | 3 | variables: 4 | # Required variables 5 | - name: AWSAccountName 6 | description: The name of the AWS Account being deployed to. 7 | 8 | - name: AWSAccountID 9 | description: The ID of the AWS Account being deployed to. 10 | -------------------------------------------------------------------------------- /examples/for-production/terragrunt-architecture-catalog/templates/_root/infrastructure-live/.terraform-version: -------------------------------------------------------------------------------- 1 | {{ .TerraformVersion }} 2 | -------------------------------------------------------------------------------- /examples/for-production/terragrunt-architecture-catalog/templates/_root/infrastructure-live/.tgswitchrc: -------------------------------------------------------------------------------- 1 | {{ .TerragruntVersion }} 2 | -------------------------------------------------------------------------------- /examples/for-production/terragrunt-architecture-catalog/templates/_root/infrastructure-live/accounts.json: -------------------------------------------------------------------------------- 1 | {{ .AWSAccounts | toPrettyJson }} 2 | -------------------------------------------------------------------------------- /examples/for-production/terragrunt-architecture-catalog/templates/_root/infrastructure-live/boilerplate.yml: -------------------------------------------------------------------------------- 1 | # This template sets up the root directory of an infrastructure-live repository. 2 | 3 | variables: 4 | # Required variables 5 | - name: ResourceNamePrefix 6 | description: A name to prefix to resources in this configuration 7 | 8 | - name: AWSAccounts 9 | description: A map of AWS account names to the account ID. 10 | type: map 11 | 12 | # Optional variables 13 | - name: SkipRemoteState 14 | description: Whether or not to skip the remote_state block. Primarily used for testing purposes. 15 | type: bool 16 | default: false 17 | 18 | - name: AccountsJSONFileName 19 | description: Name of the json file that will contain the map of account names to IDs. 20 | default: "accounts.json" 21 | 22 | - name: AWSDefaultRegion 23 | description: The default region to use when not operating on a specific region. 24 | default: us-east-1 25 | 26 | - name: TerraformVersion 27 | description: Used by the mise tool to automatically select which version of Terraform to use. 28 | default: 1.0.11 29 | 30 | - name: TerragruntVersion 31 | description: Used by the mise tool to automatically select which version of Terragrunt to use. 32 | default: v0.36.1 33 | 34 | 35 | hooks: 36 | after: 37 | # Format the rendered HCL files 38 | - command: terragrunt 39 | args: 40 | - "hclfmt" 41 | - "--terragrunt-working-dir" 42 | - "{{ outputFolder }}" 43 | -------------------------------------------------------------------------------- /examples/for-production/terragrunt-architecture-catalog/templates/_root/infrastructure-live/common.hcl: -------------------------------------------------------------------------------- 1 | # Common variables for all AWS accounts. 2 | locals { 3 | # ---------------------------------------------------------------------------------------------------------------- 4 | # ACCOUNT IDS AND CONVENIENCE LOCALS 5 | # ---------------------------------------------------------------------------------------------------------------- 6 | 7 | # Centrally define all the AWS account IDs. We use JSON so that it can be readily parsed outside of Terraform. 8 | account_ids = jsondecode(file("{{ .AccountsJSONFileName }}")) 9 | 10 | # Define a default region to use when operating on resources that are not contained within a specific region. 11 | default_region = "{{ .AWSDefaultRegion }}" 12 | 13 | # A prefix used for naming resources. 14 | name_prefix = "{{ .ResourceNamePrefix }}" 15 | } 16 | -------------------------------------------------------------------------------- /examples/for-production/terragrunt-architecture-catalog/templates/_root/infrastructure-live/terragrunt.hcl: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------------------------------------------------- 2 | # ROOT TERRAGRUNT CONFIGURATION 3 | # This configuration sets up project live configurations that are common to all terragrunt modules within this 4 | # repository. 5 | # --------------------------------------------------------------------------------------------------------------------- 6 | 7 | locals { 8 | # Automatically load common variables 9 | common_vars = read_terragrunt_config(find_in_parent_folders("common.hcl")) 10 | 11 | # Automatically load account-level variables 12 | account_vars = read_terragrunt_config(find_in_parent_folders("account.hcl")) 13 | 14 | # Automatically load region-level variables 15 | region_vars = read_terragrunt_config(find_in_parent_folders("region.hcl")) 16 | 17 | # Extract the variables we need for easy access 18 | name_prefix = local.common_vars.locals.name_prefix 19 | account_name = local.account_vars.locals.account_name 20 | account_id = local.account_vars.locals.account_id 21 | aws_region = local.region_vars.locals.aws_region 22 | } 23 | 24 | # Generate an AWS provider block 25 | generate "provider" { 26 | path = "provider.tf" 27 | if_exists = "overwrite_terragrunt" 28 | contents = < 20 | 21 | {{.Title}} 22 | 23 | 24 |

{{.WelcomeText}}

25 | {{if .ShowLogo}}{{end}} 26 | 27 | 28 | ``` 29 | 30 | ## Arithmetic 31 | 32 | Here is how you can use the arithmetic helpers to create a numbered list: 33 | 34 | 1. Item 35 | 2. Item 36 | 3. Item 37 | 38 | And here is another way to do it using the slice helper: 39 | 40 | 1. Item 41 | 2. Item 42 | 3. Item 43 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-dynamic/docs/interpolated-folder-example-folder/my_example_file.py: -------------------------------------------------------------------------------- 1 | # This file and its parent folder both show an example of using Go template syntax and boilerplate variables in their names -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-dynamic/website/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Boilerplate 4 | 5 | 6 |

Welcome!

7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-dynamic/website/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-expected-output/dependencies-dynamic/website/logo.png -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-for-each-reference-list-of-strings/live/dev/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | resource "aws_instance" "example" { 6 | ami = "ami-abcd1234" 7 | instance_type = "t3.micro" 8 | 9 | tags = { 10 | Name = "example-dev" 11 | } 12 | } -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-for-each-reference-list-of-strings/live/prod/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | resource "aws_instance" "example" { 6 | ami = "ami-abcd1234" 7 | instance_type = "t3.micro" 8 | 9 | tags = { 10 | Name = "example-prod" 11 | } 12 | } -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-for-each-reference-list-of-strings/live/stage/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | resource "aws_instance" "example" { 6 | ami = "ami-abcd1234" 7 | instance_type = "t3.micro" 8 | 9 | tags = { 10 | Name = "example-stage" 11 | } 12 | } -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-for-each-reference/live/dev/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | resource "aws_instance" "example" { 6 | ami = "ami-abcd1234" 7 | instance_type = "t3.micro" 8 | 9 | tags = { 10 | Name = "example-dev" 11 | } 12 | } -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-for-each-reference/live/prod/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | resource "aws_instance" "example" { 6 | ami = "ami-abcd1234" 7 | instance_type = "t3.micro" 8 | 9 | tags = { 10 | Name = "example-prod" 11 | } 12 | } -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-for-each-reference/live/stage/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | resource "aws_instance" "example" { 6 | ami = "ami-abcd1234" 7 | instance_type = "t3.micro" 8 | 9 | tags = { 10 | Name = "example-stage" 11 | } 12 | } -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-for-each/live/dev/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | resource "aws_instance" "example" { 6 | ami = "ami-abcd1234" 7 | instance_type = "t3.micro" 8 | 9 | tags = { 10 | Name = "example-dev" 11 | } 12 | } -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-for-each/live/prod/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | resource "aws_instance" "example" { 6 | ami = "ami-abcd1234" 7 | instance_type = "t3.micro" 8 | 9 | tags = { 10 | Name = "example-prod" 11 | } 12 | } -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-for-each/live/stage/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | resource "aws_instance" "example" { 6 | ami = "ami-abcd1234" 7 | instance_type = "t3.micro" 8 | 9 | tags = { 10 | Name = "example-stage" 11 | } 12 | } -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-recursive/README.md: -------------------------------------------------------------------------------- 1 | # Recursive dependencies example 2 | 3 | This is a boilerplate template that shows an example of using recursive dependencies. This template depends on the 4 | [dependencies](/examples/for-learning-and-testing/dependencies) example, which, in turn has its own dependencies. This 5 | template also defines all the variables needed for all dependencies to show how variable inheritance works. 6 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-recursive/dependencies/README.md: -------------------------------------------------------------------------------- 1 | # Dependencies example 2 | 3 | This is a boilerplate template that shows an example of using dependencies. It specifies both the 4 | [docs](/examples/for-learning-and-testing/docs) and [website](/examples/for-learning-and-testing/website) examples as 5 | dependencies to show how one boilerplate template can pull in another. It also defines all the variables needed for both 6 | of those dependencies at the top level to show how variable inheritance works. 7 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-recursive/dependencies/docs/README.md: -------------------------------------------------------------------------------- 1 | # Docs example 2 | 3 | This shows an example of how to use boilerplate to fill in parts of your documentation. 4 | 5 | ## Variables 6 | 7 | Here is how you can use a variable: 8 | 9 | The latest version of my app is 0.0.3. 10 | 11 | You could create a CI job that, for each release, regenerates your docs with the latest value of the `Version` variable 12 | passed in using the `--var` option. 13 | 14 | ## Snippets 15 | 16 | Here is how to use the `snippet` helper to embed files or parts of files from source code: 17 | 18 | ```html 19 | 20 | 21 | {{.Title}} 22 | 23 | 24 |

{{.WelcomeText}}

25 | {{if .ShowLogo}}{{end}} 26 | 27 | 28 | ``` 29 | 30 | ## Arithmetic 31 | 32 | Here is how you can use the arithmetic helpers to create a numbered list: 33 | 34 | 1. Item 35 | 2. Item 36 | 3. Item 37 | 38 | And here is another way to do it using the slice helper: 39 | 40 | 1. Item 41 | 2. Item 42 | 3. Item 43 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-recursive/dependencies/docs/interpolated-folder-example-folder/my_example_file.py: -------------------------------------------------------------------------------- 1 | # This file and its parent folder both show an example of using Go template syntax and boilerplate variables in their names -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-recursive/dependencies/website/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Boilerplate 4 | 5 | 6 |

Welcome!

7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-recursive/dependencies/website/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-expected-output/dependencies-recursive/dependencies/website/logo.png -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-recursive/java-project/com/acme/example/Example.java: -------------------------------------------------------------------------------- 1 | package com.acme.example 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | 5 | public class Example { 6 | public static final int EXAMPLE_INT_CONSTANT = 42 7 | public static final Map<> EXAMPLE_MAP = ImmutableMap.of("key1", "value1", "key2", "value2", "key3", "value3"); 8 | 9 | public enum ExampleEnum { 10 | Foo, Bar, Baz 11 | } 12 | } -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-remote/README.md: -------------------------------------------------------------------------------- 1 | # Dependencies example 2 | 3 | This is a boilerplate template that shows an example of using dependencies. It specifies both the 4 | [docs](/examples/for-learning-and-testing/docs) and [website](/examples/for-learning-and-testing/website) examples as 5 | dependencies to show how one boilerplate template can pull in another. It also defines all the variables needed for both 6 | of those dependencies at the top level to show how variable inheritance works. 7 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-remote/docs/README.md: -------------------------------------------------------------------------------- 1 | # Docs example 2 | 3 | This shows an example of how to use boilerplate to fill in parts of your documentation. 4 | 5 | ## Variables 6 | 7 | Here is how you can use a variable: 8 | 9 | The latest version of my app is 0.0.3. 10 | 11 | You could create a CI job that, for each release, regenerates your docs with the latest value of the `Version` variable 12 | passed in using the `--var` option. 13 | 14 | ## Snippets 15 | 16 | Here is how to use the `snippet` helper to embed files or parts of files from source code: 17 | 18 | ```html 19 | 20 | 21 | {{.Title}} 22 | 23 | 24 |

{{.WelcomeText}}

25 | {{if .ShowLogo}}{{end}} 26 | 27 | 28 | ``` 29 | 30 | ## Arithmetic 31 | 32 | Here is how you can use the arithmetic helpers to create a numbered list: 33 | 34 | 1. Item 35 | 2. Item 36 | 3. Item 37 | 38 | And here is another way to do it using the slice helper: 39 | 40 | 1. Item 41 | 2. Item 42 | 3. Item 43 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-remote/docs/interpolated-folder-example-folder/my_example_file.py: -------------------------------------------------------------------------------- 1 | # This file and its parent folder both show an example of using Go template syntax and boilerplate variables in their names -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-remote/website/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Boilerplate 4 | 5 | 6 |

Welcome!

7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-remote/website/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-expected-output/dependencies-remote/website/logo.png -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-varfile-precedence/README.md: -------------------------------------------------------------------------------- 1 | # Dependencies example 2 | 3 | This is a boilerplate template that shows an example of using dependencies. It specifies both the 4 | [docs](/examples/for-learning-and-testing/docs) and [website](/examples/for-learning-and-testing/website) examples as 5 | dependencies to show how one boilerplate template can pull in another. It also defines all the variables needed for both 6 | of those dependencies at the top level to show how variable inheritance works. 7 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-varfile-precedence/docs/README.md: -------------------------------------------------------------------------------- 1 | # Dependencies example 2 | 3 | This shows an example of how to use boilerplate to fill in parts of your documentation. 4 | 5 | ## Variables 6 | 7 | Here is how you can use a variable: 8 | 9 | The latest version of my app is 0.0.3. 10 | 11 | You could create a CI job that, for each release, regenerates your docs with the latest value of the `Version` variable 12 | passed in using the `--var` option. 13 | 14 | ## Snippets 15 | 16 | Here is how to use the `snippet` helper to embed files or parts of files from source code: 17 | 18 | ```html 19 | 20 | 21 | {{.Title}} 22 | 23 | 24 |

{{.WelcomeText}}

25 | {{if .ShowLogo}}{{end}} 26 | 27 | 28 | ``` 29 | 30 | ## Arithmetic 31 | 32 | Here is how you can use the arithmetic helpers to create a numbered list: 33 | 34 | 1. Item 35 | 2. Item 36 | 3. Item 37 | 38 | And here is another way to do it using the slice helper: 39 | 40 | 1. Item 41 | 2. Item 42 | 3. Item 43 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-varfile-precedence/docs/interpolated-folder-example-folder/reference_name.py: -------------------------------------------------------------------------------- 1 | # This file and its parent folder both show an example of using Go template syntax and boilerplate variables in their names -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-varfile-precedence/website/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Boilerplate 4 | 5 | 6 |

Title from varfile override

7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-varfile-precedence/website/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-expected-output/dependencies-varfile-precedence/website/logo.png -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-varfile/README.md: -------------------------------------------------------------------------------- 1 | # Dependencies example 2 | 3 | This is a boilerplate template that shows an example of using dependencies. It specifies both the 4 | [docs](/examples/for-learning-and-testing/docs) and [website](/examples/for-learning-and-testing/website) examples as 5 | dependencies to show how one boilerplate template can pull in another. It also defines all the variables needed for both 6 | of those dependencies at the top level to show how variable inheritance works. 7 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-varfile/docs/README.md: -------------------------------------------------------------------------------- 1 | # I am vars for docs 2 | 3 | This shows an example of how to use boilerplate to fill in parts of your documentation. 4 | 5 | ## Variables 6 | 7 | Here is how you can use a variable: 8 | 9 | The latest version of my app is 0.0.3. 10 | 11 | You could create a CI job that, for each release, regenerates your docs with the latest value of the `Version` variable 12 | passed in using the `--var` option. 13 | 14 | ## Snippets 15 | 16 | Here is how to use the `snippet` helper to embed files or parts of files from source code: 17 | 18 | ```html 19 | 20 | 21 | {{.Title}} 22 | 23 | 24 |

{{.WelcomeText}}

25 | {{if .ShowLogo}}{{end}} 26 | 27 | 28 | ``` 29 | 30 | ## Arithmetic 31 | 32 | Here is how you can use the arithmetic helpers to create a numbered list: 33 | 34 | 1. Item 35 | 2. Item 36 | 3. Item 37 | 38 | And here is another way to do it using the slice helper: 39 | 40 | 1. Item 41 | 2. Item 42 | 3. Item 43 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-varfile/docs/interpolated-folder-example-folder/my_example_file.py: -------------------------------------------------------------------------------- 1 | # This file and its parent folder both show an example of using Go template syntax and boilerplate variables in their names -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-varfile/website/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | website vars! 4 | 5 | 6 |

Welcome!

7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies-varfile/website/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-expected-output/dependencies-varfile/website/logo.png -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies/README.md: -------------------------------------------------------------------------------- 1 | # Dependencies example 2 | 3 | This is a boilerplate template that shows an example of using dependencies. It specifies both the 4 | [docs](/examples/for-learning-and-testing/docs) and [website](/examples/for-learning-and-testing/website) examples as 5 | dependencies to show how one boilerplate template can pull in another. It also defines all the variables needed for both 6 | of those dependencies at the top level to show how variable inheritance works. 7 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies/docs/README.md: -------------------------------------------------------------------------------- 1 | # Docs example 2 | 3 | This shows an example of how to use boilerplate to fill in parts of your documentation. 4 | 5 | ## Variables 6 | 7 | Here is how you can use a variable: 8 | 9 | The latest version of my app is 0.0.3. 10 | 11 | You could create a CI job that, for each release, regenerates your docs with the latest value of the `Version` variable 12 | passed in using the `--var` option. 13 | 14 | ## Snippets 15 | 16 | Here is how to use the `snippet` helper to embed files or parts of files from source code: 17 | 18 | ```html 19 | 20 | 21 | {{.Title}} 22 | 23 | 24 |

{{.WelcomeText}}

25 | {{if .ShowLogo}}{{end}} 26 | 27 | 28 | ``` 29 | 30 | ## Arithmetic 31 | 32 | Here is how you can use the arithmetic helpers to create a numbered list: 33 | 34 | 1. Item 35 | 2. Item 36 | 3. Item 37 | 38 | And here is another way to do it using the slice helper: 39 | 40 | 1. Item 41 | 2. Item 42 | 3. Item 43 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies/docs/interpolated-folder-example-folder/my_example_file.py: -------------------------------------------------------------------------------- 1 | # This file and its parent folder both show an example of using Go template syntax and boilerplate variables in their names -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies/website/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Boilerplate 4 | 5 | 6 |

Welcome!

7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/dependencies/website/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-expected-output/dependencies/website/logo.png -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/docs/README.md: -------------------------------------------------------------------------------- 1 | # Docs example 2 | 3 | This shows an example of how to use boilerplate to fill in parts of your documentation. 4 | 5 | ## Variables 6 | 7 | Here is how you can use a variable: 8 | 9 | The latest version of my app is 0.0.3. 10 | 11 | You could create a CI job that, for each release, regenerates your docs with the latest value of the `Version` variable 12 | passed in using the `--var` option. 13 | 14 | ## Snippets 15 | 16 | Here is how to use the `snippet` helper to embed files or parts of files from source code: 17 | 18 | ```html 19 | 20 | 21 | {{.Title}} 22 | 23 | 24 |

{{.WelcomeText}}

25 | {{if .ShowLogo}}{{end}} 26 | 27 | 28 | ``` 29 | 30 | ## Arithmetic 31 | 32 | Here is how you can use the arithmetic helpers to create a numbered list: 33 | 34 | 1. Item 35 | 2. Item 36 | 3. Item 37 | 38 | And here is another way to do it using the slice helper: 39 | 40 | 1. Item 41 | 2. Item 42 | 3. Item 43 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/docs/interpolated-folder-example-folder/my_example_file.py: -------------------------------------------------------------------------------- 1 | # This file and its parent folder both show an example of using Go template syntax and boilerplate variables in their names -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/hooks-working-dir/subdir/test.txt: -------------------------------------------------------------------------------- 1 | hook 2 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/include/target.txt: -------------------------------------------------------------------------------- 1 | asdf-1234-4321-fdsa 2 | 3 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/java-project/com/acme/example/Example.java: -------------------------------------------------------------------------------- 1 | package com.acme.example 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | 5 | public class Example { 6 | public static final int EXAMPLE_INT_CONSTANT = 42 7 | public static final Map<> EXAMPLE_MAP = ImmutableMap.of("key1", "value1", "key2", "value2", "key3", "value3"); 8 | 9 | public enum ExampleEnum { 10 | Foo, Bar, Baz 11 | } 12 | } -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/json/example1.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "Hello" 3 | } 4 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/json/example2.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo: "Hello" 3 | } 4 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/jsonnet/people.json: -------------------------------------------------------------------------------- 1 | { 2 | "people": [ 3 | { 4 | "name": "Yori", 5 | "age": 99, 6 | "favoriteFoods": [ 7 | "Onigiri", 8 | "Katsudon" 9 | ] 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/jsonnet/people_jsonnet.json: -------------------------------------------------------------------------------- 1 | { 2 | "people": [ 3 | { 4 | "age": 99, 5 | "favoriteFoods": [ 6 | "Onigiri", 7 | "Katsudon" 8 | ], 9 | "name": "Yori" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/order/template.txt: -------------------------------------------------------------------------------- 1 | "Gruntwork" 2 | "US" 3 | "https://gruntwork.io" 4 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/partials/target.txt: -------------------------------------------------------------------------------- 1 | This is the top of the first template. 2 | This is the target. 3 | This is the bottom of the first template. 4 | This is the top of the second template. 5 | This is the target. 6 | This is the bottom of the second template. -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/regression-template-escape/config.yml: -------------------------------------------------------------------------------- 1 | setting: 2 | name: "artifacts/{{workflow.name}}" 3 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/shell-disabled/README.md: -------------------------------------------------------------------------------- 1 | This example is executed with shell helpers and hooks disabled, so neither the hooks or shell helpers should execute. 2 | 3 | replace-me -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/shell-disabled/example-script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # An example script that will be executed via the 'shell' command in a boilerplate template. This script simply writes 3 | # the text in the first argument into the path in the second argument. 4 | 5 | echo "$1" > "$2" -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/shell/after-hook-example.txt: -------------------------------------------------------------------------------- 1 | Hello, World - executed via an after hook 2 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/shell/before-hook-example.txt: -------------------------------------------------------------------------------- 1 | Hello, World - executed via a before hook 2 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/shell/example-script-2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # An example script that will be executed via the 'shell' command in a boilerplate template. This script simply writes 3 | # the environment variable TEXT into the path in the first argument. 4 | 5 | echo "$TEXT" > "$1" -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/shell/example-script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # An example script that will be executed via the 'shell' command in a boilerplate template. This script simply echoes 3 | # back the arguments you pass to it. 4 | 5 | echo "$@" -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/shell/hello-world.txt: -------------------------------------------------------------------------------- 1 | Example of executing an arbitrary shell command using the shell helper: 2 | 3 | Hello, World 4 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/skip-files-glob/a/b/c/foo.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-expected-output/skip-files-glob/a/b/c/foo.txt -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/skip-files-mixed/docs/README.md: -------------------------------------------------------------------------------- 1 | # This is some README 2 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/skip-files-multiple/b.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-expected-output/skip-files-multiple/b.yml -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/skip-files-nested/a/b/c/.keep-dir: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-expected-output/skip-files-nested/a/b/c/.keep-dir -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/skip-not-path-mixed-noskip/docs/bar.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-expected-output/skip-not-path-mixed-noskip/docs/bar.txt -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/skip-not-path-mixed-noskip/docs/foo.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-expected-output/skip-not-path-mixed-noskip/docs/foo.txt -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/skip-not-path-mixed-skip/a/foo.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-expected-output/skip-not-path-mixed-skip/a/foo.yml -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/skip-not-path-multiple/docs/bar.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-expected-output/skip-not-path-multiple/docs/bar.txt -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/skip-not-path-multiple/docs/foo.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-expected-output/skip-not-path-multiple/docs/foo.txt -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/skip-not-path/docs/bar.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-expected-output/skip-not-path/docs/bar.txt -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/skip-not-path/docs/foo.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-expected-output/skip-not-path/docs/foo.txt -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/template-helpers/docs/README.md: -------------------------------------------------------------------------------- 1 | # Docs example 2 | 3 | This shows an example of how to use boilerplate to fill in parts of your documentation. 4 | 5 | ## Variables 6 | 7 | Here is how you can use a variable: 8 | 9 | The latest version of my app is 0.0.3. 10 | 11 | You could create a CI job that, for each release, regenerates your docs with the latest value of the `Version` variable 12 | passed in using the `--var` option. 13 | 14 | ## Snippets 15 | 16 | Here is how to use the `snippet` helper to embed files or parts of files from source code: 17 | 18 | ```html 19 | 20 | 21 | {{.Title}} 22 | 23 | 24 |

{{.WelcomeText}}

25 | {{if .ShowLogo}}{{end}} 26 | 27 | 28 | ``` 29 | 30 | ## Arithmetic 31 | 32 | Here is how you can use the arithmetic helpers to create a numbered list: 33 | 34 | 1. Item 35 | 2. Item 36 | 3. Item 37 | 38 | And here is another way to do it using the slice helper: 39 | 40 | 1. Item 41 | 2. Item 42 | 3. Item 43 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/template-helpers/docs/interpolated-folder-example-folder/my_example_file.py: -------------------------------------------------------------------------------- 1 | # This file and its parent folder both show an example of using Go template syntax and boilerplate variables in their names -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/template-helpers/sample.txt: -------------------------------------------------------------------------------- 1 | ../docs 2 | ./docs 3 | ../website 4 | ./website 5 | 6 | foo 7 | Inazagi 8 | 9 | -world 10 | 11 | ../../d 12 | 13 | Inazagi 14 | 15 | foo 16 | 17 | [2 3] 18 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/template-helpers/website/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Boilerplate 4 | 5 | 6 |

Welcome!

7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/template-helpers/website/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-expected-output/template-helpers/website/logo.png -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/terraform/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | resource "aws_instance" "example" { 6 | ami = "ami-abcd1234" 7 | instance_type = "t3.micro" 8 | 9 | tags = { 10 | Name = "MyServer" 11 | } 12 | } -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/tofu-example/README.md: -------------------------------------------------------------------------------- 1 | # Vpc example 2 | 3 | An example of how to use the [vpc module](../../modules/vpc). 4 | 5 | ## Quick start 6 | 7 | 1. Open `variables.tf` and fill in the values you want. 8 | 2. `tofu init`. 9 | 3. `tofu apply`. 10 | 4. When you're done testing: `tofu destroy`. -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/tofu-example/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "1.6.2" 3 | } 4 | 5 | module "vpc" { 6 | source = "../../modules/vpc" 7 | 8 | example_required_input = "Hello" 9 | example_optional_input = "World" 10 | } -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/tofu-example/outputs.tf: -------------------------------------------------------------------------------- 1 | output "example_output" { 2 | description = "example output" 3 | value = module.vpc.example_output 4 | } -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/tofu-module-full/examples/vpc/README.md: -------------------------------------------------------------------------------- 1 | # Vpc example 2 | 3 | An example of how to use the [vpc module](../../modules/vpc). 4 | 5 | ## Quick start 6 | 7 | 1. Open `variables.tf` and fill in the values you want. 8 | 2. `tofu init`. 9 | 3. `tofu apply`. 10 | 4. When you're done testing: `tofu destroy`. -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/tofu-module-full/examples/vpc/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "1.6.2" 3 | } 4 | 5 | module "vpc" { 6 | source = "../../modules/vpc" 7 | 8 | example_required_input = "Hello" 9 | example_optional_input = "World" 10 | } -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/tofu-module-full/examples/vpc/outputs.tf: -------------------------------------------------------------------------------- 1 | output "example_output" { 2 | description = "example output" 3 | value = module.vpc.example_output 4 | } -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/tofu-module-full/modules/vpc/README.md: -------------------------------------------------------------------------------- 1 | # Vpc module 2 | 3 | TODO: fill in documentation for the vpc module. 4 | 5 | ## License 6 | 7 | Copyright 2024 Gruntwork, Inc. 8 | 9 | Please see [LICENSE.txt](LICENSE.txt) for details on how the code in this repo is licensed. -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/tofu-module-full/modules/vpc/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "1.6.2" 3 | } 4 | 5 | # --------------------------------------------------------------------------------------------------------------------- 6 | # TODO: DEFINE YOUR RESOURCES HERE 7 | # --------------------------------------------------------------------------------------------------------------------- 8 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/tofu-module-full/modules/vpc/outputs.tf: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------------------------------------------------- 2 | # TODO: DEFINE YOUR OUTPUTS HERE 3 | # --------------------------------------------------------------------------------------------------------------------- 4 | 5 | output "example_output" { 6 | description = "example output" 7 | value = "${var.example_required_input} ${var.example_optional_input}" 8 | } -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/tofu-module-full/modules/vpc/variables.tf: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------------------------------------------------- 2 | # REQUIRED VARIABLES 3 | # TODO: define your required variables here 4 | # --------------------------------------------------------------------------------------------------------------------- 5 | 6 | variable "example_required_input" { 7 | description = "Example required input variable" 8 | type = string 9 | } 10 | 11 | # --------------------------------------------------------------------------------------------------------------------- 12 | # OPTIONAL VARIABLES 13 | # TODO: define your optional variables here 14 | # --------------------------------------------------------------------------------------------------------------------- 15 | 16 | variable "example_optional_input" { 17 | description = "Example optional input variable" 18 | type = string 19 | default = "example-optional" 20 | } 21 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/tofu-module-full/test/vpc_test.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | // +build ignore 3 | 4 | package test 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/gruntwork-io/terratest/modules/terraform" 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func TestVpc(t *testing.T) { 14 | t.Parallel() 15 | 16 | opts := &terraform.Options{ 17 | TerraformDir: "../examples/vpc", 18 | TerraformBinary: "tofu", 19 | } 20 | 21 | defer terraform.Destroy(t, opts) 22 | 23 | terraform.InitAndApply(t, opts) 24 | 25 | actualOutput := terraform.OutputRequired(t, opts, "example_output") 26 | assert.Equal(t, "Hello World", actualOutput) 27 | } 28 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/tofu-module/README.md: -------------------------------------------------------------------------------- 1 | # Vpc module 2 | 3 | TODO: fill in documentation for the vpc module. 4 | 5 | ## License 6 | 7 | Copyright 2024 Gruntwork, Inc. 8 | 9 | Please see [LICENSE.txt](LICENSE.txt) for details on how the code in this repo is licensed. -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/tofu-module/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "1.6.2" 3 | } 4 | 5 | # --------------------------------------------------------------------------------------------------------------------- 6 | # TODO: DEFINE YOUR RESOURCES HERE 7 | # --------------------------------------------------------------------------------------------------------------------- 8 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/tofu-module/outputs.tf: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------------------------------------------------- 2 | # TODO: DEFINE YOUR OUTPUTS HERE 3 | # --------------------------------------------------------------------------------------------------------------------- 4 | 5 | output "example_output" { 6 | description = "example output" 7 | value = "${var.example_required_input} ${var.example_optional_input}" 8 | } -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/tofu-module/variables.tf: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------------------------------------------------- 2 | # REQUIRED VARIABLES 3 | # TODO: define your required variables here 4 | # --------------------------------------------------------------------------------------------------------------------- 5 | 6 | variable "example_required_input" { 7 | description = "Example required input variable" 8 | type = string 9 | } 10 | 11 | # --------------------------------------------------------------------------------------------------------------------- 12 | # OPTIONAL VARIABLES 13 | # TODO: define your optional variables here 14 | # --------------------------------------------------------------------------------------------------------------------- 15 | 16 | variable "example_optional_input" { 17 | description = "Example optional input variable" 18 | type = string 19 | default = "example-optional" 20 | } 21 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/tofu-test/vpc_test.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | // +build ignore 3 | 4 | package test 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/gruntwork-io/terratest/modules/terraform" 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func TestVpc(t *testing.T) { 14 | t.Parallel() 15 | 16 | opts := &terraform.Options{ 17 | TerraformDir: "../examples/vpc", 18 | TerraformBinary: "tofu", 19 | } 20 | 21 | defer terraform.Destroy(t, opts) 22 | 23 | terraform.InitAndApply(t, opts) 24 | 25 | actualOutput := terraform.OutputRequired(t, opts, "example_output") 26 | assert.Equal(t, "Hello World", actualOutput) 27 | } 28 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/validations/template.txt: -------------------------------------------------------------------------------- 1 | "Gruntwork" 2 | "US" 3 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/variables-recursive/README.md: -------------------------------------------------------------------------------- 1 | # Recursive variables 2 | 3 | This shows an example of variables that reference other variables. 4 | 5 | Foo = foo 6 | Bar = foo-bar 7 | Baz = foo-bar-baz 8 | 9 | FooList = foo, bar, baz 10 | BarList = foo, bar, baz 11 | FooMap = bar: 2, baz: 3, foo: 1 12 | BarMap = bar: 2, baz: 3, foo: 1 13 | 14 | ListWithTemplates = foo, foo-bar, foo-bar-baz 15 | MapWithTemplates = foo: foo, foo-bar: foo-bar, foo-bar-baz: foo-bar-baz 16 | ListWithNestedMap = (name: foo, value: foo), (name: bar, value: bar) 17 | MapWithNestedList = (key: bar, value: 4, 5, 6), (key: foo, value: 1, 2, 3) 18 | 19 | IntValue: 42 20 | IntValueInterpolation: 42 21 | FloatValue: 3.14 22 | FloatValueInterpolation: 3.14 23 | BoolValue: true 24 | BoolValueInterpolationSimple: true 25 | BoolValueInterpolationSimpleComplex: true 26 | ListValue: 1, 2, 3 27 | ListValueInterpolation: 1, 2, 3 28 | MapValue: bar: 2, baz: 3, foo: 1 29 | MapValueInterpolation: bar: 2, baz: 3, foo: 1 30 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/variables-recursive/example.txt: -------------------------------------------------------------------------------- 1 | BazMap = bar: 2, baz: 3, foo: 1 -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/website/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Boilerplate 4 | 5 | 6 |

Welcome!

7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test-fixtures/examples-expected-output/website/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-expected-output/website/logo.png -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/dependencies-dynamic/vars.yml: -------------------------------------------------------------------------------- 1 | Version: 0.0.3 2 | Title: Dynamic dependencies example 3 | website.Title: Boilerplate 4 | docs.Title: Docs example 5 | WelcomeText: Welcome! 6 | Description: This is a boilerplate template that shows an example of using dependencies 7 | WebsiteTemplateFolder: ../website 8 | WebsiteOutputFolder: ./website -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/dependencies-for-each-reference-list-of-strings/vars.yml: -------------------------------------------------------------------------------- 1 | # Intentionally empty -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/dependencies-for-each-reference/vars.yml: -------------------------------------------------------------------------------- 1 | # Intentionally empty -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/dependencies-for-each/vars.yml: -------------------------------------------------------------------------------- 1 | # Intentionally empty -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/dependencies-recursive/vars.yml: -------------------------------------------------------------------------------- 1 | Version: 0.0.3 2 | Title: Recursive dependencies example 3 | WelcomeText: Welcome! 4 | Description: This is a boilerplate template that shows an example of using recursive dependencies 5 | 6 | dependencies.Title: Dependencies example 7 | dependencies.Description: This is a boilerplate template that shows an example of using dependencies 8 | dependencies.website.Title: Boilerplate 9 | dependencies.docs.Title: Docs example 10 | 11 | java-project.CompanyName: acme 12 | java-project.ExampleIntConstant: 42 13 | java-project.IncludeEnum: true 14 | java-project.EnumNames: 15 | - Foo 16 | - Bar 17 | - Baz 18 | java-project.ExampleMap: 19 | key1: value1 20 | key2: value2 21 | key3: value3 -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/dependencies-remote/vars.yml: -------------------------------------------------------------------------------- 1 | Version: 0.0.3 2 | Title: Dependencies example 3 | website.Title: Boilerplate 4 | docs.Title: Docs example 5 | WelcomeText: Welcome! 6 | Description: This is a boilerplate template that shows an example of using dependencies -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/dependencies-varfile-precedence/vars.yml: -------------------------------------------------------------------------------- 1 | Version: 0.0.3 2 | Title: Dependencies example 3 | website.Title: Boilerplate 4 | Description: This is a boilerplate template that shows an example of using dependencies 5 | -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/dependencies-varfile/vars.yml: -------------------------------------------------------------------------------- 1 | Version: 0.0.3 2 | WelcomeText: Welcome! 3 | Description: This is a boilerplate template that shows an example of using dependencies 4 | -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/dependencies/vars.yml: -------------------------------------------------------------------------------- 1 | Version: 0.0.3 2 | Title: Dependencies example 3 | website.Title: Boilerplate 4 | docs.Title: Docs example 5 | WelcomeText: Welcome! 6 | Description: This is a boilerplate template that shows an example of using dependencies -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/docs/vars.yml: -------------------------------------------------------------------------------- 1 | Title: Docs example 2 | Version: 0.0.3 -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/hooks-working-dir/vars.yml: -------------------------------------------------------------------------------- 1 | # Intentionally empty -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/include/vars.yml: -------------------------------------------------------------------------------- 1 | RandomVal: asdf-1234-4321-fdsa 2 | -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/java-project/vars.yml: -------------------------------------------------------------------------------- 1 | CompanyName: acme 2 | ExampleIntConstant: 42 3 | IncludeEnum: true 4 | EnumNames: 5 | - Foo 6 | - Bar 7 | - Baz 8 | ExampleMap: 9 | key1: value1 10 | key2: value2 11 | key3: value3 -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/json/vars.yml: -------------------------------------------------------------------------------- 1 | Foo: Hello -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/jsonnet/vars.yml: -------------------------------------------------------------------------------- 1 | Name: "Yori" 2 | IncludeAge: true 3 | AgeMap: 4 | Yori: 99 5 | Python: -1 6 | FavoriteFoods: 7 | - "Onigiri" 8 | - "Katsudon" 9 | -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/kebab-case-bug-unix/vars.yml: -------------------------------------------------------------------------------- 1 | Name: test-2-a 2 | -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/order/vars.yml: -------------------------------------------------------------------------------- 1 | CompanyName: Gruntwork 2 | CountryCode: US 3 | URL: "https://gruntwork.io" 4 | -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/partials/vars.yml: -------------------------------------------------------------------------------- 1 | Foo: bar 2 | -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/regression-template-escape/vars.yml: -------------------------------------------------------------------------------- 1 | SettingValue: "artifacts/{{ `{{workflow.name}}` }}" 2 | -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/shell-disabled/vars.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-var-files/shell-disabled/vars.yml -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/shell/vars.yml: -------------------------------------------------------------------------------- 1 | Text: Hello, World -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/skip-files-glob/vars.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-var-files/skip-files-glob/vars.yml -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/skip-files-mixed/vars.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-var-files/skip-files-mixed/vars.yml -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/skip-files-multiple/vars.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-var-files/skip-files-multiple/vars.yml -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/skip-files-nested/vars.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-var-files/skip-files-nested/vars.yml -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/skip-not-path-mixed-noskip/vars.yml: -------------------------------------------------------------------------------- 1 | DocsOnly: true 2 | -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/skip-not-path-mixed-skip/vars.yml: -------------------------------------------------------------------------------- 1 | DocsOnly: false 2 | -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/skip-not-path-multiple/vars.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-var-files/skip-not-path-multiple/vars.yml -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/skip-not-path/vars.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/examples-var-files/skip-not-path/vars.yml -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/template-helpers/vars.yml: -------------------------------------------------------------------------------- 1 | SomeGlobalVar: foo 2 | website.Title: Boilerplate 3 | website.WelcomeText: Welcome! 4 | docs.Title: Docs example 5 | docs.Version: 0.0.3 -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/terraform/vars.yml: -------------------------------------------------------------------------------- 1 | ServerName: MyServer -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/tofu-example/vars.yml: -------------------------------------------------------------------------------- 1 | ModuleName: vpc 2 | ModuleSource: ../../modules/vpc -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/tofu-module-full/vars.yml: -------------------------------------------------------------------------------- 1 | ModuleName: vpc 2 | CopyrightInfo: Copyright 2024 Gruntwork, Inc. 3 | -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/tofu-module/vars.yml: -------------------------------------------------------------------------------- 1 | ModuleName: vpc 2 | CopyrightInfo: Copyright 2024 Gruntwork, Inc. -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/tofu-test-unix/vars.yml: -------------------------------------------------------------------------------- 1 | ModuleName: vpc 2 | ExamplePath: ../examples/vpc -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/tofu-test/vars.yml: -------------------------------------------------------------------------------- 1 | ModuleName: vpc 2 | ExamplePath: ../examples/vpc -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/validations/vars.yml: -------------------------------------------------------------------------------- 1 | CompanyName: Gruntwork 2 | CountryCode: US 3 | 4 | -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/variables-recursive/vars.yml: -------------------------------------------------------------------------------- 1 | Foo: "foo" -------------------------------------------------------------------------------- /test-fixtures/examples-var-files/website/vars.yml: -------------------------------------------------------------------------------- 1 | Title: Boilerplate 2 | WelcomeText: Welcome! -------------------------------------------------------------------------------- /test-fixtures/include-test/template.txt: -------------------------------------------------------------------------------- 1 | {{ .RandomVal }} 2 | -------------------------------------------------------------------------------- /test-fixtures/jsonnet-unit-test/externalVars/expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "templateFolder": "/path/to/template", 3 | "outputFolder": "/path/to/output" 4 | } 5 | -------------------------------------------------------------------------------- /test-fixtures/jsonnet-unit-test/externalVars/template.jsonnet: -------------------------------------------------------------------------------- 1 | function(boilerplateVars) { 2 | templateFolder: std.extVar('templateFolder'), 3 | outputFolder: std.extVar('outputFolder'), 4 | } 5 | -------------------------------------------------------------------------------- /test-fixtures/jsonnet-unit-test/externalVars/variables.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /test-fixtures/jsonnet-unit-test/functions/expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "person": { 3 | "name": "Yori" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test-fixtures/jsonnet-unit-test/functions/template.jsonnet: -------------------------------------------------------------------------------- 1 | local newPerson(name) = { 2 | name: name, 3 | }; 4 | 5 | function(boilerplateVars) { 6 | person: newPerson(boilerplateVars.Name), 7 | } 8 | -------------------------------------------------------------------------------- /test-fixtures/jsonnet-unit-test/functions/variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "Yori" 3 | } 4 | -------------------------------------------------------------------------------- /test-fixtures/jsonnet-unit-test/imports/expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "person": { 3 | "name": "Yori" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test-fixtures/jsonnet-unit-test/imports/funcdef.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | newPerson(name):: { 3 | name: name, 4 | }, 5 | } 6 | -------------------------------------------------------------------------------- /test-fixtures/jsonnet-unit-test/imports/template.jsonnet: -------------------------------------------------------------------------------- 1 | local funcs = import 'funcdef.libsonnet'; 2 | 3 | function(boilerplateVars) { 4 | person: funcs.newPerson(boilerplateVars.Name), 5 | } 6 | -------------------------------------------------------------------------------- /test-fixtures/jsonnet-unit-test/imports/variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "Yori" 3 | } 4 | -------------------------------------------------------------------------------- /test-fixtures/marshal-yaml-test/shell/expected.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - description: Enter the text to display 3 | name: Text 4 | type: string 5 | hooks: 6 | after: 7 | - command: echo 8 | args: 9 | - Running after hooks 10 | - command: ./example-script-2.sh 11 | args: 12 | - '{{ outputFolder }}/after-hook-example.txt' 13 | env: 14 | TEXT: '{{ .Text }} - executed via an after hook' 15 | before: 16 | - command: echo 17 | args: 18 | - Running before hooks 19 | - command: ./example-script-2.sh 20 | args: 21 | - '{{ outputFolder }}/before-hook-example.txt' 22 | env: 23 | TEXT: '{{ .Text }} - executed via a before hook' 24 | - command: ./example-script-2.sh 25 | args: 26 | - '{{ outputFolder }}/before-hook-should-be-skipped.txt' 27 | env: 28 | TEXT: this hook should be skipped 29 | skip: "true" 30 | -------------------------------------------------------------------------------- /test-fixtures/marshal-yaml-test/variables-recursive/expected.yml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: variables 3 | output-folder: . 4 | template-url: ../variables 5 | variables: 6 | - name: Foo 7 | type: string 8 | - default: '{{ .Foo }}-bar' 9 | name: Bar 10 | type: string 11 | - default: '{{ .Bar }}-baz' 12 | name: Baz 13 | type: string 14 | - default: 15 | - foo 16 | - bar 17 | - baz 18 | name: FooList 19 | type: list 20 | - name: BarList 21 | reference: FooList 22 | type: list 23 | - default: 24 | bar: 2 25 | baz: 3 26 | foo: 1 27 | name: FooMap 28 | type: map 29 | - name: BarMap 30 | reference: FooMap 31 | type: map 32 | - default: 33 | - '{{ .Foo }}' 34 | - '{{ .Bar }}' 35 | - '{{ .Baz }}' 36 | name: ListWithTemplates 37 | type: list 38 | - default: 39 | '{{ .Bar }}': '{{ .Bar }}' 40 | '{{ .Baz }}': '{{ .Baz }}' 41 | '{{ .Foo }}': '{{ .Foo }}' 42 | name: MapWithTemplates 43 | type: map 44 | - default: 45 | - name: foo 46 | value: foo 47 | - name: bar 48 | value: bar 49 | name: ListWithNestedMap 50 | type: list 51 | - default: 52 | bar: 53 | - 4 54 | - 5 55 | - 6 56 | foo: 57 | - 1 58 | - 2 59 | - 3 60 | name: MapWithNestedList 61 | type: map 62 | - default: 42 63 | name: IntValue 64 | type: int 65 | - default: '{{ .IntValue }}' 66 | name: IntValueInterpolation 67 | type: int 68 | - default: 3.14 69 | name: FloatValue 70 | type: float 71 | - default: '{{ .FloatValue }}' 72 | name: FloatValueInterpolation 73 | type: float 74 | - default: true 75 | name: BoolValue 76 | type: bool 77 | - default: '{{ .BoolValue }}' 78 | name: BoolValueInterpolationSimple 79 | type: bool 80 | - default: '{{ eq .IntValue 42 }}' 81 | name: BoolValueInterpolationSimpleComplex 82 | type: bool 83 | - default: 84 | - 1 85 | - 2 86 | - 3 87 | name: ListValue 88 | type: list 89 | - default: '{{ .ListValue }}' 90 | name: ListValueInterpolation 91 | type: list 92 | - default: 93 | bar: 2 94 | baz: 3 95 | foo: 1 96 | name: MapValue 97 | type: map 98 | - default: '{{ .MapValue }}' 99 | name: MapValueInterpolation 100 | type: map 101 | -------------------------------------------------------------------------------- /test-fixtures/partials-test/first.txt: -------------------------------------------------------------------------------- 1 | {{- define "first_template" -}} 2 | This is the top of the first template. 3 | {{ template "target" . }} 4 | This is the bottom of the first template. 5 | {{- end -}} 6 | 7 | -------------------------------------------------------------------------------- /test-fixtures/partials-test/second.txt: -------------------------------------------------------------------------------- 1 | {{- define "second_template" -}} 2 | This is the top of the second template. 3 | {{ template "target" . }} 4 | This is the bottom of the second template. 5 | {{- end -}} 6 | -------------------------------------------------------------------------------- /test-fixtures/regression-test/misspelled-git/boilerplate.yml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: guestbook 3 | output-folder: './guestbook' 4 | template-url: git@github.com/JDoe/guestbook.git//nginx?ref=v0.1.0 5 | -------------------------------------------------------------------------------- /test-fixtures/regression-test/required-version/match/boilerplate.yml: -------------------------------------------------------------------------------- 1 | required_version: "= 1.33.7" 2 | -------------------------------------------------------------------------------- /test-fixtures/regression-test/required-version/over-test/boilerplate.yml: -------------------------------------------------------------------------------- 1 | required_version: "~> 3.0" 2 | -------------------------------------------------------------------------------- /test-fixtures/regression-test/required-version/under-test/boilerplate.yml: -------------------------------------------------------------------------------- 1 | required_version: "> 1.0" 2 | -------------------------------------------------------------------------------- /test-fixtures/regression-test/slice-parsing/boilerplate.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: MapValue 3 | description: A map value that will be passed in via a --var flag 4 | type: map 5 | -------------------------------------------------------------------------------- /test-fixtures/regression-test/slice-parsing/output.txt: -------------------------------------------------------------------------------- 1 | {{ .MapValue | toJson }} -------------------------------------------------------------------------------- /test-fixtures/templates-test/full-file-snippet.txt: -------------------------------------------------------------------------------- 1 | Hi 2 | boilerplate-snippet: foo 3 | Hello, World! 4 | boilerplate-snippet: foo 5 | Bye -------------------------------------------------------------------------------- /test-fixtures/util-test/is-text-file/binary-file: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/util-test/is-text-file/binary-file -------------------------------------------------------------------------------- /test-fixtures/util-test/is-text-file/binary-file.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/util-test/is-text-file/binary-file.jpg -------------------------------------------------------------------------------- /test-fixtures/util-test/is-text-file/binary-file.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/util-test/is-text-file/binary-file.pdf -------------------------------------------------------------------------------- /test-fixtures/util-test/is-text-file/binary-file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/util-test/is-text-file/binary-file.png -------------------------------------------------------------------------------- /test-fixtures/util-test/is-text-file/binary-file.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/util-test/is-text-file/binary-file.zip -------------------------------------------------------------------------------- /test-fixtures/util-test/is-text-file/empty-file: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/boilerplate/8412739e213e8584fa01ad1c539c1b40ebc08974/test-fixtures/util-test/is-text-file/empty-file -------------------------------------------------------------------------------- /test-fixtures/util-test/is-text-file/file-go.go: -------------------------------------------------------------------------------- 1 | package is_text_file 2 | -------------------------------------------------------------------------------- /test-fixtures/util-test/is-text-file/file-hcl.hcl: -------------------------------------------------------------------------------- 1 | terraform { 2 | source = "." 3 | } 4 | 5 | inputs = { 6 | region = "us-west-2" 7 | vpc_cidr = "10.0.0.1/" 8 | } -------------------------------------------------------------------------------- /test-fixtures/util-test/is-text-file/file-java.java: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | public static void main(String... args) { 4 | 5 | } -------------------------------------------------------------------------------- /test-fixtures/util-test/is-text-file/file-xml.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | potato 4 | -------------------------------------------------------------------------------- /test-fixtures/util-test/is-text-file/json-file.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar" 3 | } -------------------------------------------------------------------------------- /test-fixtures/util-test/is-text-file/text-file.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | This is HTML 4 | 5 | -------------------------------------------------------------------------------- /test-fixtures/util-test/is-text-file/text-file.js: -------------------------------------------------------------------------------- 1 | var x = "this is a text file"; -------------------------------------------------------------------------------- /test-fixtures/util-test/is-text-file/text-file.md: -------------------------------------------------------------------------------- 1 | # This is a text file -------------------------------------------------------------------------------- /test-fixtures/util-test/is-text-file/text-file.tf: -------------------------------------------------------------------------------- 1 | variable "foo" { 2 | description = "this is a text file" 3 | } -------------------------------------------------------------------------------- /test-fixtures/util-test/is-text-file/text-file.txt: -------------------------------------------------------------------------------- 1 | This is a text file -------------------------------------------------------------------------------- /test-fixtures/util-test/is-text-file/yaml-file.yaml: -------------------------------------------------------------------------------- 1 | foo: "bar" -------------------------------------------------------------------------------- /util/collections.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import "fmt" 4 | 5 | // Merge all the maps into one. Sadly, Go has no generics, so this is only defined for string to interface maps. 6 | func MergeMaps(maps ...map[string]any) map[string]any { 7 | out := map[string]any{} 8 | 9 | for _, currMap := range maps { 10 | for key, value := range currMap { 11 | out[key] = value 12 | } 13 | } 14 | 15 | return out 16 | } 17 | 18 | // Return true if the given list of strings (haystack) contains the given string (needle) 19 | func ListContains(needle string, haystack []string) bool { 20 | for _, str := range haystack { 21 | if needle == str { 22 | return true 23 | } 24 | } 25 | 26 | return false 27 | } 28 | 29 | // Convert a generic list to a list of strings 30 | func ToStringList(genericList []any) []string { 31 | stringList := []string{} 32 | 33 | for _, value := range genericList { 34 | stringList = append(stringList, ToString(value)) 35 | } 36 | 37 | return stringList 38 | } 39 | 40 | // Convert a generic map to a map from string to string 41 | func ToStringMap(genericMap map[any]any) map[string]string { 42 | stringMap := map[string]string{} 43 | 44 | for key, value := range genericMap { 45 | stringMap[ToString(key)] = ToString(value) 46 | } 47 | 48 | return stringMap 49 | } 50 | 51 | // Convert a generic map to a map from string to interface 52 | func ToStringToGenericMap(genericMap map[any]any) map[string]any { 53 | stringToGenericMap := map[string]any{} 54 | 55 | for key, value := range genericMap { 56 | stringToGenericMap[ToString(key)] = value 57 | } 58 | 59 | return stringToGenericMap 60 | } 61 | 62 | // Convert a single value to its string representation 63 | func ToString(value any) string { 64 | return fmt.Sprintf("%v", value) 65 | } 66 | -------------------------------------------------------------------------------- /util/file.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gabriel-vasile/mimetype" 6 | "github.com/gruntwork-io/boilerplate/errors" 7 | "io/ioutil" 8 | "os" 9 | "os/exec" 10 | "path/filepath" 11 | ) 12 | 13 | const textMimeType = "text/plain" 14 | 15 | // Return true if the path exists 16 | func PathExists(path string) bool { 17 | _, err := os.Stat(path) 18 | return err == nil 19 | } 20 | 21 | // Return true if the path points to a directory 22 | func IsDir(path string) bool { 23 | fileInfo, err := os.Stat(path) 24 | return err == nil && fileInfo.IsDir() 25 | } 26 | 27 | // IsTextFile - usage of mimetype library to identify if the file is binary or text. 28 | func IsTextFile(path string) (bool, error) { 29 | if !PathExists(path) { 30 | return false, NoSuchFile(path) 31 | } 32 | // consider empty file as binary file 33 | fileInfo, err := os.Stat(path) 34 | if err != nil { 35 | return false, errors.WithStackTrace(err) 36 | } 37 | if fileInfo.Size() == 0 { 38 | return false, nil 39 | } 40 | 41 | detectedMIME, err := mimetype.DetectFile(path) 42 | if err != nil { 43 | return false, errors.WithStackTrace(err) 44 | } 45 | for mtype := detectedMIME; mtype != nil; mtype = mtype.Parent() { 46 | if mtype.Is(textMimeType) { 47 | return true, nil 48 | } 49 | } 50 | return false, nil 51 | } 52 | 53 | // Return true if the OS has the given command installed 54 | func CommandInstalled(command string) bool { 55 | _, err := exec.LookPath(command) 56 | return err == nil 57 | } 58 | 59 | // Run the given command return its stdout and stderr as a string 60 | func RunCommandAndGetOutput(command string, args ...string) (string, error) { 61 | cmd := exec.Command(command, args...) 62 | 63 | bytes, err := cmd.Output() 64 | if err != nil { 65 | return "", errors.WithStackTrace(err) 66 | } 67 | 68 | return string(bytes), nil 69 | } 70 | 71 | // Copy a file from source to destination 72 | func CopyFile(source string, destination string) error { 73 | contents, err := ioutil.ReadFile(source) 74 | if err != nil { 75 | return errors.WithStackTrace(err) 76 | } 77 | 78 | return WriteFileWithSamePermissions(source, destination, contents) 79 | } 80 | 81 | // Write a file to the given destination with the given contents using the same permissions as the file at source 82 | func WriteFileWithSamePermissions(source string, destination string, contents []byte) error { 83 | fileInfo, err := os.Stat(source) 84 | if err != nil { 85 | return errors.WithStackTrace(err) 86 | } 87 | 88 | return ioutil.WriteFile(destination, contents, fileInfo.Mode()) 89 | } 90 | 91 | // Copy all the files and folders in srcFolder to targetFolder. 92 | func CopyFolder(srcFolder string, targetFolder string) error { 93 | return filepath.Walk(srcFolder, func(path string, info os.FileInfo, err error) error { 94 | relPath, err := filepath.Rel(srcFolder, path) 95 | if err != nil { 96 | return err 97 | } 98 | 99 | if IsDir(path) { 100 | return os.MkdirAll(filepath.Join(targetFolder, relPath), 0755) 101 | } else { 102 | return CopyFile(path, filepath.Join(targetFolder, relPath)) 103 | } 104 | }) 105 | } 106 | 107 | // custom error types 108 | 109 | type NoSuchFile string 110 | 111 | func (path NoSuchFile) Error() string { 112 | return fmt.Sprintf("File %s does not exist", string(path)) 113 | } 114 | -------------------------------------------------------------------------------- /util/file_test.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | 10 | "github.com/gruntwork-io/boilerplate/errors" 11 | ) 12 | 13 | func TestIsTextFile(t *testing.T) { 14 | t.Parallel() 15 | 16 | testCases := []struct { 17 | file string 18 | isText bool 19 | }{ 20 | {"binary-file.jpg", false}, 21 | {"binary-file.png", false}, 22 | {"binary-file.pdf", false}, 23 | {"binary-file.zip", false}, 24 | {"binary-file", false}, 25 | {"empty-file", false}, 26 | {"text-file.html", true}, 27 | {"text-file.js", true}, 28 | {"text-file.txt", true}, 29 | {"text-file.md", true}, 30 | {"text-file.tf", true}, 31 | {"json-file.json", true}, 32 | {"yaml-file.yaml", true}, 33 | {"file-go.go", true}, 34 | {"file-java.java", true}, 35 | {"file-xml.xml", true}, 36 | {"file-hcl.hcl", true}, 37 | } 38 | 39 | for _, testCase := range testCases { 40 | testCase := testCase 41 | t.Run(testCase.file, func(t *testing.T) { 42 | t.Parallel() 43 | actual, err := IsTextFile(fmt.Sprintf("../test-fixtures/util-test/is-text-file/%s", testCase.file)) 44 | 45 | assert.Nil(t, err) 46 | assert.Equal(t, testCase.isText, actual, "Incorrect classification for %s", testCase.file) 47 | }) 48 | } 49 | } 50 | 51 | func TestIsTextFileInvalidPath(t *testing.T) { 52 | t.Parallel() 53 | 54 | _, err := IsTextFile("invalid-path") 55 | assert.NotNil(t, err) 56 | assert.True(t, errors.IsError(err, NoSuchFile("invalid-path")), "Expected NoSuchFile error but got %s", reflect.TypeOf(err)) 57 | } 58 | -------------------------------------------------------------------------------- /util/logger.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "log" 5 | "os" 6 | ) 7 | 8 | // A simple logger we can use to get consistent log formatting through out the app 9 | var Logger = log.New(os.Stdout, "[boilerplate] ", log.LstdFlags) 10 | -------------------------------------------------------------------------------- /util/marshal.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/gruntwork-io/boilerplate/errors" 7 | "gopkg.in/yaml.v2" 8 | ) 9 | 10 | // MarshalListOfObjectsToYAML will marshal the list of objects to yaml by calling MarshalYAML on every item in the list 11 | // and return the results as a list. This is useful when building a custom YAML marshaler. 12 | func MarshalListOfObjectsToYAML(inputList []interface{}) ([]interface{}, error) { 13 | output := []interface{}{} 14 | for _, item := range inputList { 15 | itemAsMarshaler, hasType := item.(yaml.Marshaler) 16 | if hasType == false { 17 | return nil, errors.WithStackTrace(UnmarshalableObjectErr{item}) 18 | } 19 | yaml, err := itemAsMarshaler.MarshalYAML() 20 | if err != nil { 21 | return nil, errors.WithStackTrace(ObjectMarshalingErr{item, err}) 22 | } 23 | output = append(output, yaml) 24 | } 25 | return output, nil 26 | } 27 | 28 | // Custom errors 29 | 30 | // ObjectMarshalingErr is returned when there was an error marshaling the given object to yaml. 31 | type ObjectMarshalingErr struct { 32 | object interface{} 33 | underlyingErr error 34 | } 35 | 36 | func (err ObjectMarshalingErr) Error() string { 37 | return fmt.Sprintf("Error marshaling %v to YAML: %s", err.object, err.underlyingErr) 38 | } 39 | 40 | // UnmarshalableObjectErr is returned when the given object does not implement Marshaler interface. 41 | type UnmarshalableObjectErr struct { 42 | object interface{} 43 | } 44 | 45 | func (err UnmarshalableObjectErr) Error() string { 46 | return fmt.Sprintf("Can not marshal %v to YAML", err.object) 47 | } 48 | -------------------------------------------------------------------------------- /util/prompt.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "os" 7 | "strings" 8 | 9 | "github.com/fatih/color" 10 | "github.com/inancgumus/screen" 11 | 12 | "github.com/gruntwork-io/boilerplate/errors" 13 | ) 14 | 15 | var BRIGHT_GREEN = color.New(color.FgHiGreen, color.Bold) 16 | 17 | // Prompt the user for text in the CLI. Returns the text entered by the user. 18 | func PromptUserForInput(prompt string) (string, error) { 19 | BRIGHT_GREEN.Print(fmt.Sprintf("%s: ", prompt)) 20 | reader := bufio.NewReader(os.Stdin) 21 | 22 | text, err := reader.ReadString('\n') 23 | if err != nil { 24 | return "", errors.WithStackTrace(err) 25 | } 26 | 27 | return strings.TrimSpace(text), nil 28 | } 29 | 30 | // Prompt the user for a yes/no response and return true if they entered yes. 31 | func PromptUserForYesNo(prompt string) (bool, error) { 32 | resp, err := PromptUserForInput(fmt.Sprintf("%s (y/n) ", prompt)) 33 | 34 | if err != nil { 35 | return false, errors.WithStackTrace(err) 36 | } 37 | 38 | switch strings.ToLower(resp) { 39 | case "y", "yes": 40 | return true, nil 41 | default: 42 | return false, nil 43 | } 44 | } 45 | 46 | // Clear the terminal screen in a cross-platform compatible manner 47 | func ClearTerminal() { 48 | screen.Clear() 49 | } 50 | -------------------------------------------------------------------------------- /util/shell.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "os" 5 | "os/exec" 6 | "strings" 7 | 8 | "github.com/gruntwork-io/boilerplate/errors" 9 | ) 10 | 11 | // Run the given shell command with the given environment variables and arguments in the given working directory 12 | func RunShellCommandAndGetOutput(workingDir string, envVars []string, command string, args ...string) (string, error) { 13 | Logger.Printf("Running command: %s %s", command, strings.Join(args, " ")) 14 | 15 | cmd := exec.Command(command, args...) 16 | 17 | cmd.Stdin = os.Stdin 18 | cmd.Stderr = os.Stderr 19 | cmd.Dir = workingDir 20 | cmd.Env = append(os.Environ(), envVars...) 21 | 22 | out, err := cmd.Output() 23 | if err != nil { 24 | return "", errors.WithStackTrace(err) 25 | } 26 | return string(out), nil 27 | } 28 | 29 | // Run the given shell command with the given environment variables and arguments in the given working directory 30 | func RunShellCommand(workingDir string, envVars []string, command string, args ...string) error { 31 | Logger.Printf("Running command: %s %s", command, strings.Join(args, " ")) 32 | 33 | cmd := exec.Command(command, args...) 34 | 35 | cmd.Stdin = os.Stdin 36 | cmd.Stderr = os.Stderr 37 | cmd.Stdout = os.Stdout 38 | cmd.Dir = workingDir 39 | cmd.Env = append(os.Environ(), envVars...) 40 | 41 | return cmd.Run() 42 | } 43 | -------------------------------------------------------------------------------- /variables/dependencies_test.go: -------------------------------------------------------------------------------- 1 | package variables 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestSplitIntoDependencyNameAndVariableName(t *testing.T) { 10 | t.Parallel() 11 | 12 | testCases := []struct { 13 | variableName string 14 | expectedDependencyName string 15 | expectedOriginalVariableName string 16 | }{ 17 | {"", "", ""}, 18 | {"foo", "", "foo"}, 19 | {"foo-bar baz_blah", "", "foo-bar baz_blah"}, 20 | {"foo.bar", "foo", "bar"}, 21 | {"foo.bar.baz", "foo", "bar.baz"}, 22 | } 23 | 24 | for _, testCase := range testCases { 25 | actualDependencyName, actualOriginalVariableName := SplitIntoDependencyNameAndVariableName(testCase.variableName) 26 | assert.Equal(t, testCase.expectedDependencyName, actualDependencyName, "Variable name: %s", testCase.variableName) 27 | assert.Equal(t, testCase.expectedOriginalVariableName, actualOriginalVariableName, "Variable name: %s", testCase.variableName) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /variables/engines_test.go: -------------------------------------------------------------------------------- 1 | package variables 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/gruntwork-io/boilerplate/errors" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestEnginesRequiresSupportedTemplateEngine(t *testing.T) { 12 | t.Parallel() 13 | 14 | testCases := []struct { 15 | name string 16 | typeStr string 17 | expectError bool 18 | }{ 19 | { 20 | name: "gotemplate", 21 | typeStr: string(GoTemplate), 22 | expectError: false, 23 | }, 24 | { 25 | name: "jsonnet", 26 | typeStr: string(Jsonnet), 27 | expectError: false, 28 | }, 29 | { 30 | name: "unsupported", 31 | typeStr: "dhall", 32 | expectError: true, 33 | }, 34 | } 35 | 36 | for _, tc := range testCases { 37 | // Capture range variable so it does not change across for loop iterations. 38 | tc := tc 39 | 40 | t.Run(tc.name, func(t *testing.T) { 41 | t.Parallel() 42 | 43 | mockFields := map[string]interface{}{ 44 | "engines": []interface{}{ 45 | map[interface{}]interface{}{ 46 | "path": fmt.Sprintf("foo.%s", tc.name), 47 | "template_engine": tc.typeStr, 48 | }, 49 | }, 50 | } 51 | _, err := UnmarshalEnginesFromBoilerplateConfigYaml(mockFields) 52 | if tc.expectError { 53 | assert.Error(t, err) 54 | underlyingErr := errors.Unwrap(err) 55 | _, hasType := underlyingErr.(InvalidTemplateEngineErr) 56 | assert.True(t, hasType) 57 | } else { 58 | assert.NoError(t, err) 59 | } 60 | }) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /variables/skip_files.go: -------------------------------------------------------------------------------- 1 | package variables 2 | 3 | import "github.com/gruntwork-io/boilerplate/errors" 4 | 5 | // A single skip_file entry, which is a file that (conditionally) should be excluded from the rendered output. 6 | type SkipFile struct { 7 | Path string 8 | NotPath string 9 | If string 10 | } 11 | 12 | // Implement the go-yaml marshaler interface so that the config can be marshaled into yaml. We use a custom marshaler 13 | // instead of defining the fields as tags so that we skip the attributes that are empty. 14 | func (skipFile SkipFile) MarshalYAML() (interface{}, error) { 15 | skipFileYml := map[string]interface{}{} 16 | if skipFile.Path != "" { 17 | skipFileYml["path"] = skipFile.Path 18 | } 19 | if skipFile.NotPath != "" { 20 | skipFileYml["not_path"] = skipFile.Path 21 | } 22 | if skipFile.If != "" { 23 | skipFileYml["if"] = skipFile.If 24 | } 25 | return skipFileYml, nil 26 | } 27 | 28 | // Given a list of key:value pairs read from a Boilerplate YAML config file of the format: 29 | // 30 | // skip_files: 31 | // - path: 32 | // if: 33 | // - path: 34 | // - not_path: 35 | // 36 | // convert to a list of SkipFile structs. 37 | func UnmarshalSkipFilesFromBoilerplateConfigYaml(fields map[string]interface{}) ([]SkipFile, error) { 38 | rawSkipFiles, err := unmarshalListOfFields(fields, "skip_files") 39 | if err != nil || rawSkipFiles == nil { 40 | return nil, err 41 | } 42 | 43 | skipFiles := []SkipFile{} 44 | 45 | for _, rawSkipFile := range rawSkipFiles { 46 | skipFile, err := unmarshalSkipFileFromBoilerplateConfigYaml(rawSkipFile) 47 | if err != nil { 48 | return nil, err 49 | } 50 | // We only return nil pointer when there is an error, so we can assume skipFile is non-nil at this point. 51 | skipFiles = append(skipFiles, *skipFile) 52 | } 53 | 54 | return skipFiles, nil 55 | } 56 | 57 | // Given key:value pairs read from a Boilerplate YAML config file of the format: 58 | // 59 | // path: 60 | // not_path: 61 | // if: 62 | // 63 | // This method unmarshals the YAML data into a SkipFile struct 64 | func unmarshalSkipFileFromBoilerplateConfigYaml(fields map[string]interface{}) (*SkipFile, error) { 65 | pathPtr, err := unmarshalStringField(fields, "path", false, "") 66 | if err != nil { 67 | return nil, err 68 | } 69 | path := "" 70 | if pathPtr != nil { 71 | path = *pathPtr 72 | } 73 | 74 | notPathPtr, err := unmarshalStringField(fields, "not_path", false, "") 75 | if err != nil { 76 | return nil, err 77 | } 78 | notPath := "" 79 | if notPathPtr != nil { 80 | notPath = *notPathPtr 81 | } 82 | 83 | // One of not_path or path must be set, so we check that here. 84 | if (notPath == "" && path == "") || (notPath != "" && path != "") { 85 | return nil, errors.WithStackTrace(MutexRequiredFieldErr{fields: []string{"path", "not_path"}}) 86 | } 87 | 88 | skipIfPtr, err := unmarshalStringField(fields, "if", false, path) 89 | if err != nil { 90 | return nil, err 91 | } 92 | skipIf := "" 93 | if skipIfPtr != nil { 94 | skipIf = *skipIfPtr 95 | } 96 | 97 | return &SkipFile{Path: path, NotPath: notPath, If: skipIf}, nil 98 | } 99 | -------------------------------------------------------------------------------- /variables/types.go: -------------------------------------------------------------------------------- 1 | package variables 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/gruntwork-io/boilerplate/errors" 7 | ) 8 | 9 | // An enum that represents the types we support for boilerplate variables 10 | type BoilerplateType string 11 | 12 | var ( 13 | String = BoilerplateType("string") 14 | Int = BoilerplateType("int") 15 | Float = BoilerplateType("float") 16 | Bool = BoilerplateType("bool") 17 | List = BoilerplateType("list") 18 | Map = BoilerplateType("map") 19 | Enum = BoilerplateType("enum") 20 | ) 21 | 22 | var ALL_BOILERPLATE_TYPES = []BoilerplateType{String, Int, Float, Bool, List, Map, Enum} 23 | var BOILERPLATE_TYPE_DEFAULT = String 24 | 25 | // Convert the given string to a BoilerplateType enum, or return an error if this is not a valid value for the 26 | // BoilerplateType enum 27 | func ParseBoilerplateType(str string) (*BoilerplateType, error) { 28 | for _, boilerplateType := range ALL_BOILERPLATE_TYPES { 29 | if boilerplateType.String() == str { 30 | return &boilerplateType, nil 31 | } 32 | } 33 | return nil, errors.WithStackTrace(InvalidBoilerplateType(str)) 34 | } 35 | 36 | // Return a string representation of this Type 37 | func (boilerplateType BoilerplateType) String() string { 38 | return string(boilerplateType) 39 | } 40 | 41 | type InvalidEntries struct { 42 | Issues []ValidationIssue 43 | } 44 | 45 | type ValidationIssue struct { 46 | Value interface{} 47 | ValidationMap map[string]bool 48 | } 49 | 50 | // Custom error types 51 | 52 | type InvalidBoilerplateType string 53 | 54 | func (err InvalidBoilerplateType) Error() string { 55 | return fmt.Sprintf("Invalid InvalidBoilerplateType '%s'. Value must be one of: %s", string(err), ALL_BOILERPLATE_TYPES) 56 | } 57 | -------------------------------------------------------------------------------- /variables/variables_test.go: -------------------------------------------------------------------------------- 1 | package variables 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestParseStringAsList(t *testing.T) { 10 | t.Parallel() 11 | 12 | testCases := []struct { 13 | testName string 14 | str string 15 | expectedList []string 16 | }{ 17 | {"empty-list", "[]", []string{}}, 18 | {"one-item", "[a]", []string{"a"}}, 19 | {"three-items", "[a b c]", []string{"a", "b", "c"}}, 20 | {"leading-trailing-whitespace", "[ a b c ]", []string{"a", "b", "c"}}, 21 | {"json-list-one-item", `["a"]`, []string{"a"}}, 22 | {"json-list-three-items", `["a", "b", "c"]`, []string{"a", "b", "c"}}, 23 | } 24 | 25 | for _, testCase := range testCases { 26 | t.Run(testCase.testName, func(t *testing.T) { 27 | actualList, err := parseStringAsList(testCase.str) 28 | assert.Nil(t, err, "Got unexpected error for string '%s': %v", testCase.str, err) 29 | assert.Equal(t, testCase.expectedList, actualList, "For string '%s'", testCase.str) 30 | }) 31 | } 32 | 33 | } 34 | 35 | func TestParseStringAsMap(t *testing.T) { 36 | t.Parallel() 37 | 38 | testCases := []struct { 39 | testName string 40 | str string 41 | expectedMap map[string]string 42 | }{ 43 | {"empty-map", "map[]", map[string]string{}}, 44 | {"one-item", "map[a:b]", map[string]string{"a": "b"}}, 45 | {"three-items", "map[a:b c:d e:f]", map[string]string{"a": "b", "c": "d", "e": "f"}}, 46 | {"multiple-colons", "map[a:b:c:d:e]", map[string]string{"a:b:c:d": "e"}}, 47 | {"leading-trailing-whitespace", "map[ a:b c:d e:f ]", map[string]string{"a": "b", "c": "d", "e": "f"}}, 48 | {"json-map-empty", `{}`, map[string]string{}}, 49 | {"json-map-one-item", `{"a": "b"}`, map[string]string{"a": "b"}}, 50 | {"json-map-three-items", `{"a": "b", "c": "d", "e": "f"}`, map[string]string{"a": "b", "c": "d", "e": "f"}}, 51 | } 52 | 53 | for _, testCase := range testCases { 54 | t.Run(testCase.testName, func(t *testing.T) { 55 | actualMap, err := parseStringAsMap(testCase.str) 56 | assert.Nil(t, err, "Got unexpected error for string '%s': %v", testCase.str, err) 57 | assert.Equal(t, testCase.expectedMap, actualMap, "For string '%s'", testCase.str) 58 | }) 59 | } 60 | 61 | } 62 | --------------------------------------------------------------------------------