Terramate ❤️ Zsh

Terramate ❤️ Zsh

10 Useful Aliases and Functions for Terramate and Zsh Users

Terramate is an amazing tool to enhance your Terraform experience. However, there is a way to make it even more handy for everyday use.

Solve annoying things

1. Too long to type

Obvious one: terraform and terramate commands are too long to type :)

Use aliases:

# ~/.zshrc
alias tf="terraform "
alias tm="terramate "
alias tmg="terramate generate "

You still have to type terraform after tm run because tm knows nothing about your aliases. But it will be solved below too.

2. Command chaining

Often, to execute a Terraform command, you need to run a preceding command. For example, before tf init, you should run tm generate. Similarly, before plan, you might need to run init, and so on.

You could use Makefiles or the terramate script run feature that comes with Terramate to handle command chaining. However, this only addresses the issue of chaining commands. Plus, you'd have to add these configurations to every repository you work with.

And it's still too much typing. You'll likely resort to using aliases anyway. So, why not start with shell configuration right from the start?

Zsh functions can help:

# ~/.zshrc
function tmi () {
  terramate generate && \
  terramate run terraform init $@
}
function tmp () {
  tmi $1 && \
  terramate run terraform plan -out=tfplan $@
}

3. Tags for stacks

Tags are a fantastic feature of Terramate, especially if you're managing many stacks. They allow all tm run commands to be executed in stack directories selected by tags. However, their usability could be better—you always need to type them somewhere in the middle of a tm command.

For example, if you want to check the plan for the dev environment and then for the stage environment:

terramate run --tags=mngt:dev terraform plan
terramate run --tags=mngt:stage terraform plan

To create the last command, you can use a sequence of keys like this before typing stage: up, option+left, option+left, left, esc, backspace.

Make functions smarter:

# ~/.zshrc
function tmi () {
  terramate generate && \
  terramate run --tags=$1 terraform init ${@:2}
}
function tmp () {
  tmi $1 && \
  terramate run --tags=$1 terraform plan -out=tfplan ${@:2}
}

Now, you have fewer steps before you start typing stage: up, esc, backspace.

Additionally, you can specify plan options as the second or later arguments thanks to ${@:2} in the function.

4. Not sure about what you've typed?

Print the command before executing it:

# ~/.zshrc
function tmr () {
  print -z "terramate run --tags=$@ "
}

So tmr dev:asd ls + enter will lead to terramate run --tags=dev:asd ls in the command line.

Let's put it all together

# ~/.zshrc
alias tf="terraform "
alias tm="terramate "
alias tmg="terramate generate "
function tmi () {
  terramate generate && \
  terramate run --tags=$1 terraform init ${@:2}
}
function tmv () {
  tmi $1 && \
  terramate run --tags=$1 terraform validate ${@:2}
}
function tmp () {
  tmi $1 && \
  terramate run --tags=$1 terraform plan -out=tfplan ${@:2}
}
function tma () {
  print -z "terramate run --tags=$1 terraform apply tfplan ${@:2}"
}
function tmpl () {
  tmi $1 && \
  terramate run --tags=$1 terraform providers lock -platform=linux_amd64 -platform=darwin_amd64 -platform=darwin_arm64 ${@:2}
}
function tmc () {
  tmi $1 && \
  terramate run --tags=$1 terraform console ${@:2}
}
function tmr () {
  print -z "terramate run --tags=$@ "
}

Usage

Examples

tmi admin        # will run `terramate run --tags=admin terraform init`
tmp dev:infra    # will run `terramate run --tags=dev:infra terraform plan -out=tfplan`
tmr admin        # will print `terramate run --tags=admin` in prompt so you can run any command in the admin stack dir
tmr admin ls -la # will print `terramate run --tags=admin ls -la` in prompt, press 'enter' to execute `ls -la` in the admin stack dir or append more args

Shortcuts description

CommandAction
tfterraform
tmterramate
tmgterramate generate
tmi <TAGS> [ARGS]tm generate => tf init [ARGS]
tmv <TAGS> [ARGS]tm generate => tf init => tf validate [ARGS]
tmp <TAGS> [ARGS]tm generate => tf init => tf plan -out=tfplan [ARGS]
tma <TAGS> [ARGS]tf apply tfplan [ARGS]
tmpl <TAGS> [ARGS]tm generate => tf init => tf providers lock -platform=linux_amd64 -platform=darwin_amd64 -platform=darwin_arm64 [ARGS]
tml <TAGS> [ARGS]tm generate => tf init => tf console [ARGS]
tmc <TAGS> [ARGS]aws sso login [ARGS]
tmr <TAGS> <CMD> [ARGS]terramate run --tags=<TAGS> <CMD> [ARGS]

Bonus

Use different environment variable values for different stacks.

For example, if stacks use different AWS accounts, place the account name in the stack's globals and add it to your repository's root tm-file.

# repo root terramate.tm
terramate {
  config {
    run {
      env {
        AWS_PROFILE = "${global.aws_profile}"
      }
    }
  }
}

tmr aws aws sso login FTW 🤟