npm package: @nurturejs/cli
Description: NurtureJS CLI - a tool for generating your environment by generating a .env from different sources you provide (e.g. files, AWS)
Latest version: 0.1.0

# Nurturejs

A self-documenting environment generation tool for JS applications with mixed local and external sources (e.g. AWS).

_Nurture your environment and let it grow_

## What is Nurture JS?

Welcome to Nurture JS, an opinionated environment building system for JS

Nurture JS is a tool for setting up your application's environment. It does this by building a .env for you. All of your environmental config is placed in a single file - `environment.json` - in your project root. Based on details provided in the file, Nurture JS will build the right .env file for the environment you specified, fetching any variables you need along the way from 3rd parties or cloud providers.

## What is the rationale for Nurture JS?

If you've ever built a JS application, you'll be aware that setting up an environment for your application to run within can be quite painful. There are lots of good libraries for simple cases (e.g. `env-cmd`, `config`), but for more fully fledged applications requiring complicated setups, async variables and needing to run both locally and with CI/CD, there are no real tools that solve all of these problems.

Nurture JS tries to solve this. We do this by being opinionated about what constitutes a good way of setting up an environment. We believe:

- New people to a project shouldn't need to go and find someone to give them the right set up for their system
- Your application should be self documenting in how the environment works, so nobody has to scratch their head confusingly or go find the one CI/CD person who understand how it all works
- Async and sync config should be handled in the same way and outside of applications

We do this by generating your environment before your application runs. We generate a .env file beforehand because:

- Virtually every tool supports a .env file. This means that no matter what new tool you add to your build or deploy chain, they all get a consistent configuration. (And for the tiny fraction that don't even use .env commands, you are covered by the following shell command: `export $(cat .env | sed 's/#.*//g' | xargs)`).
- Generating your .env beforhand means there's no async set-up necessary in your application or build tools, which is good as not all tools support async setup.

If you agree with that approach, then Nurture JS is for you.

## Quick Start

Create an `environment.json` which lays out how to generate your environment.

Example:

```json
{
  "plugins": ["@nurture/aws-plugin"],
  "aws": {
    "dev": {
      "profile": "aws-dev-profile"
    },
    "prod": {
      "profile": "aws-prod-profile"
    },
  },
  "config": {
    "dev": {
      "CONFIG_VAR": "development"
    },
    "prod": {
      "CONFIG_VAR": "production"
    }
  },
  "variables": [
    {
      "name": "STATIC_VAR",
      "description": "A variable that you always set tot he same thing",
      "value": "I am set!"
    },
    {
      "name": "CONFIG_VAR",
      "description": "An environment variable you set from a config entry in this file that will be development in the dev environment and production in the prod environment",
      "source" "config"
    },
    {
      "name": "ENVIRONMENT_VAR",
      "description": "An environment variable forwarded on from the environment (and maybe remapped) which we document here.  Here we load $FROM_THE_ENVIRONMENT into this variable.  You can neglect the key if you just want to use the name.",
      "source": "environment",
      "key": "FROM_THE_ENVIRONMENT"
    },
    {
      "name": "AWS_VAR",
      "description": "A variable from a 3rd party provider, in this case the AWS SSM Paramter store, which uses the aws key above to configure where it should fetch its data from.  In this case, the dev environment uses aws-dev-profile",
      "source": "aws",
      "source_input": "/path/to/my/ssm/paramater"
    },
    {
      "name": "MULTIPLE_SOURCE_VAR",
      "description": "A variable from a 3rd party provider which you may wish to fetch if you don't have it provided by another means first (e.g. the envrionment).  Useful for variables from githosts which have integrated CI/CD pipelines such as Gitlab that auto-inject their project variables into their pipelines.  Just remember to namespace the parameters so they don't collide! (In this case, both plugins use the key value)",
      "sources": ["environment", "gitlab"],
      "environment": {
        "key": "MULTIPLE_SOURCE_VAR",
      },
      "gitlab": {
        "key": {
          "key": "MULTIPLE_SOURCE_VAR"
        }
      }
    }
  ]
}
```

Run:

npm users:

`npx nurture -e dev`

yarn users:

`yarn nurture -e dev`

to build the dev environment.

## Config File Schema

The config file (`environment.json`) is parsed by nurture to generate your environment .env file. The schema is:

### variables:

This key contains a list of all of your variables and where they come from.

The following schema is accepted:

- "name" - the environment variable value we will generate an environment variable for
- "description" - Used to self-document the environment
- "value" - If this is supplied, the environment value is set to this and processing is terminated for this variable.
- "source" - Where the variable should be taken from. The source is usually provided by a plugin and Nurture comes with two default plugins, environment and config, for extracting things from the environment and from this config file. Other plugins supply extra values (e.g. the aws-plugin supplies the aws source).
- "default": If no environment variable is set using any of the above options, this is the value the variable defaults to.

Most plugins also have keys that they use e.g. the AWS SSM parameter uses "parameter" while gitlab uses "key". Please refer to the documentation for your plugin.

### config:

If you have config variables where you want to set a specific variable name in a specific environment, this is where you put them. Used by the inbuilt config plugin.

e.g.

```json
{
  "config": {
    "dev": {
      "var1": "A value used for development",
    },
    "test": {
      "var1": "The value in the test environment",
    },
    "prod" {
      "var1": "And in production it would be this value",
    }
  }
}
```

With this config, `yarn nurture -e test` will produce:

```
var1="The value in the test environment"
```

### plugins

A list of nurture plugins you wish to initialise. Each plugin may have a config section with a root key it sets (e.g. aws for the aws-plugin).

## Plugins

The core of nurture is are the plugins, which help automate the fetching of variables from your cloud providers or other 3rd party services. The currently supported plugins are:

- `[@nurturejs/aws-plugin](https://www.npmjs.com/package/@nurturejs/aws-plugin)` - Access AWS SSM parameters using AWS profiles
- `[@nurturejs/gitlab-plugin](https://www.npmjs.com/package/@nurturejs/gitlab-plugin)` - Access gitlab project variables using a gitlab read API token

### Writing a plugin

Writing a plugin is fairly easy. Here's the AWS plugin:

```typescript
export class AwsPlugin {
  protected configuration: any;
  public name = 'aws';

  constructor(configuration: any) {
    this.configuration = configuration['aws'];
  }

  async load(variable: any, environment: string) {
    const awsParams = this.configuration[environment];

    // eslint-disable-next-line @typescript-eslint/no-var-requires
    const ssmClient = new SSMClient({
      credentials: fromIni({ profile: awsParams.profile as string }),
      region: awsParams.region as string,
    });

    const parameter = variable.aws?.parameter || variable.parameter;
    const command = new GetParameterCommand({
      Name: parameter,
      WithDecryption: true,
    });
    const response = await ssmClient.send(command);

    return response.Parameter!.Value;
  }
}
```

As long as you parse the config in the contructor and have an async load function, as well as a name to identify the plugin to Nurture, you're good to go. Just remember to export your plugin class as `Plugin` at the top level of your package! e.g.

```typescript
export { AwsPlugin as Plugin };
```

Please contribute any plugins for any services that aren't supported yet and we'll include them in the @nurturejs namespace so others can find them too.

## Releases

0.1.x - Increased performance and ability to load multiple sources in order for a single variable
0.0.x - First releases with basic feature of creating a `.env` fle from a named source using plugins