Automate terraform modules versioning with GitHub actions

Automate terraform modules versioning with GitHub actions

Like most engineers out there, we try to focus as much as possible on automation. One of those ways is using modules when working with Terraform.

But sometimes, finding an efficient way to release and distribute those can present a challenge.

Therefore after some time of experimenting, I have a solution that might come in handy for those of you working with Github & Terraform.

Our focus will be set around Github Actions, and If you have not yet heard of them, then I recommend you check out the following link https://github.com/features/actions

The flow we will be implementing today can be shows from high level overview as follow:


While working with Terraform modules it became apparent that after committing the code, it usually boiled down to several actions that needed to be executed for a complete modification of a Terraform module. Those actions were:

 

    • Running terraform checks ( before merging a PR )

    • updating the documentation

    • finding out next semver for the module

    • tagging the module ( or creating a release )

Based on those, our Raftech engineers created Github Actions workflows that use several actions to automate the above. This of course is only one way of many out there that support achieving this goal.


Checks

For every PR action, we run a set of checks. In our case, we decided we need to make sure base modules files are present, labels for semver are added, labels defining the purpose of the PR, and lastly that the code goes through pre-commit validations

Our resulting workflow in Github has the following content:

name: ci-checks-tf

on:
  pull_request:
    types: [opened, reopened, synchronize, labeled, unlabeled]

permissions:
  id-token: write
  contents: write
  pull-requests: write


jobs:
  pre-commit:
    runs-on: ubuntu-latest
    container: ghcr.io/antonbabenko/pre-commit-terraform:v1.79.1
    steps:
      - uses: actions/checkout@v3
      
      - name: 'pre-commit::add-github-repo-safe'
        run: |
          git config --global --add safe.directory $GITHUB_WORKSPACE     

      - name: 'pre-commit::run-all-checks'
        run: |
          pre-commit run -a --show-diff-on-failure -v

  module-required-files:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: 'tf-module::check-required-files'
        id: check_files
        uses: andstor/file-existence-action@v2
        with:
          files: "variables.tf, main.tf, README.md, versions.tf"
          fail: true

  label-required-semver:
    runs-on: ubuntu-latest
    steps:
      - name: 'pr::check-required-semver'
        uses: docker://agilepathway/pull-request-label-checker:latest
        with:
          prefix_mode: true
          one_of: "release/" # patch , minor , major
          repo_token: ${{ secrets.GITHUB_TOKEN }}

  label-required-pr-type:
    runs-on: ubuntu-latest
    steps:
      - name: 'pr::check-required-pr-type'
        uses: docker://agilepathway/pull-request-label-checker:latest
        with:
          any_of: bug,enhancement,documentation,security
          repo_token: ${{ secrets.GITHUB_TOKEN }}

  label-do-not-merge:
    runs-on: ubuntu-latest
    steps:
      - name: 'pr::check-required-semver'
        uses: docker://agilepathway/pull-request-label-checker:latest
        with:
          none_of: do-not-merge
          repo_token: ${{ secrets.GITHUB_TOKEN }}

To make sure these checks are mandatory – we set them up as required in the branch protection rules against the main/master branch.

With these checks being required you will have on every PR in your modules repositories the checks doing the work of making sure your baseline for delivering of terraform modules are followed


Release a new version

Once all of our checks have passed and our code is up to our requirements, we can create a new release. Of course, we want to have it done in a completely automated way – therefore we added one more action which will act upon a closed PR event. It will then automatically find the release label we use ( release/patch ; release/minor or release/major ) and use that information to bump our semver tag.

Once that is completed it will go ahead and create the final item – release.

name: v1-func-create-tag-and-release

on:
  pull_request:
    types: [closed]

jobs:
  create-new-release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions-ecosystem/action-release-label@v1
        id: release-label
        if: ${{ github.event.pull_request.merged == true }}

      - uses: actions-ecosystem/action-get-latest-tag@v1
        id: get-latest-tag
        if: ${{ steps.release-label.outputs.level != null }}

      - uses: actions-ecosystem/action-bump-semver@v1
        id: bump-semver
        if: ${{ steps.release-label.outputs.level != null }}
        with:
          current_version: ${{ steps.get-latest-tag.outputs.tag }}
          level: ${{ steps.release-label.outputs.level }}

      - uses: actions-ecosystem/action-push-tag@v1
        if: ${{ steps.release-label.outputs.level != null }}
        with:
          tag: ${{ steps.bump-semver.outputs.new_version }}
          message: '${{ steps.bump-semver.outputs.new_version }}: PR #${{ github.event.pull_request.number }} ${{ github.event.pull_request.title }}'

      - name: 'gh::release'
        if: ${{ steps.release-label.outputs.level != null }}      
        uses: softprops/action-gh-release@v1    
        with:
          tag_name: ${{ steps.bump-semver.outputs.new_version }}   
          

Once the last step is completed you will see the release on the repository page


Summary

Once the action completes its run you have made sure your code runs through your checks , have been tagged and a release have been created! At Raftech we believe that is the way you want to do your job 🙂 automated !

Related Posts
Leave a Reply

Your email address will not be published.Required fields are marked *