@toa.io/cli 0.20.0-dev.5 → 0.20.0-dev.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toa.io/cli",
3
- "version": "0.20.0-dev.5",
3
+ "version": "0.20.0-dev.6",
4
4
  "description": "Toa CLI",
5
5
  "author": "temich <tema.gurtovoy@gmail.com>",
6
6
  "homepage": "https://github.com/toa-io/toa#readme",
@@ -22,13 +22,14 @@
22
22
  "@toa.io/runtime": "*"
23
23
  },
24
24
  "dependencies": {
25
- "@toa.io/console": "0.20.0-dev.5",
26
- "@toa.io/generic": "0.20.0-dev.5",
27
- "@toa.io/kubernetes": "0.20.0-dev.5",
28
- "@toa.io/norm": "0.20.0-dev.5",
29
- "@toa.io/yaml": "0.20.0-dev.5",
25
+ "@toa.io/console": "0.20.0-dev.7",
26
+ "@toa.io/generic": "0.20.0-dev.7",
27
+ "@toa.io/kubernetes": "0.20.0-dev.7",
28
+ "@toa.io/norm": "0.20.0-dev.7",
29
+ "@toa.io/yaml": "0.20.0-dev.7",
30
+ "dotenv": "16.1.1",
30
31
  "find-up": "5.0.0",
31
32
  "yargs": "17.6.2"
32
33
  },
33
- "gitHead": "86fa43267cbf99d1b2743b6d1ff6c3fdac38f49a"
34
+ "gitHead": "146e7e209d7a8bfca0fdfacaa8eaa51f41412a9a"
34
35
  }
package/readme.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Toa Command Line Interface
2
2
 
3
+ ## Common Options
4
+
5
+ <dl>
6
+ <dt><code>--env</code></dt>
7
+ <dd>Path to the environment variables file (`.env` format)</dd>
8
+ </dl>
9
+
3
10
  ## Development
4
11
 
5
12
  ### compose
@@ -9,14 +16,15 @@ Run composition.
9
16
  <dl>
10
17
  <dt><code>toa compose [paths]</code></dt>
11
18
  <dd>
12
- <code>paths</code> glob patterns to look for components<br/>
13
- <code>--kill</code> shutdown composition after it's started<br/>
14
- <code>--dock</code> run in Docker using current <code>.env</code><br/>
15
- <code>--bindnings</code> override bindings (obsolete)<br/>
19
+ <code>paths</code> Glob patterns to look for components.<br/>
20
+ <code>--kill</code> Shutdown composition after it's started<br/>
21
+ <code>--dock</code> Run in Docker using current <code>.env</code>.<br/>
22
+ <code>--context</code> Path to the Context root (default <code>.</code>).<br/>
23
+ <code>--bindnings</code> Override bindings (obsolete).
16
24
  </dd>
17
25
  </dl>
18
26
 
19
- > Note that your `localhost` it is accessible from the container as `host.docker.internal`.
27
+ > Note that your `localhost` it is accessible from a container as `host.docker.internal`.
20
28
 
21
29
  ### env
22
30
 
@@ -26,13 +34,14 @@ Export environment to a `.env` file.
26
34
  <dt><code>toa env [environment]</code></dt>
27
35
  <dd>
28
36
  <code>environment</code> deployment environment name (default <code>local</code>).<br/>
29
- <code>--path</code> path to context (default <code>.</code>)<br/>
37
+ <code>--path</code> path to a Context (default <code>.</code>)<br/>
38
+ <code>--as</code> output file path (default <code>.env</code>)
30
39
  </dd>
31
40
  </dl>
32
41
 
33
- Credentials specified in `.env` file are preserved.
42
+ Credentials specified in the output file are preserved.
34
43
 
35
- > It is recommended to add `.env` to `.gitignore`.
44
+ > It is recommended to add `.env*` to `.gitignore`.
36
45
 
37
46
  ### replay
38
47
 
@@ -42,7 +51,7 @@ format.
42
51
  <dl>
43
52
  <dt><code>toa replay [paths...]</code></dt>
44
53
  <dd>
