├── .editorconfig ├── .github └── workflows │ └── example.yaml ├── .gitignore ├── .terraform.lock.hcl ├── LICENSE ├── README.md └── main.tf /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = tab 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.{tf,tfvars}] 12 | indent_style = space 13 | 14 | [*.yaml] 15 | indent_style = space 16 | -------------------------------------------------------------------------------- /.github/workflows/example.yaml: -------------------------------------------------------------------------------- 1 | name: Terraform provider cache example 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | main: 8 | name: Example 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout source 12 | uses: actions/checkout@v4 13 | - name: Setup Terraform 14 | uses: hashicorp/setup-terraform@v3 15 | with: 16 | terraform_version: 1.7.5 17 | - name: Configure Terraform plugin cache 18 | run: | 19 | echo "TF_PLUGIN_CACHE_DIR=$HOME/.terraform.d/plugin-cache" >>"$GITHUB_ENV" 20 | mkdir --parents "$HOME/.terraform.d/plugin-cache" 21 | - name: Cache Terraform 22 | uses: actions/cache@v4 23 | with: 24 | path: | 25 | ~/.terraform.d/plugin-cache 26 | key: terraform-${{ runner.os }}-${{ hashFiles('**/.terraform.lock.hcl') }} 27 | restore-keys: | 28 | terraform-${{ runner.os }}- 29 | - name: Init Terraform configuration 30 | run: | 31 | terraform init 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.terraform/ 2 | -------------------------------------------------------------------------------- /.terraform.lock.hcl: -------------------------------------------------------------------------------- 1 | # This file is maintained automatically by "terraform init". 2 | # Manual edits may be lost in future updates. 3 | 4 | provider "registry.terraform.io/hashicorp/aws" { 5 | version = "5.38.0" 6 | constraints = "~> 5.38.0" 7 | hashes = [ 8 | "h1:axFddT4mkdtZREgkDXwXdzZGm1qxheF0fLN7S7bJJX4=", 9 | "h1:idoY48RPD1LeRvsaPlLUtEbxU061bbGwGJb2TBoHYrM=", 10 | "h1:v82ZV2gf8xI4mFPi/xc377ilZKfnORPPAYyXMKBqAxo=", 11 | "zh:0d58264440fd28b6729990b48d8fd61e732f5570689d17bbbc0c5f2324d3dd00", 12 | "zh:175e24a3d399495fc91da359cc30a9fe06b7eeb98804816abcf1493859f6d28e", 13 | "zh:244a1f56d6710cc1a643f602a185b46d3cd064f6df60330006f92ab32f3ff60c", 14 | "zh:30dd99413867b1be808b656551a2f0452e4e37787f963780c51f1f85bf406441", 15 | "zh:3629d4e212c8ffd8e74c4ab9e9d22ca7fff803052366d011c014591fa65beb48", 16 | "zh:521badb184bbdde5dddb1228f7a241997db52ea51c9f8039ed5a626362952cf4", 17 | "zh:5580a937e1f5fa59c16c4b9802079aa45a16c7c69e5b7d4e97aebf2c0fb4bd00", 18 | "zh:87b801057d492ff0adc82ce6251871d87bdf5890749fe5753f447ec6fe4710ff", 19 | "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", 20 | "zh:9c44e0c143f1d021440e9c448a9bc595f51a95e6cc382fcffe9db6d3b17f24c2", 21 | "zh:b7e6b7b182932a3dbb6ca5f8ebb8d37befe1456f3dffaafb37cee07dc0473696", 22 | "zh:d43fcf4f59cf79b1be3bec164d95fe9edc3fe39195a83226b911918a6538c8b3", 23 | "zh:ec3e383ce1e414f0bd7d3fe73409ff7d2777a5da27248b70fd5df1df323d920b", 24 | "zh:f729b443179bb115bbcbb0369fe46640de1c6dbd627b52694e9b3b8a41ec7881", 25 | "zh:fd532b707746145d3c6d3507bca2b8d44cc618b3d5006db99426221b71db7da7", 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Peter Mescalchin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Terraform GitHub Actions caching example 2 | 3 | [![Terraform provider cache example](https://github.com/magnetikonline/terraform-github-action-cache-example/actions/workflows/example.yaml/badge.svg)](https://github.com/magnetikonline/terraform-github-action-cache-example/actions/workflows/example.yaml) 4 | 5 | ## Summary 6 | 7 | An implementation of caching [Terraform providers](https://developer.hashicorp.com/terraform/language/providers) via [`actions/cache`](https://github.com/actions/cache) within a workflow run in an attempt to improve `terraform init|plan|apply` execution times. 8 | 9 | Why? 10 | 11 | - Providers are external to Terraform itself and require download during `terraform init` operations. 12 | - Common use providers can often be very large in size. For example, the [AWS Provider](https://registry.terraform.io/providers/hashicorp/aws/latest/docs) at time of writing weighs in around `360MB` uncompressed. 13 | - By caching these provider binaries between GitHub Action runs, we hope to have required configuration providers available to `terraform` sooner! 14 | 15 | ## Example 16 | 17 | See: [`.github/workflows/example.yaml`](.github/workflows/example.yaml) 18 | 19 | Breakdown of the key workflow steps: 20 | 21 | - Git source is fetched and Terraform setup via [`actions/checkout`](https://github.com/actions/checkout) and [`hashicorp/setup-terraform`](https://github.com/hashicorp/setup-terraform) respectively. 22 | - Terraform plugin (provider) cache path is configured: 23 | - By default Terraform downloads providers to individual `.terraform/` directories alongside a configuration. By enabling a system wide cache, `terraform` downloads each provider _once_ to a central location and symlink back into each `.terraform/` directory - avoiding repeated downloads. [More details here](https://developer.hashicorp.com/terraform/cli/config/config-file#provider-plugin-cache). 24 | - The plugin cache path is set via the [`TF_PLUGIN_CACHE_DIR`](https://developer.hashicorp.com/terraform/cli/config/environment-variables#tf_plugin_cache_dir) environment variable. 25 | - With a global plugin cache location enabled, we've now got the perfect candidate for workflow run caching. 26 | - Finally, [`actions/cache`](https://github.com/actions/cache) is setup to save/restore the plugin cache location we've set at `~/.terraform.d/plugin-cache`. The cache key is composed using a hash of dependency lock files (`.terraform.lock.hcl`), introduced in [Terraform 0.14](https://developer.hashicorp.com/terraform/language/files/dependency-lock). 27 | 28 | Configuration lock file can be created/updated via the following: 29 | 30 | ```sh 31 | $ terraform providers lock -platform=darwin_amd64 -platform=darwin_arm64 -platform=linux_amd64 32 | ``` 33 | 34 | - Finally a `terraform init` is run, which sets up a trivial Terraform configuration of [`main.tf`](main.tf). 35 | -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.7.5" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws", 7 | version = "~> 5.38.0", 8 | } 9 | } 10 | } 11 | --------------------------------------------------------------------------------