Skip to content
This repository has been archived by the owner on Nov 13, 2023. It is now read-only.

Command Option Precedence

JamesBauman edited this page Nov 19, 2018 · 7 revisions

Overview

Imperative provides a flexible "command option precedence" mechanism. When a command is issued, Imperative will "search" (in order) for option values in the following locations:

  1. Options specified on the command (e.g. "--my-opt" or a positional)
  2. Environment variables (e.g. "CLI_OPT_MY_OPTION")
  3. Loaded profiles (e.g. "myOption:" or "my-option:")
  4. Default value on the command definition (e.g. "defaultValue:")

The command option precedence feature allows Imperative based CLIs to be flexible for different situations:

  • For example, a human user might not want to supply static, non-changing configuration such as host, port, and credentials when issuing every command. Therefore, it makes sense to persist those options in a configuration profile (which can be secured with Keytar).
  • CI/CD tools normally provide a mechanism for securely storing configuration (e.g. credentials). In the case of Jenkins, you can use withCredentials to expose credentials as an ENV or Groovy variable. In this case, you won't need to duplicate those values in an Imperative profile, you can simply place them in the appropriate ENV variables before issuing commands. This of course assumes, that the profile is not marked as "required", but rather "optional", for the command.

Users of an Imperative based CLI can mix-and-match where they specify option values to suit their needs/preferences. For example:

SAMP_OPT_OPTION="Value for option" samp hello --another-option "Value for another option"

Note: If you want to enable users of your Imperative based CLI to specify values in profiles, you must define a profile type on the Imperative configuration document and list that type in the profile property of your command definition.

Option Mapping

In general, the arguments object passed to command handlers contains both "camel" and "kebab" case properties for options that were supplied to the handler. However, if an option does not contain hyphens or mixed case it will appear only once on the object.

This concept is applied to profiles when Imperative is searching for an option value.

Assume we have an option definition with name my-opt (--my-opt on the command line).

Imperative will attempt to extract it's value from both fields in the profile:

myOpt: "the value 1"
my-opt: "the value 2"

If both are present (as in the example above), Imperative uses the profile field that matches the option name exactly. In this case, the arguments object would be provided as:

{
    "$0": "main.js",
    "_": ["hello"],
    "myOpt": "the value 2",
    "my-opt": "the value 2"
}

In other words, kebab and camel case are treated as the same specification in a profile.

Profile Order

Imperative allows for more than one profile type to be defined and used on a command.

Assume we have the following profile definition on our command definition document:

{
    "name": "hello",
    "description": "A sample command",
    "type": "command",
    "handler": "/path/to/handler",
    "options": [{
         "name": "tastiest",
         "description": "My option",
         "type": "string"
    }],
    "profile": {
        "optional": ["fruits", "vegetables"],
    }
}

When the hello command is issued, Imperative will "search" for option values in each profile loaded for types "fruits" and "vegetables" in the order listed on the command definition document. In other words, if field tastiest is supplied in both profiles, the value from "fruits" is used.