Terraform plan in Pull Requests with Google Cloud Build
By: Peter Malina
Tags: Cloud Build, Github, Google Cloud, Terraform

Running Terraform locally just to review a pull request always was a bit of a pain in the ass. Good thing is, there are some nice people running projects like Atlantis and if you host them by yourself or use Spacelift, you’re good to go.

I just always felt like it’s a bit too much work to manage Atlantis just to run plans and applies. Instead, I deep dived into Cloud Build and tried to replicate the same idea, but in a serverless way.

PR Comments were a Problem

At the time I was trying to stitch all the components together, there was a missing component: containerized cloud builder for Github CLI. Yup, Github has a new CLI, that lets you post comments on PRs. How cool is that?

So I contributed the Github CLI builder into the cloud-builders-community in PR#469 (by the time you are reading this, it may be in master, but if not, just feel free to use the branch).

> I’ll update the script below once the builder is in master



gcloud builds submit --config=cloudbuild.yaml . git clone https://github.com/petomalina/cloud-builders-community.git && cd cloud-builders-community/githubgcloud builds submit --config=cloudbuild.yaml .

The script installs the Github builder into your Google Cloud project. In case you are missing the terraform, just cd ../terraform and submit the build in the same way.

Planning Terraform inside Cloud Build

First, we’ll want to use the terraform builder to initialize and plan the changes. Make sure your Cloud Build service account has enough rights to do whatever you require in the terraform.

steps:

- name: 'gcr.io/$PROJECT_ID/terraform'

args: [

'init'

]

- name: 'gcr.io/$PROJECT_ID/terraform'

entrypoint: 'bash'

args: [

'-c',

'terraform plan -no-color > plan.txt'

]

The second step puts its output into a file called plan.txt . Files in the /workspace directory are preserved between steps, making it available in the next steps.

Providing a Github Token

The next step is to provide a Github token for our CLI. We can generate one navigating into settings/Developer Settings/Personal Access Tokens. The token will need to have the following rights:

repo so it can read from your private repositories and write comments

so it can read from your private repositories and write comments org:read in case you are using this for an organization

Once your token is created, copy it, and create a new secret inside your project's Secret Manager. You can call the secret github-personal-token .

Creating a Secret inside the Secret Manager

Posting the Plan into a Github PR

To post a comment with the plan results, we will need to Create a Trigger for Pull Request events, connected to your terraform repository. Afterward, we will add two more steps to our cloudbuild.yaml . These steps will get the Github Token and use it in the Github builder to post the comment.

First, let’s create our trigger. Put it on the Pull Request event and connect your repository like on an example below. You can also enable the Comment Control in case you want the triggers to be manual only for collaborators or owners (to make sure you don’t execute plans on pre-approved PRs).

Creating a new Terraform plan trigger

Second, we’ll update our build configuration. The added steps do the following:

Get the Github Token from the Secret Manager so we can pass it as an authorization to our Github builder

Use the Github builder to comment the plan into a foldable code in the PR

- name: gcr.io/cloud-builders/gcloud

entrypoint: 'bash'

args: [

'-c',

"gcloud secrets versions access latest --secret=github-personal-token --format='get(payload.data)' | tr '_-' '/+' | base64 -d > token.txt"

]

- name: 'gcr.io/$PROJECT_ID/github'

entrypoint: 'bash'

args:

- '-c'

- |-

read -r -d "" gh_comment_template << EOF

<details>

<summary>Terraform Plan Results</summary>



\`\`\`

%s

\`\`\`

</details>

EOF



gh_comment=$(printf "$$gh_comment_template" "$(cat plan.txt)")

/usr/bin/gh.bash pr review $_PR_NUMBER -R $_GITHUB_USER/$REPO_NAME -c -b "$$gh_comment"

The second step may seem a bit too much, however, it makes the comment folded. Running the trigger multiple times won’t create infinite scroll PRs with terraform plans.

Folded terraform plan results in a Pull Request