This repository contains the source code for the CLI utility to initialize and manage a development workspace.
The CLI utility is based on Node.js and NPM. To install the utility, it is necessary to have Node.js and NPM installed.
The CLI utility can be executed via npx:
npx @cycrilabs/ws-ctrl@latestThis will pull the latest version of the utility from the NPM registry and execute it. The utility will then display the available commands and options.
A command is executed by appending it to the initial npx, for example for the
init command:
npx @cycrilabs/ws-ctrl@latest initThe following table lists all available commands and options.
| Command | Description |
|---|---|
init |
Initialize a new workspace |
run |
Run a specific use case in the workspace |
sync |
Syncs the templates |
help |
Displays help information |
The init command initializes a new workspace. After executing the command, the
user is prompted to enter at least to location of new workspace. Alternatively,
the location can be passed as an argument directly, e.g.
npx @cycrilabs/ws-ctrl@latest init ./platformIn addition, the user is prompted to specify whether a template repository should be used, and if so, which one.
Furthermore, the following options are available:
| Option | Description |
|---|---|
--templates-repository <templatesRepository> |
use the specified template repository |
The template repository is a Git repository that contains the templates for the workspace. If no template repository is specified, provided templates from the CLI utility package are used.
For more details, see the Workspace structure and Template repository sections.
The run command executes a specific use case in the workspace. Use cases can
only be executed if the workspace has been initialized before and only within
the top-level workspace directory.
The following options are available:
| Option | Description |
|---|---|
-u, --use-case [use-case] |
the use case to run |
--debug |
enable debug mode; allows to run use cases from any location, assuming the config structure matches |
For example, to run the check-requirements use case, execute:
npx @cycrilabs/ws-ctrl@latest run -u check-requirementsFor more details, see the Use cases section.
The sync command syncs the templates. This command is used to update the
templates in the workspace. Templates are copied from the CLI utility package
itself and, if a template repository is used, from the template repository.
The command is executed via:
npx @cycrilabs/ws-ctrl@latest syncFor more details, see the Template repository section.
The help command displays help information. It can be executed via:
npx @cycrilabs/ws-ctrl@latest helpThe workspace is structured as follows, assuming the workspace is located in
./platform and a template repository is used:
├── platform
│ ├── config
│ │ ├── development
│ | | ├── ...
│ │ ├── docker
│ | | ├── ...
│ │ ├── git-templates
│ | | ├── ...
│ │ ├── repositories
│ | | ├── ...
│ │ ├── secret-templates
│ | | ├── ...
│ │ ├── servers
│ | | ├── ...
│ │ ├── services-config
│ | | ├── ...
│ │ ├── use-cases
│ | | ├── ...
│ │ ├── cli.sh
│ ├── development
│ | ├── ...
│ ├── adbb1a3d55.json
│ ├── cli.sh
The following table lists the directories and files in the workspace and their purpose:
| Directory/File | Purpose |
|---|---|
config |
configuration files for the workspace; all files in here are the basis for the workspace |
config/development |
development files for the workspace; this directory is copied to the root directory and will contain all cloned repositories as well as IDE configuration files |
config/docker |
Docker configuration files for the workspace; the files are copied to the root directory and will be used to start services |
config/git-templates |
Git template repository; contains the cloned template repository, if configured; all files from it will be copied over recursively to the config directory |
config/repositories |
repository configuration files for the workspace; see Repository Configuration |
config/secret-templates |
secret templates for the workspace; see Secret Templates |
config/servers |
server configuration files for the workspace; see Server Configuration |
config/services-config |
service configuration files for the workspace; the file are automatically generated by the use case generate-service-configuration |
config/use-cases |
use case configuration files for the workspace; see Use Cases |
The repository configuration files are used to configure the repositories
that can be cloned into the workspace. The configuration files are located in
the config/repositories directory. All files are automatically available for
prompts.
This JSON Schema defines the structure of the repository configuration.
The server configuration files are used to configure the servers that can be
used to run the platform against. The configuration files are located in the
config/servers directory. All files are automatically available for prompts.
This JSON Schema defines the structure of the server configuration.
The secret templates are used to provide the secrets that are necessary for all services
running locally to connect to Keycloak or other services. In addition,
they can contain environment variables specific to each service. The secret templates
are located in the config/secret-templates directory.
The secret templates are based on the Keycloak Configurator. For more details, check the documentation.
If secret templates are the input for the generate-service-configuration executor,
then, the Keycloak Configurator gets
the .env file as input as well as additionally the following variables:
KCC_WORKSPACE_PATH: The absolute path to the workspace directory.KCC_WORKING_DIR: The absolute path to the working directory.
Use cases are scripts based on JSON that can be executed in the workspace. They
are located in the config/use-cases directory. Use cases can be executed via
the run command.
Use cases provide a special syntax to define the steps that are executed in order to modify the configuration of a workspace, execute commands, or perform other tasks.
In the following, available use cases are listed and it is described how to create new use cases.
The following use cases are available out of the box and provided by the CLI utility package:
| Use case name | Description |
|---|---|
check-requirements |
Checks the requirements for the workspace |
clone-repositories |
Clones selected repositories into the workspace |
list-containers |
Lists all running docker containers in the workspace |
pull-repositories |
Pulls the latest changes from the repositories in the workspace |
The use cases are available by default and can be disabled via a template repository.
In addition, there are two use cases that are executed right after the commands
init and sync are executed:
| Use case name | Description |
|---|---|
init |
Executed directly after the init command did it's hard-coded work; only executed once on creation |
sync |
Executed directly after the sync command did it's hard-coded work; executed after every sync |
These use cases have the state HIDDEN (see Creating use cases)
and are not displayed in the list of available use cases. They can't be executed
directly. However, via template repositories, it is possible to overwrite these
use cases and easily extend what should be done after the init or sync
command per project basis.
Although there are a lot of use cases available, it is possible to create new use cases. Use cases are simply JSON files that expect some specific structure and keywords to be correctly interpreted by the CLI utility. Like this, it is possible to easily configure and execute pretty much everything on the workspace configuration files.
This JSON schema describes the structure of a use case. In the following, each keyword is described and potential end-2-end usage examples are provided.
A use case consists of the follow properties:
id: a unique identifier for the use case; can be used to reference the use case or call it via the-uoptionname: the name of the use case; mainly used for display purposesdescription(optional): a description of the use case; mainly used for display purposesstate(optional): the state of the use case; can be one of the followingENABLED: the use case is generally usable; this is the default stateDISABLED: the use case is not usable at allINITIAL: the use case is only usable with commandsHIDDEN: the use case is only callable byid, either by-uor via reference from another use case
steps: an array of steps that are executed in order
Each step consists of the following properties:
type: the type of the step; can be one of the followingFORMULA: a JavaScript formula that is executed in this step; executed viaevalCOMMAND: execute a command; the command is executed via NodeJSchild_process.execSync; if used in combination withresultVariablecommand output is capturedEXECUTOR: a special step that is connected to some build-in executor; see Available executorsUSE_CASE: call another use casePROMPT: trigger a prompt for user input
description(optional): a description of the step; mainly used for display purposesloop(optional): a loop that is executed for each element in the array; the loop is an object with the following propertieslist: the array that is looped overname: the variable that is used in the loop
inputFile(optional): the input file for the step; the file is read and the content is passed to the step; can be used to write back contentoutputFile(optional): the output file for the command; the output of the step is written to the fileabortIf(optional): a formula that is evaluated; if the formula is true, the use case is stoppedskipIf(optional): a formula that is evaluated; if the formula is true, the step is skippedcatchErrors(optional): a flag to catch errors; if set totrue, errors are caught and the use case is not stopped; defaults tofalseuseCase(optional): the use case that is called; only used forUSE_CASEstepsformula(optional): the formula that is executed; only used forFORMULAsteps; a JavaScript formula that is executed in this step; executed viaevalcommand(optional): the command that is executed; only used forCOMMANDsteps; the command is executed via NodeJSchild_process.execSyncexecutor(optional): the executor that is used; only used forEXECUTORsteps; see Available executorsresultVariable(optional): the variable that is used to store the result of the step; the variable is available in the next steps; if not provided, results are stored asSTEP_RESULTcontext(optional): the context that is used for the step; the context is an object that is passed to the step; can be used to store variables
The following executors are available:
custom-prompt: trigger a custom prompt on the CLI; the following context is expected:name: the name of the variable that is used to store the result of the promptmessage: the message that is displayed to the usertype: the type of the prompt; can be one of the following (see prompts)text: a simple text inputnumber: a simple number inputconfirm: a yes or no questionsselect: a single select promptmultiselect: a multi select prompt
entities: the entities that are used for the select or multiselect promptentityKey: a key that is used to display entities from the context
generate-service-configuration: generates .env files for services based on Keycloak Configurator; the following context is expected:kcVersion: the version of the Keycloak Configurator to useauthServerUrl: the URL of the Keycloak serverauthUser: the user to authenticate withauthPassword: the password to authenticate withauthTenant: the tenant to authenticate with
change-env-var-value: changes the value of an environment variable in a giveninputFile; the following context is expected:name: the variable to change the value ofvalue: the new value of the variable
All steps are working with a context object that is empty initially. Whenever a use case starts, the context is filled with the following properties. Throughout execution, steps can add or modify properties in the context object.
OS: the operating system where the CLI is executed on; represents the result ofprocess.platformWORKSPACE_PATH: the absolute path to the workspaceWORKING_DIR: the absolute path to the working directory, see Workspace structureSERVERS: the list of all servers, see Server configurationREPOSITORIES: the list of all repositories, see Repository configuration
The context can be accessed throughout different step types within a formula,
command, or executor via the properties in context. Whenever input is evaluated
based on the Javascript eval function, the context is available as a flat list
of properties. For example, assume the context looks as follows:
const context = {
server: 'local',
};A formula can access the server property via:
server === 'local' : 'yes' : 'no'The template repository is a Git repository. The structure of the repository
is the same as the config directory in the workspace, described in the
Workspace structure section.
If a template repository is used, the repository is cloned into the workspace,
to the config/git-templates directory. The files from the template repository
are then copied over recursively to the config directory, overwriting all
existing files.
This allows to provide different servers, use cases, and other configurations
that are specific to a project. A common use case could be to provide additional
servers or repositories that are specific to a project. Furthermore, often the
docker-compose-cxc.yml is overwritten to use cxc specific services.
To develop the CLI utility, it is necessary to install the dependencies:
npm installAfterward, the tool can be executed via:
npm run devCommands can be executed as described above. They must be simply appended to
the npm run dev command:
npm run dev -- help initThe tool can be tested end-2-end by executing the following command:
npm linkThis adds a symlink to the global NPM packages, so that the tool can be executed from any directory. The tool can be executed via:
ws-ctrl helpAfter testing, the symlink can be removed via:
npm uninstall ws-ctrl -gIt is possible to test use cases directly in the workspace. To do so, the use case
should be placed in the assets/templates/config/use-cases directory.
The use case can then be executed via:
npm run dev -- run ./assets/templates -u <use-case-name> --debug