45
- <code>paths</code> Path(s) to component(s) or a context (default <code>.</code>).<br/>
54
+ <code>paths</code> Path(s) to Component(s) or a Context (default <code>.</code>).<br/>
46
55
  <code>--component &lt;id&gt;</code> Replay samples for a specified component <code>id</code>.<br/>
47
56
  <code>--integration</code> Replay integration tests only.<br/>
48
57
  <code>--autonomous</code> Replay autonomous tests only.<br/>
@@ -63,8 +72,8 @@ $ toa replay ./path/to/context
63
72
  $ toa replay --title "should add numbers"
64
73
  ```
65
74
 
66
- If a path is a context directory (containing `context.toa.yaml` file), samples for components within
67
- the context will be found and replayed sequentially.
75
+ If the path is a Context root (containing `context.toa.yaml` file), samples for components within the Context will be
76
+ found and replayed sequentially.
68
77
 
69
78
  ### export manifest
70
79
 
@@ -73,48 +82,73 @@ the context will be found and replayed sequentially.
73
82
  <dd>Print normalized manifest.
74
83
 
75
84
  <code>--path</code> path to component (default <code>.</code>)<br/>
76
- <code>--error</code> print errors only<br/>
85
+ <code>--error</code> print errors only
77
86
  </dd>
78
87
  </dl>
79
88
 
80
89
  ## Operations
81
90
 
82
- > Commands use current Kubernetes context.
91
+ > Some commands use current Kubernetes context.
92
+
93
+ ### build
94
+
95
+ Build Docker images.
96
+
97
+ <dl>
98
+ <dt><code>toa build</code></dt>
99
+ <dd>
100
+ <code>--path</code> path to a Context (default <code>.</code>)
101
+ </dd>
102
+ </dl>
83
103
 
84
104
  ### deploy
85
105
 
106
+ Deploy a Context.
107
+
108
+ - Build Docker images.
109
+ - Push Docker images to the registry.
110
+ - Build a Helm chart.
111
+ - Apply the Helm chart to the current Kubernetes context.
112
+
86
113
  <dl>
87
114
  <dt><code>toa deploy [environment]</code></dt>
88
- <dd>Deploy context.
89
-
115
+ <dd>
90
116
  <code>environment</code> deployment environment name (default <code>default</code>).<br/>
117
+ <code>--path</code> path to a Context (default <code>.</code>)<br/>
118
+ <code>--namespace</code> Kubernetes namespace to apply the Helm chat to<br/>
119
+ <code>--wait</code> wait until all
120
+ Pods [are ready](https://helm.sh/docs/intro/using_helm/#helpful-options-for-installupgraderollback)<br/>
121
+ <code>--dry</code> do not apply the Helm chart
91
122
  </dd>
92
123
  </dl>
93
124
 
94
125
  ### conceal
95
126
 
127
+ Deploy a `key` with a `value` to a secret named `toa-{secret}`.
128
+
96
129
  <dl>
97
130
  <dt><code>toa conceal &lt;secret&gt; &lt;key&gt; &lt;value&gt;</code></dt>
98
- <dd>Deploy a <code>key</code> with a <code>value</code> to a secret named <code>toa-{secret}</code>.</dd>
99
131
  </dl>
100
132
 
101
133
  ### reveal
102
134
 
135
+ Outputs keys and values of a secret.
136
+
103
137
  <dl>
104
138
  <dt>
105
139
  <code>toa reveal &lt;secret&gt;</code>
106
140
  </dt>
107
- <dd>Print keys and values of a secret.</dd>
108
141
  </dl>
109
142
 
110
143
  ### shell
111
144
 
145
+ Run interactive shell inside a disposable pod inside a Kubernetes cluster.
146
+
112
147
  <dl>
113
148
  <dt>
114
149
  <code>toa shell [image]</code>
115
150
  </dt>
116
- <dd>Run interactive shell inside a disposable pod.
117
-
151
+ <dd>
118
152
  <code>image</code> Docker image<br/>
119
153
  </dd>
120
154
  </dl>
@@ -22,6 +22,12 @@ const builder = (yargs) => {
22
22
  type: 'boolean',
23
23
  desc: 'Run in Docker'
24
24
  })
25
+ .option('context', {
26
+ group: 'Command options:',
27
+ type: 'string',
28
+ desc: 'Path to the Context (used with --dock)',
29
+ default: '.'
30
+ })
25
31
  .option('bindings', {
26
32
  group: 'Command options:',
27
33
  type: 'string',
@@ -12,10 +12,16 @@ const builder = (yargs) => {
12
12
  .option('path', {
13
13
  alias: 'p',
14
14
  group: 'Command options:',
15
- describe: 'Path to component',
15
+ describe: 'Path to a Context',
16
16
  type: 'string',
17
17
  default: '.'
18
18
  })
19
+ .option('as', {
20
+ group: 'Command options:',
21
+ describe: 'Output file path',
22
+ type: 'string',
23
+ default: '.env'
24
+ })
19
25
  }
20
26
 
21
27
  exports.command = 'env [environment]'
@@ -52,6 +52,12 @@ const builder = (yargs) => {
52
52
  group: 'Command options:',
53
53
  describe: 'Replay inside Docker container'
54
54
  })
55
+ .option('context', {
56
+ group: 'Command options:',
57
+ type: 'string',
58
+ desc: 'Path to the Context (used with --dock)',
59
+ default: '.'
60
+ })
55
61
  }
56
62
 
57
63
  exports.command = 'replay [paths...]'
@@ -1,6 +1,5 @@
1
1
  'use strict'
2
2
 
3
- const { file: { dot } } = require('@toa.io/filesystem')
4
3
  const { pick } = require('@toa.io/generic')
5
4
  const boot = require('@toa.io/boot')
6
5
 
@@ -27,12 +26,11 @@ async function compose (argv) {
27
26
  * @return {Promise<void>}
28
27
  */
29
28
  async function dock (argv) {
30
- const envFile = await dot('env')
31
- const repository = await docker.build(argv.paths)
29
+ const repository = await docker.build(argv.context, argv.paths)
32
30
  const args = pick(argv, ['kill', 'bindings'])
33
31
  const command = docker.command('toa compose *', args)
34
32
 
35
- await docker.run(repository, command, ['--env-file', envFile])
33
+ await docker.run(repository, command, argv.env)
36
34
  }
37
35
 
38
36
  exports.compose = compose
@@ -1,18 +1,18 @@
1
1
  'use strict'
2
2
 
3
3
  const { newid } = require('@toa.io/generic')
4
- const { component: load } = require('@toa.io/norm')
4
+ const norm = require('@toa.io/norm')
5
5
  const { deployment: { Factory } } = require('@toa.io/operations')
6
- const runtime = require('@toa.io/runtime')
7
6
 
8
7
  const find = require('../../util/find')
9
8
 
10
9
  /**
11
- * @param {string[]} paths
10
+ * @param {string} contextPath
11
+ * @param {string[]} componentPatterns
12
12
  * @return {Promise<string>}
13
13
  */
14
- async function build (paths) {
15
- const context = await createContext(/** @type {string[]} */ paths)
14
+ async function build (contextPath, componentPatterns) {
15
+ const context = await createContext(contextPath, componentPatterns)
16
16
  const factory = new Factory(context)
17
17
  const registry = factory.registry()
18
18
 
@@ -20,32 +20,26 @@ async function build (paths) {
20
20
 
21
21
  const composition = context.compositions[0].name
22
22
 
23
- return `${context.name}/composition-${composition}`
23
+ return `${context.registry.base ? context.registry.base + '/' : ''}${context.name}/composition-${composition}`
24
24
  }
25
25
 
26
26
  /**
27
- * @param {string[]} patterns
27
+ * @param {string} contextPath
28
+ * @param {string[]} componentPatterns
28
29
  * @return {Promise<toa.norm.Context>}
29
30
  */
30
- async function createContext (patterns) {
31
- const paths = patterns.map((pattern) => find.components(pattern))
31
+ async function createContext (contextPath, componentPatterns) {
32
+ const contextRoot = find.context(contextPath)
33
+ const context = await norm.context(contextRoot)
34
+ const paths = componentPatterns.map((pattern) => find.components(pattern))
32
35
  const components = await loadComponents(paths)
33
36
  const rnd = newid().substring(0, 6)
34
37
  const name = 'replay-' + rnd
35
38
 
36
- return {
37
- name: 'toa-temp',
38
- runtime: {
39
- version: runtime.version
40
- },
41
- registry: {
42
- platforms: null
43
- },
44
- compositions: [{
45
- name,
46
- components
47
- }]
48
- }
39
+ context.name += '-' + rnd
40
+ context.compositions = [{ name, components }]
41
+
42
+ return context
49
43
  }
50
44
 
51
45
  /**
@@ -56,7 +50,7 @@ async function loadComponents (paths) {
56
50
  const components = []
57
51
 
58
52
  for (const path of paths) {
59
- const component = await load(path)
53
+ const component = await norm.component(path)
60
54
 
61
55
  components.push(component)
62
56
  }
@@ -4,22 +4,27 @@ const { spawn, exec } = require('node:child_process')
4
4
  const { promisify } = require('node:util')
5
5
 
6
6
  const { promex } = require('@toa.io/generic')
7
+ const { file: { dot } } = require('@toa.io/filesystem')
7
8
 
8
9
  const execute = promisify(exec)
9
10
 
10
11
  /**
11
12
  * @param {string} repository
12
13
  * @param {string} command
13
- * @param {string[]} runArguments
14
+ * @param {string} [envFile]
14
15
  * @return {Promise<void>}
15
16
  */
16
- async function run (repository, command, runArguments) {
17
- const imagesResult =
17
+ async function run (repository, command, envFile) {
18
+ if (envFile === undefined) envFile = await dot('env')
19
+
20
+ const envArgs = envFile === undefined ? [] : ['--env-file', envFile]
21
+
22
+ const found =
18
23
  /** @type {{ stdout: string }} */
19
24
  await execute(`docker images -q ${repository} | head -n 1`)
20
25
 
21
- const id = imagesResult.stdout.trim()
22
- const args = ['run', '--rm', ...(runArguments ?? []), id, 'sh', '-c', command]
26
+ const id = found.stdout.trim()
27
+ const args = ['run', '--rm', ...envArgs, id, 'sh', '-c', command]
23
28
  const done = promex()
24
29
 
25
30
  const running = await spawn('docker', args, { stdio: 'inherit' })
@@ -8,7 +8,7 @@ const { context: find } = require('../util/find')
8
8
 
9
9
  async function env (argv) {
10
10
  const path = find(argv.path)
11
- const filepath = join(path, '.env')
11
+ const filepath = join(path, argv.as)
12
12
  const operator = await boot.deployment(path, argv.environment)
13
13
  const variables = operator.variables()
14
14
  const currentValues = await read(filepath)
@@ -50,11 +50,11 @@ async function replay (argv) {
50
50
  * @return {Promise<void>}
51
51
  */
52
52
  async function dock (argv) {
53
- const repository = await docker.build(argv.paths)
53
+ const repository = await docker.build(argv.context, argv.paths)
54
54
  const args = pick(argv, ['component', 'operation', 'integration', 'title'])
55
55
  const command = docker.command('toa replay *', args)
56
56
 
57
- await docker.run(repository, command)
57
+ await docker.run(repository, command, argv.env)
58
58
  }
59
59
 
60
60
  const GREEN = '\x1b[32m'
package/src/program.js CHANGED
@@ -16,6 +16,11 @@ yargs(process.argv.slice(2))
16
16
 
17
17
  console.level(argv.log)
18
18
  })
19
+ .middleware(async (argv) => {
20
+ if (argv.env === undefined) return
21
+
22
+ require('dotenv').config({ path: /** @type {string} */ argv.env })
23
+ })
19
24
  .fail((msg, err) => {
20
25
  const actual = err || new Error(msg)
21
26
 
@@ -26,6 +31,10 @@ yargs(process.argv.slice(2))
26
31
  .option('log', {
27
32
  describe: 'Log level'
28
33
  })
34
+ .option('env', {
35
+ type: 'string',
36
+ describe: 'Path to environment variables file (.env format)'
37
+ })
29
38
  .commandDir('./commands')
30
39
  .demandCommand(1, 'A command is required. Pass --help to see all available commands and options.')
31
40
  .strict()