goliatone / go-envset

run commands in an environment defined using a ini configuration file.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

envset

envset run commands in an environment defined using a ini configuration file.



Environment level configuration

Application configuration is (usually) specific to an environment and will change between different build environments- e.g. app secrets for a staging environment are different than your production secrets.

The 12 factor app guidelines suggest you store your application's configuration in the environment.

Environment variables enable us to manage application configuration outside of our application code.

Application configuration usually are small and sensitive data such as API keys or tokens, database credentials, etc. However not all environment configuration have to be secrets, there might be build distribution specific values such as the application's base URL to build OAuth callbacks, a dependent service endpoint or anything that changes between development and production environments.

envset helps you manage environment variables for multiple build environments.

The following command will run a Node.js application with a development environment:

$ envset development -- node server.js

envset will load the variables defined in the [development] section of a local .envset file and execute the command after the --.

See the examples section for more details.

Similar Tools

Inspired by daemontools' tool envdir and tools such as dotenv.

  • Distributed as a single binary
  • No dependencies in your codebase
    • e.g. dotenv-rails and dotenv1 for Node.js require you to use a library
  • Support multiple environments in a single file
  • Generates an example file with your current env vars to keep documentation updated.
  • Interpolation of variable using POSIX variable expansion.
  • Command expansion
  • Define required variables and exit with error if not set
  • By default the shell environment is not loaded in the context

Instead of having an .env file per environment you can have one single .envset file with one section per environment.

1: You an actually require the library outside of your project with the node -r flag.

Examples

Executing A Command

An .envset file could look like this:

[development]
APP_SECRET_TOKEN=4c038a0b-4ed9-44e6-8682-9c82d5b831fd
APP_REMOTE_SERVICE_KEY=07ed716a-078a-4327-8847-b86394f14575

[production]
APP_SECRET_TOKEN=796bca0f-2692-495b-a994-e8ce82cad55f
APP_REMOTE_SERVICE_KEY=5655969e-af9f-4ac5-b186-184f43468443

To use it, simply prefix the call to your program with envset and the name of the environment section. The node app.js will be running with the environment variables specified in the development section of the .envset file.

$ envset development -- node app.js

Restart Command

envset will optionally restart your command if it exits with an error code. There are three flags you can use to manage the restart behavior:

  • --restart: Restart command on exit error, default to true.
  • --max-restarts [int]: Max times to restart command, defaults to 3.
  • --forever: If present restart the command for as long as envset is running.

All these can be configured using an .envsetrc file.

This will restart the node app for a maximum of --max-restarts.

$ envset development --restart --max-restarts 10 -- node app.js

Variable Substitution

You can execute commands that use environment variables in the command arguments.

Is important to note that you need to scape the variable so that it is not replaced in the shell as you call envset. You can do so by using single quotes ' or the scape char \$.

$ envset development -- say '${APP_ENV}'
$ envset development -- say \${APP_ENV}

Inherit Environment

Sometimes the command you want to run will assume that has access to predefined environment variables:

$ envset development -- spd-say '${APP_ENV}'
Failed to connect to Speech Dispatcher:
Error: Can't connect to unix socket ~/.cache/speech-dispatcher/speechd.sock: No such file or directory. Autospawn: Autospawn failed. Speech Dispatcher refused to start with error code, stating this as a reason:
exit status 1

By default the process in which envset runs spd-say in an isolated mode has no access to your shell.

You can control environment inheritance using two flags:

  • --isolated: Inherit all parent environment variables
  • --inherit: Inherit specific parent environment variables

If you need the executed command to inherit the host's environment wholesale use the --isolated=false flag.

$ envset development --isolated=false -- spd-say '${APP_ENV}'

Some commands might rely on a known environment variable set on your shell, for instance if you want to go run:

$ envset development -- go run cmd/app/server.go
missing $GOPATH

You will get an error saying that $GOPATH is not available. The --inherit flag lets you specify a list of environment variable keys that will be inherited from the parent environment:

$ envset development -I=GOPATH -I=HOME -- go run cmd/app/server.go

Overwriting Variables At Runtime

You can overwrite environment variables without editing your .envset file.

APP_NAME="New Name" envset development --isolated=false -- spd-say '${APP_NAME}'

Load Env File To Current Shell Session

If you want to make the variables defined in a env file to your running shell session use something like the following snippet.

$ eval $(envset development)

Required Environment Variables

You can specify a list of required environment variables for your command using the --required flag or its -R alias.

Given the following env file:

[development]
APP_SECRET_TOKEN={{APP_SECRET_TOKEN}}
APP_REMOTE_SERVICE_KEY={{APP_REMOTE_SERVICE_KEY}}

If you run the following command:

$ envset development --required=BOOM -R BOOM2 -- node index.js

envset will exit with an error and a message with the missing variables:

missing required keys: BOOM,BOOM2

Generating An Example Template

If we run the envset template command with the previous .envset file we generate a envset.example file:

[development]
APP_SECRET_TOKEN={{APP_SECRET_TOKEN}}
APP_REMOTE_SERVICE_KEY={{APP_REMOTE_SERVICE_KEY}}

[production]
APP_SECRET_TOKEN={{APP_SECRET_TOKEN}}
APP_REMOTE_SERVICE_KEY={{APP_REMOTE_SERVICE_KEY}}

