# Terramate ❤️ Zsh

[Terramate](https://github.com/terramate-io/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:

```bash
# ~/.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:

```bash
# ~/.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:

```bash
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:

```bash
# ~/.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:

```bash
# ~/.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

```bash
# ~/.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

```bash
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

| Command | Action |
| --- | --- |
| `tf` | `terraform` |
| `tm` | `terramate` |
| `tmg` | `terramate generate` |
| `tmi <TAGS>` \[ARGS\] | `tm generate` =&gt; `tf init [ARGS]` |
| `tmv <TAGS>` \[ARGS\] | `tm generate` =&gt; `tf init` =&gt; `tf validate [ARGS]` |
| `tmp <TAGS>` \[ARGS\] | `tm generate` =&gt; `tf init` =&gt; `tf plan -out=tfplan [ARGS]` |
| `tma <TAGS>` \[ARGS\] | `tf apply tfplan [ARGS]` |
| `tmpl <TAGS>` \[ARGS\] | `tm generate` =&gt; `tf init` =&gt; `tf providers lock -platform=linux_amd64 -platform=darwin_amd64 -platform=darwin_arm64 [ARGS]` |
| `tml <TAGS>` \[ARGS\] | `tm generate` =&gt; `tf init` =&gt; `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.

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

`tmr aws aws sso login` FTW 🤟
