SkillAgentSearch skills...

Variant2

Turn your bash scripts into a modern, single-executable CLI app today

Install / Use

/learn @mumoshu/Variant2
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Variant 2

This repository contains a development branch of the second major version of Variant.

See https://github.com/mumoshu/variant for more information on the first version.

Once finished, this repository will eventually take over the master branch of the original variant repository.

Features

  • HCL-based DSL: Terraform-like strongly-typed DSL on top of HCL to define your command. See Configuration Language below.
  • Concurrency and Workflow: Embedded workflow engine with concurrency. See Concurrency below. Example: concurrency
  • Auto-prompt: Variant prompts for missing arguments to your command so that your user is only needed to provide missing arguments on the fly, instead of rerunning the whole command by repeating every argument.
  • Configs: Deep-merging YAML configuration files. Example: config
  • Secrets: Deep-merging secret values from Vault, AWS SecretsManager, SOPS, etc. powered by vals. Example: secret
  • Testing: Test framework with go test-compatible test runner. Example: simple
  • Embeddable: Easy embedding in any Golang application
  • Easy distribution: Build a single-executable of your command with Golang
  • Dependency Management: Dependent files, executable binaries and docker-run shims can be automatically installed and updated with the variantdev/mod integration. Example: module
  • Run as a Kubernetes controller: You can easily turn your Variant command into a Kubernetes controller. See examples/controller
  • Integrations: Integrates nicely with Slack, GitHub. You can run Variant command in response to Slack message, GitHub issue comment, commit push, etc.

Getting Started

Create an variant file that contains the following:

examples/getting-started/getting-started.variant:

option "namespace" {
  description = "Namespace to interact with"
  type = string
  default = "default"
  short = "n"
}

job "kubectl" {
  parameter "dir" {
    type = string
  }

  exec {
    command = "kubectl"
    args = ["-n", opt.namespace, "-f", param.dir]
  }
}

job "helm" {
  parameter "release" {
    type = string
  }
  parameter "chart" {
    type = string
  }
  option "values" {
    type = list(string)
  }

  exec {
    command = "helm"
    args = ["upgrade", "--install", "-n", opt.namespace, param.release, param.chart]
  }
}

job "deploy" {
  description = "Deploys our application and the infrastructure onto the K8s cluster"

  step "deploy infra" {
    run "helm" {
      release = "app1"
      chart = "app1"
    }
  }

  step "deploy apps" {
    run "kubectl" {
      dir = "deploy/environments/${opt.env}/manifests"
    }
  }
}

Now you can run it with variant:

variant run -h will show you that all the jobs are available via sub-commands:

$ variant run -h
Usage:
  variant run [flags]
  variant run [command]

Available Commands:
  deploy
  helm
  kubectl

Flags:
  -h, --help               help for run
  -n, --namespace string   Namespace to interact with

Use "variant run [command] --help" for more information about a command.

And variant run deploy -h for the usage for the specific job = sub-command named deploy:

Deploys our application and the infrastructure onto the K8s cluster

Usage:
  variant run deploy [flags]

Flags:
  -h, --help   help for deploy

Global Flags:
  -n, --namespace string   Namespace to interact with

As you've seen in the help output, variant run deploy runs the deploy job, which in turn runs kubectl and helm to install your apps onto the K8s cluster:

$ variant run deploy

Once you're finished developing the command, let's build a single executable binary of the command for easy distribution:

$ variant export binary ./ build/myapp

The exported executable binary accepts the same arguments as variant run:

$ ./build/myapp -h

$ ./build/myapp run deploy

Congratulations! You're now ready to dive deep and solve your own problems with Variant.

Still curious how Variant helps developing your own command as it grows?

Head over to the following per-topic sections for more features:

Generating Shims

If you're distributing this command with your teammates, do use variant generate shim to create a shim to make it look like a native command:

$ variant generate shim examples/getting-started/
$ cat ./examples/getting-started/getting-started
#!/usr/bin/env variant

import = "."
$ ./examples/getting-started/getting-started
Usage:
  getting-started [flags]
  getting-started [command]

Available Commands:
  deploy      Deploys our application and the infrastructure onto the K8s cluster
  helm
  help        Help about any command
  kubectl

Flags:
  -h, --help               help for getting-started
  -n, --namespace string   Namespace to interact with

Use "getting-started [command] --help" for more information about a command.

Compiling Command

As we've covered in the Getting Started guide, variant export sub-commands can be used to export your command in various formats.

variant export binary SRC CMD generates an executable binary at the path CMD from your command defined under the directory SRC:

$ variant export binary ./ build/myapp

The exported executable binary accepts the same arguments as variant run. So myapp -h corresponds to cd $SRC; variant run -h, while myapp run deploy corresponds to cd $SRC; variant run deploy.

variant export go SRC/CMD PKG generates a directory at PKG/CMD that contains Go source files that can be built by running go build PKG/CMD.

Assuming you already have go installed, you can run variint export go src/myapp build, then edit code under build/myapp to make any customization that can't be done with shims, and finally build an executable with go build -o myapp ./build/myapp.

Running Command From Other Directory

Usually, when your command has been defined under the directory path/to/your/command, variant run requires you to chdir to it before running.

To be clear, cd $SRC; variant run can be used to run it from another directory. However with that you command cannot access the actual current directory, as you've already cded.

You can also use a shim or an exported binary to make it runnable from any directory. But it takes some time so probably you'd like to run it from any directory without a variant export step while developing?

The VARIANT_DIR environment variable might be the solution. When variant recognizes it, it reads the command from the directory specified by it.

Just run:

VARIANT_DIR=$SRC variant run

Your command can now be run without cd and still has access to the current directory.

Split, Merge and Import

Do you have a huge yourcmd.variant that needs to be split for readability?

path/to/yourcmd.variant:

job "foo" {
  # snip
}

job "bar" {
  # snip
}

job "baz" {
  # snip
}

Variant usually works per-directory basis. That is, it loads and merges all the .variant files in a directory to form a single command.

That is, you can just split the file into three .variant files in the same directory to split the huge file:

path/to/yourcmd_foo.variant:

job "foo" {
  parameter "param1" {
    # snip
  }

  # snip
}

path/to/yourcmd_bar.variant:

job "bar" {
  # snip
}

path/to/yourcmd_baz.variant:

job "baz" {
  # snip
}

Okay that works. But you ended up too many files in a single directory?

A "parent" variant file containing import or imports can be used to load all the *.variant files in the directory into the current job.

path/to/yourcmd.variant:

job "foo" {
  import = "./foo"
}

job "bar" {
  import = "./bar"
}

path/to/foo/foo.variant:

parameter "param1" {
  # snip
}

# snip

Note that imports is the newer variant of import that supports multiple sources to be imported.

Also, you can import following sources:

  • Relative path to local directory (A local path that doesn't start with /, like foo/bar)
  • Absolute path to local directory (An absolute path that starts with /, like `/variant/modules/example.co

Related Skills

View on GitHub
GitHub Stars148
CategoryDevelopment
Updated3mo ago
Forks11

Languages

Go

Security Score

92/100

Audited on Jan 5, 2026

No findings