Support For .env Files

You can load other environment files like .env files:

$ envset --env-file=.env -- node index.js

Metadata

The metadata command will generate a JSON file capturing the values of the provided env file.

Metadata Compare

Note that envset metadata compare will output to stderr in the case that both files do not match.

$ envset metadata compare --section=development .meta/data.json .meta/prod.data.json

You can omit the path to the local source metadata file and only pass the remote file you want to compare against, it will use the configured path:

$ envset metadata compare --section=development .meta/prod.data.json

Pretty output

β€’  source: .meta/data.json
   STATUS       ENV KEY         HASH
πŸ‘» Missing      MY_APP_NAME     6d22b97ab7dd...


β€’ target: .meta/env.staging.json
πŸ‘ target has no extra environment variables

β€’  different values
   STATUS       ENV KEY         HASH
❓ Different    APP_ENV         2e9975854897...
❓ Different    NEW_THING       8896f09440c1...


πŸ‘» Missing in source (1) | 🌱 Missing in target (1)

❓ Different values (2)  | 🀷 Ignored Keys (0)

To have JSON output you can pass the --json flag:

$ envset metadata compare --json -s development .meta/data.json .meta/prod.json
{
  "name": "development",
  "values": [
    {
      "key": "MY_APP_SECRET",
      "hash": "aca50d5cf2f285a5a5c5469c8fe9df2540b9bea6905a23461b",
      "comment": "different hash value"
    },
    {
      "key": "MY_APP_NAME",
      "hash": "6d22b97ab7dd929f1b30099dcacd3a8f883373cefbe4a59a05",
      "comment": "missing in source"
    }
  ]
}

Ignore Variables

When comparing metadata files you can optionally ignore some variables that you know will be different or will be missing. You can do pass --ignore or -I flag with the variable name:

$ envset metadata compare --section=development -I IGNORED_VAR .meta/prod.data.json

Installation

macOS

Add tap to brew:

$ brew tap goliatone/homebrew-tap

Install envset:

$ brew install envset

Ubuntu/Debian x86_64 - amd64

$ export tag=<version>
$ cd /tmp
$ wget https://github.com/goliatone/go-envset/releases/download/v${tag}/envset_${tag}_linux_x86_64.deb
$ sudo dpkg -i envset_${tag}_linux_x86_64.deb

CentOS/Redhat x86_64 - amd64

$ yum localinstall https://github.com/goliatone/go-envset/releases/download/v<version>/envset_<version>_linux_x86_64.rpm

Manual Install x86_64 - amd64

$ wget https://github.com/goliatone/go-envset/releases/download/v<version>/envset_<version>_linux_x86_64.tar.gz
$ tar -C /usr/bin/ -xzvf envset_<version>_linux_x86_64.tar.gz envset
$ chmod +x /usr/bin/envset

Documentation

envset will look for a file defining different environments and make them available as commands.

[development]
APP_BASE_URL=https://localhost:3003

[production]
APP_BASE_URL=https://envset.sh

Your .envset files can have global variables that you are not part of any section but can be used to do string interpolation in section's variable values.

The syntax to interpolate is %(KEY)s.

VERSION=v0.6.2

[development]
APP_BASE_URL=https://localhost:3003
DOWNLOAD_URL=%(APP_BASE_URL)s/%(VERSION)s

[production]
APP_BASE_URL=https://envset.sh
DOWNLOAD_URL=%(APP_BASE_URL)s/%(VERSION)s

You can have a special section with comments and the content will not generate syntax errors.

Commands

The following is a list of the available commands:

  • metadata
    • compare
  • template

Variable Expansion

envset can interpolate variables using POSIX variable expansion in both the loaded environment file and the running command arguments.

[development]
CLIENT_NAME=$(whoami -f)
CLIENT_ID=${CLIENT_NAME}.devices.local
$ envset development -- node cli.js --user '${USER}'

Commands

If you type envset without arguments it will display help and a list of supported environment names.

.envset File

.envsetrc

You can create an .envsetrc file with configuration options for envset.

The default .envsetrc looks like this:

# Default configuration
filename=.envset
expand=true
isolated=true
export_environment=APP_ENV
restart=true
max_restarts=3
restart_forever=false

[metadata]
dir=.meta
file=data.json
print=true
json=false

[template]
dir=.
file=envset.example

[environments]
name=test
name=staging
name=production
name=development

[comments]
key=COMMENTS
key=DOCUMENTATION

Configuration

Follows rc standards.

Configuration Syntax

The loaded files need to be valid ini syntax.

[development]
APP_BASE_URL=https://localhost:3003

[production]
APP_BASE_URL=https://envset.sh

Ignored And Required Sections

You can add a [required] or [ignored] section in your .envsetrc:

[ignored]
development=MY_APP_NAME
development=MY_APP_SECRET
staging=MY_IGNORED_STAGING

[required]
development=MY_REQUIRED_APP_NAME
staging=MY_REQUIRED_VAR_STAGING

License

Copyright (c) 2015 goliatone Licensed under the MIT license.

About

run commands in an environment defined using a ini configuration file.

License:MIT License


Languages

Language:Go 90.3%Language:Shell 9.7%