Skip to content

Commit

Permalink
Updated README + roadmap, added 'What' and 'Why'
Browse files Browse the repository at this point in the history
  • Loading branch information
gaui committed Jul 15, 2019
1 parent e9e6007 commit 66c920d
Showing 1 changed file with 89 additions and 62 deletions.
151 changes: 89 additions & 62 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,94 @@
# argster

A simple command/argument manager with a simple API that makes it easy to build commands and arguments.
A simple command/argument manager with a simple API that makes it easy to build dynamic commands and dynamic arguments with computed values.

## Examples
## What

Check out this [CodeSandbox](https://codesandbox.io/s/lyjjqzv38q).
The [Builder's](#builder) builds and manages commands. When a new `Builder` instance is created, it provides an simple API to create and execute commands, append and prepend dynamic arguments.

When creating [commands](#command) through the builder, it goes through the list of file patterns recursively, reads each file, parses each line in the file, resolves dynamic variables to their values, and generates an executable command string. When a command is executed, it returns an object which contains both a _promise_ which is resolved or rejected based on how the process exits (0 / 1), along with a [Readable](https://nodejs.org/api/stream.html#stream_readable_streams) streams object for listening to stdout and stderr streams.

So instead of manually creating the following command in our CI pipeline, with dynamic arguments and dynamic values that need to be computed at runtime:

```bash
docker build . -t myimage:1.0.0 --label org.label-schema.build-date=2019-07-14 --label org.label-schema.name=argster-120-example --label org.label-schema.vendor=Vendor --label org.label-schema.version=1.0.0 --label org.label-schema.schema-version=1.0.0-rc.1
```

You could create a simple JavaScript script and create complex commands with dynamic arguments (evaluated JavaScript functions) and version control it all with Git.

### Example (docker build)

Pay special attention to the `org.label-schema.build-date` label with the dynamic date.

**1. If we created the following builder and command**

```typescript
const options = {
dynamicVariables: {
BUILD_DATE: () => new Date().toISOString().slice(0, 10),
NAME: () => pkg.name,
VERSION: () => pkg.version,
DESCRIPTION: () => pkg.description,
VENDOR: () => "Vendor",
SCHEMA_VERSION: () => "1.0.0-rc.1"
},
skipUnresolvedVariables: true
};

const builder = new Builder(options);

const cmd = builder.createCommand('docker build .', [
{
patterns: ['**/*.lbl'],
prefix: '--label'
}
]);

cmd.prependArgument({
argument: `myimage:${pkg.version}`,
prefix: '-t'
});

command.exec();
```

**2. And had this pattern file**

**`./some/deep/path/file.lbl`**

```ini
org.label-schema.build-date=${BUILD_DATE}
org.label-schema.name=${NAME}
org.label-schema.description=${DESCRIPTION}
org.label-schema.vendor=${VENDOR}
org.label-schema.version=${VERSION}
org.label-schema.schema-version=${SCHEMA_VERSION}
```

**3. This will be the executed command:**

```bash
docker build . -t myimage:1.0.0 --label org.label-schema.build-date=2019-07-14 --label org.label-schema.name=argster-120-example --label org.label-schema.vendor=Vendor --label org.label-schema.version=1.0.0 --label org.label-schema.schema-version=1.0.0-rc.1
```

## Why

I always felt the lack of a tool/library to easily create dynamic commands with dynamic arguments that were derived by functions but had the possibility to version control, without creating complex shell scripts. It first started when I was experimenting with DevOps and started to work with Docker trying to create sane images. I started reading about best practices around labeling and tagging Docker images and stumbled up on [Label Schema](http://label-schema.org/rc1/#label-semantics).

I sat down and thought about the following technologies:

- Label Schema and label semantics for e.g. Docker images
- Dockerfile and `ENV` / `ARG`
- Dockerfile and `.env` file
- Power of JavaScript
- Power of variables
- Power of Git

With the great tech above I wanted to utilise it all and create a Node library that was able to build up complex dynamic command-line commands and arguments. Then the idea of **argster** was born.

Check out this [CodeSandbox](https://codesandbox.io/s/lyjjqzv38q) for examples.

Checkout the [roadmap](#roadmap) for what to come.

## Setup

Expand Down Expand Up @@ -57,59 +141,6 @@ All files matching the glob pattern `**/*.arg` and `**/*.lbl` would be read and

When the command arguments are evaluated, a finalized command string is generated from those file contents.

To explain...

#### 1. If we created the following builder/command

```typescript
const extensions = [
{
prefix: '--build-arg',
patterns: ['**/*.arg']
},
{
prefix: '--label',
patterns: ['**/*.lbl']
}
];

const options = {
dynamicVariables: {
BUILD_DATE: () => new Date().toISOString().slice(0, 10)
}
};

const builder = new Builder(options);
const command = builder.createCommand('docker build .', extensions);
command.exec();
```

#### 2. And had these pattern files

**`./foo/file.arg`**

```ini
VAR1=VAL1
VAR2=VAL2
VAR3=VAL3
```

**`./foo/bar/file.lbl`**

```ini
org.label-schema.build-date=${BUILD_DATE}
org.label-schema.name=MyProject
```

#### 3. This would be the generated command that would be executed


```bash
docker build . --build-arg VAR1=VAL1 --build-arg VAR2=VAL2 --build-arg VAR3=VAL3 --label org.label-schema.build-date=2018-08-03 --label org.label-schema.name=MyProject
```

Take a look at how the `${BUILD_DATE}` argument now has the actual date. This is based on the dynamic variable we specified in the builder options above.

### Builder Options

#### rootDir
Expand Down Expand Up @@ -287,14 +318,10 @@ toString(): string;
toArray(): ReadonlyArray<string>;
```

## How it works

The [Builder's](#builder) responsibility is to build and manage commands. When a new `Builder` instance is created, it provides a API to create commands.

When creating [commands](#command) through the builder, it goes through the list of file patterns recursively, reads each file, parses each line in the file, resolves dynamic variables to their values, and generates a executable command string. When a command is executed, it returns an object which contains both a _promise_ which is resolved or rejected based on how the process exits, along with a [Readable](https://nodejs.org/api/stream.html#stream_readable_streams) streams object for listening to stdout and stderr streams.

## Roadmap

- Set up automated TypeScript documentation for APIs
- Follow [Conventional Commits](https://www.conventionalcommits.org)
- Set up CI to run automated tests
- Plugin / Middleware architecture
- Ability to hook into events
Expand Down

0 comments on commit 66c920d

Please sign in to comment.