@toa.io/operations 0.7.5 → 0.7.6-alpha.56

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.
Files changed (30) hide show
  1. package/package.json +5 -5
  2. package/readme.md +15 -0
  3. package/src/deployment/.deployment/.describe/variables.js +1 -8
  4. package/src/deployment/chart/templates/services.yaml +3 -1
  5. package/src/deployment/factory.js +26 -10
  6. package/src/deployment/images/composition.Dockerfile +6 -4
  7. package/src/deployment/images/composition.js +8 -6
  8. package/src/deployment/images/factory.js +19 -5
  9. package/{test → src}/deployment/images/image.fixtures.js +7 -1
  10. package/src/deployment/images/image.js +26 -14
  11. package/{test → src}/deployment/images/image.test.js +2 -6
  12. package/src/deployment/images/index.js +0 -2
  13. package/src/deployment/images/service.Dockerfile +4 -4
  14. package/src/deployment/images/service.js +3 -2
  15. package/src/deployment/operator.js +11 -39
  16. package/{test → src}/deployment/operator.test.js +6 -3
  17. package/src/deployment/{images/registry.js → registry.js} +46 -26
  18. package/src/deployment/workspace.js +17 -0
  19. package/src/process.js +2 -0
  20. package/types/deployment/composition.d.ts +4 -6
  21. package/types/deployment/dependency.d.ts +8 -13
  22. package/types/deployment/deployment.d.ts +10 -12
  23. package/types/deployment/factory.d.ts +7 -5
  24. package/types/deployment/images/image.d.ts +5 -7
  25. package/types/deployment/operator.d.ts +1 -7
  26. package/types/deployment/registry.d.ts +21 -0
  27. package/types/deployment/service.d.ts +11 -13
  28. package/types/deployment/index.d.ts +0 -1
  29. /package/{test → src}/deployment/deployment.fixtures.js +0 -0
  30. /package/{test → src}/deployment/deployment.test.js +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toa.io/operations",
3
- "version": "0.7.5",
3
+ "version": "0.7.6-alpha.56+a80d81d4",
4
4
  "description": "Toa Deployment",
5
5
  "homepage": "https://toa.io",
6
6
  "author": {
@@ -26,10 +26,10 @@
26
26
  "test": "echo \"Error: run tests from root\" && exit 1"
27
27
  },
28
28
  "dependencies": {
29
- "@toa.io/filesystem": "1.0.1",
30
- "@toa.io/generic": "0.10.0",
31
- "@toa.io/yaml": "0.7.5",
29
+ "@toa.io/filesystem": "1.0.2-alpha.56+a80d81d4",
30
+ "@toa.io/generic": "0.10.1-alpha.56+a80d81d4",
31
+ "@toa.io/yaml": "0.7.6-alpha.56+a80d81d4",
32
32
  "execa": "5.1.1"
33
33
  },
34
- "gitHead": "25fdf15b413338d49b16ddefe17807e4e746f37e"
34
+ "gitHead": "a80d81d4d9da9fec07606154c959dd6512de4c76"
35
35
  }
package/readme.md ADDED
@@ -0,0 +1,15 @@
1
+ # Toa Operations
2
+
3
+ ## Context
4
+
5
+ ### Container Registry
6
+
7
+ #### Build Options
8
+
9
+ ```yaml
10
+ registry:
11
+ build:
12
+ arguments: [NPM_TOKEN]
13
+ run: |
14
+ echo //npm.pkg.github.com/:_authToken=${NPM_TOKEN} > .npmrc
15
+ ```
@@ -9,7 +9,7 @@ const variables = (context, variables) => {
9
9
  if (variables.global === undefined) variables.global = []
10
10
 
11
11
  if (context.environment !== undefined) {
12
- const variable = format('TOA_ENV', context.environment)
12
+ const variable = { name: 'TOA_ENV', value: context.environment }
13
13
 
14
14
  variables.global.unshift(variable)
15
15
  }
@@ -17,11 +17,4 @@ const variables = (context, variables) => {
17
17
  return variables
18
18
  }
19
19
 
20
- /**
21
- * @param {string} name
22
- * @param {string} value
23
- * @returns {toa.deployment.dependency.Variable}
24
- */
25
- const format = (name, value) => ({ name, value })
26
-
27
20
  exports.variables = variables
@@ -47,7 +47,9 @@ metadata:
47
47
  {{ toYaml .ingress.annotations | indent 4 }}
48
48
  {{- end }}
49
49
  spec:
50
- ingressClassName: {{ required "ingress.class is required" .ingress.class }}
50
+ {{- if .ingress.class }}
51
+ ingressClassName: {{ .ingress.class }}
52
+ {{- end }}
51
53
  rules:
52
54
  - host: {{ required "ingress.host is required" .ingress.host }}
53
55
  http:
@@ -2,8 +2,9 @@
2
2
 
3
3
  const { Process } = require('../process')
4
4
  const { Operator } = require('./operator')
5
- const { Factory: Images, Registry } = require('./images')
5
+ const { Factory: ImagesFactory } = require('./images')
6
6
  const { Deployment } = require('./deployment')
7
+ const { Registry } = require('./registry')
7
8
  const { Composition } = require('./composition')
8
9
  const { Service } = require('./service')
9
10
 
@@ -13,8 +14,16 @@ const { Service } = require('./service')
13
14
  class Factory {
14
15
  /** @type {toa.norm.Context} */
15
16
  #context
16
- /** @type {toa.deployment.images.Registry} */
17
+
18
+ /** @type {Composition[]} */
19
+ #compositions
20
+
21
+ /** @type {toa.deployment.Dependency[]} */
22
+ #dependencies
23
+
24
+ /** @type {toa.deployment.Registry} */
17
25
  #registry
26
+
18
27
  /** @type {toa.operations.Process} */
19
28
  #process
20
29
 
@@ -25,18 +34,23 @@ class Factory {
25
34
  this.#context = context
26
35
  this.#process = new Process()
27
36
 
28
- const images = new Images(context.name, context.runtime)
29
- this.#registry = new Registry(context.registry, images, this.#process)
37
+ const imagesFactory = new ImagesFactory(context.name, context.runtime, context.registry)
38
+
39
+ this.#registry = new Registry(context.registry, imagesFactory, this.#process)
40
+ this.#compositions = context.compositions.map((composition) => this.#composition(composition))
41
+ this.#dependencies = this.#getDependencies()
30
42
  }
31
43
 
32
44
  operator () {
33
- const compositions = this.#context.compositions.map((composition) => this.#composition(composition))
34
- const dependencies = this.#dependencies()
35
- const deployment = new Deployment(this.#context, compositions, dependencies, this.#process)
45
+ const deployment = new Deployment(this.#context, this.#compositions, this.#dependencies, this.#process)
36
46
 
37
47
  return new Operator(deployment, this.#registry)
38
48
  }
39
49
 
50
+ registry () {
51
+ return this.#registry
52
+ }
53
+
40
54
  /**
41
55
  * @param composition {toa.norm.context.Composition}
42
56
  * @returns {Composition}
@@ -50,12 +64,14 @@ class Factory {
50
64
  /**
51
65
  * @returns {toa.deployment.Dependency[]}
52
66
  */
53
- #dependencies () {
67
+ #getDependencies () {
54
68
  /** @type {toa.deployment.Dependency[]} */
55
69
  const dependencies = []
56
70
 
71
+ if (this.#context.dependencies === undefined) return dependencies
72
+
57
73
  for (const [reference, instances] of Object.entries(this.#context.dependencies)) {
58
- const dependency = this.#dependency(reference, instances)
74
+ const dependency = this.#getDependency(reference, instances)
59
75
 
60
76
  if (dependency !== undefined) dependencies.push(dependency)
61
77
  }
@@ -68,7 +84,7 @@ class Factory {
68
84
  * @param {toa.norm.context.dependencies.Instance[]} instances
69
85
  * @returns {toa.deployment.Dependency | undefined}
70
86
  */
71
- #dependency (path, instances) {
87
+ #getDependency (path, instances) {
72
88
  const module = require(path)
73
89
  const pkg = require(path + '/package.json')
74
90
 
@@ -1,9 +1,9 @@
1
- FROM node:18.2.0-alpine3.15
1
+ FROM node:18.16.0-alpine3.17
2
2
 
3
3
  ENV NODE_ENV=production
4
- RUN npm set registry {{registry}}
5
- RUN npm set proxy {{proxy}}
6
- RUN npm i -g @toa.io/runtime@{{version}}
4
+ RUN if [ {{runtime.egistry}} != undefined ]; then npm set registry {{runtime.registry}}; fi
5
+ RUN if [ {{runtime.proxy}} != undefined ]; then npm set proxy {{runtime.proxy}}; fi
6
+ RUN npm i -g @toa.io/runtime@{{runtime.version}}
7
7
 
8
8
  WORKDIR /composition
9
9
  ADD . .
@@ -11,4 +11,6 @@ ADD . .
11
11
  # run 'npm i' in each component
12
12
  RUN find . -maxdepth 1 -type d \( ! -name . \) -exec /bin/sh -c "cd '{}' && if [ -f package.json ]; then npm i; fi" \;
13
13
 
14
+ RUN {{build.command}}
15
+
14
16
  CMD toa compose *
@@ -11,16 +11,18 @@ class Composition extends Image {
11
11
 
12
12
  /** @type {string} */
13
13
  #name
14
- /** @type {Array<toa.norm.Component>} */
14
+
15
+ /** @type {toa.norm.Component[]} */
15
16
  #components
16
17
 
17
18
  /**
18
- * @param scope {string}
19
- * @param runtime {toa.norm.context.Runtime}
20
- * @param composition {toa.norm.context.Composition}
19
+ * @param {string} scope
20
+ * @param {toa.norm.context.Runtime} runtime
21
+ * @param {toa.norm.context.Registry} registry
22
+ * @param {toa.norm.context.Composition} composition
21
23
  */
22
- constructor (scope, runtime, composition) {
23
- super(scope, runtime)
24
+ constructor (scope, runtime, registry, composition) {
25
+ super(scope, runtime, registry)
24
26
 
25
27
  this.#name = composition.name
26
28
  this.#components = composition.components
@@ -9,30 +9,44 @@ const { Service } = require('./service')
9
9
  class Factory {
10
10
  /** @type {string} */
11
11
  #scope
12
+
12
13
  /** @type {toa.norm.context.Runtime} */
13
14
  #runtime
14
15
 
16
+ /** @type {toa.norm.context.Registry} */
17
+ #registry
18
+
15
19
  /**
16
- * @param scope {string}
17
- * @param runtime {toa.norm.context.Runtime}
20
+ * @param {string} scope
21
+ * @param {toa.norm.context.Runtime} runtime
22
+ * @param {toa.norm.context.Registry} registry
18
23
  */
19
- constructor (scope, runtime) {
24
+ constructor (scope, runtime, registry) {
20
25
  this.#scope = scope
21
26
  this.#runtime = runtime
27
+ this.#registry = registry
22
28
  }
23
29
 
24
30
  /**
25
31
  * @returns {Composition}
26
32
  */
27
33
  composition (composition) {
28
- return new Composition(this.#scope, this.#runtime, composition)
34
+ const instance = new Composition(this.#scope, this.#runtime, this.#registry, composition)
35
+
36
+ instance.tag()
37
+
38
+ return instance
29
39
  }
30
40
 
31
41
  /**
32
42
  * @returns {Service}
33
43
  */
34
44
  service (path, service) {
35
- return new Service(this.#scope, this.#runtime, path, service)
45
+ const instance = new Service(this.#scope, this.#runtime, this.#registry, path, service)
46
+
47
+ instance.tag()
48
+
49
+ return instance
36
50
  }
37
51
  }
38
52
 
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { Image } = require('../../../src/deployment/images/image')
3
+ const { Image } = require('./image')
4
4
  const { generate } = require('randomstring')
5
5
  const { hash } = require('@toa.io/generic')
6
6
 
@@ -25,9 +25,15 @@ const runtime = {
25
25
  version: generate()
26
26
  }
27
27
 
28
+ /** @type {toa.norm.context.Registry} */
29
+ const registry = {
30
+ base: generate()
31
+ }
32
+
28
33
  exports.scope = generate()
29
34
  exports.name = name
30
35
  exports.version = hash(runtime.version + ';' + version)
31
36
  exports.Class = Class
32
37
  exports.runtime = runtime
38
+ exports.registry = registry
33
39
  exports.process = process
@@ -3,7 +3,7 @@
3
3
  const { join, posix } = require('node:path')
4
4
  const { readFile: read, writeFile: write } = require('node:fs/promises')
5
5
 
6
- const { hash } = require('@toa.io/generic')
6
+ const { hash, overwrite } = require('@toa.io/generic')
7
7
  const { directory } = require('@toa.io/filesystem')
8
8
 
9
9
  /**
@@ -22,19 +22,38 @@ class Image {
22
22
 
23
23
  /** @type {string} */
24
24
  #scope
25
+
26
+ /** @type {toa.norm.context.Registry} */
27
+ #registry
28
+
25
29
  /** @type {toa.norm.context.Runtime} */
26
30
  #runtime
31
+
27
32
  /** @type {string} */
28
33
  #type
29
34
 
35
+ /** @type {{ runtime?: Partial<toa.norm.context.Runtime>, build: object }} */
36
+ #values = { build: { command: 'echo hello' } }
37
+
30
38
  /**
31
- * @param scope {string}
32
- * @param runtime {toa.norm.context.Runtime}
39
+ * @param {string} scope
40
+ * @param {toa.norm.context.Runtime} runtime
41
+ * @param {toa.norm.context.Registry} registry
33
42
  */
34
- constructor (scope, runtime) {
43
+ constructor (scope, runtime, registry) {
35
44
  this.#scope = scope
45
+ this.#registry = registry
36
46
  this.#runtime = runtime
37
47
  this.#type = this.constructor.name.toLowerCase()
48
+
49
+ this.#values.runtime = runtime
50
+ this.#values.build = overwrite(this.#values.build, registry.build)
51
+ }
52
+
53
+ tag () {
54
+ const tag = hash(this.#runtime?.version + ';' + this.version)
55
+
56
+ this.reference = posix.join(this.#registry.base ?? '', this.#scope, `${this.#type}-${this.name}:${tag}`)
38
57
  }
39
58
 
40
59
  /**
@@ -51,12 +70,6 @@ class Image {
51
70
  */
52
71
  get version () {}
53
72
 
54
- tag (base) {
55
- const tag = hash(this.#runtime.version + ';' + this.version)
56
-
57
- this.reference = posix.join(base, `${this.#scope}/${this.#type}-${this.name}:${tag}`)
58
- }
59
-
60
73
  async prepare (root) {
61
74
  if (this.dockerfile === undefined) throw new Error('Dockerfile isn\'t specified')
62
75
 
@@ -65,7 +78,7 @@ class Image {
65
78
  await directory.ensure(path)
66
79
 
67
80
  const template = await read(this.dockerfile, 'utf-8')
68
- const contents = template.replace(/{{(\.?\w+)}}/g, (_, key) => this.#value(key))
81
+ const contents = template.replace(/{{(\S{1,32})}}/g, (_, key) => this.#value(key))
69
82
  const ignore = 'Dockerfile'
70
83
 
71
84
  await write(join(path, 'Dockerfile'), contents)
@@ -81,10 +94,9 @@ class Image {
81
94
  * @returns {string}
82
95
  */
83
96
  #value (key) {
84
- const [, property] = key.split('.')
97
+ const [source, property] = key.split('.')
85
98
 
86
- if (property !== undefined) return this[property]
87
- else return this.#runtime[key]
99
+ return this.#values[source]?.[property] ?? ''
88
100
  }
89
101
  }
90
102
 
@@ -7,15 +7,11 @@ const { generate } = require('randomstring')
7
7
  let instance
8
8
 
9
9
  beforeEach(() => {
10
- instance = new fixtures.Class(fixtures.scope, fixtures.runtime)
10
+ instance = new fixtures.Class(fixtures.scope, fixtures.runtime, fixtures.registry)
11
11
  })
12
12
 
13
13
  it('should assign url', () => {
14
- const registry = generate()
15
-
16
- instance.tag(registry)
17
-
18
- expect(instance.reference).toEqual(`${registry}/${fixtures.scope}/class-${fixtures.name}:${fixtures.version}`)
14
+ expect(instance.reference).toEqual(`${fixtures.registry.base}/${fixtures.scope}/class-${fixtures.name}:${fixtures.version}`)
19
15
  })
20
16
 
21
17
  describe('prepare', () => {
@@ -1,7 +1,5 @@
1
1
  'use strict'
2
2
 
3
3
  const { Factory } = require('./factory')
4
- const { Registry } = require('./registry')
5
4
 
6
5
  exports.Factory = Factory
7
- exports.Registry = Registry
@@ -1,9 +1,9 @@
1
- FROM node:18.2.0-alpine3.15
1
+ FROM node:18.16.0-alpine3.17
2
2
 
3
3
  ENV NODE_ENV=production
4
- RUN npm set registry {{registry}}
5
- RUN npm set proxy {{proxy}}
6
- RUN npm i -g @toa.io/runtime@{{version}}
4
+ RUN if [ {{runtime.registry}} != undefined ]; then npm set registry {{runtime.registry}}; fi
5
+ RUN if [ {{runtime.proxy}} != undefined ]; then npm set proxy {{runtime.proxy}}; fi
6
+ RUN npm i -g @toa.io/runtime@{{runtime.version}}
7
7
 
8
8
  WORKDIR /service
9
9
  ADD . .
@@ -28,11 +28,12 @@ class Service extends Image {
28
28
  /**
29
29
  * @param {string} scope
30
30
  * @param {toa.norm.context.Runtime} runtime
31
+ * @param {toa.norm.context.Registry} registry
31
32
  * @param {string} reference
32
33
  * @param {toa.deployment.dependency.Service} service
33
34
  */
34
- constructor (scope, runtime, reference, service) {
35
- super(scope, runtime)
35
+ constructor (scope, runtime, registry, reference, service) {
36
+ super(scope, runtime, registry)
36
37
 
37
38
  this.service = service.name
38
39
 
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { directory } = require('@toa.io/filesystem')
3
+ const workspace = require('./workspace')
4
4
 
5
5
  /**
6
6
  * @implements {toa.deployment.Operator}
@@ -8,12 +8,13 @@ const { directory } = require('@toa.io/filesystem')
8
8
  class Operator {
9
9
  /** @type {toa.deployment.Deployment} */
10
10
  #deployment
11
- /** @type {toa.deployment.images.Registry} */
11
+
12
+ /** @type {toa.deployment.Registry} */
12
13
  #registry
13
14
 
14
15
  /**
15
16
  * @param deployment {toa.deployment.Deployment}
16
- * @param registry {toa.deployment.images.Registry}
17
+ * @param registry {toa.deployment.Registry}
17
18
  */
18
19
  constructor (deployment, registry) {
19
20
  this.#deployment = deployment
@@ -21,7 +22,7 @@ class Operator {
21
22
  }
22
23
 
23
24
  async export (path) {
24
- const target = await Operator.#target('deployment', path)
25
+ const target = await workspace.create('deployment', path)
25
26
 
26
27
  await this.#deployment.export(target)
27
28
 
@@ -29,61 +30,32 @@ class Operator {
29
30
  }
30
31
 
31
32
  async prepare (path) {
32
- const target = await Operator.#target('images', path)
33
-
34
- await this.#registry.prepare(target)
35
-
36
- return target
33
+ return await this.#registry.prepare(path)
37
34
  }
38
35
 
39
- async build () {
40
- const target = await Operator.#target('images')
41
-
42
- await this.#registry.prepare(target)
36
+ async push () {
43
37
  await this.#registry.push()
44
-
45
- await directory.remove(target)
46
38
  }
47
39
 
48
40
  async install (options = {}) {
49
41
  options = Object.assign({}, OPTIONS, options)
50
42
 
51
- const [source] = await Promise.all([this.export(), this.build()])
52
-
43
+ await Promise.all([this.export(), this.push()])
53
44
  await this.#deployment.install(options)
54
-
55
- await directory.remove(source)
56
45
  }
57
46
 
58
47
  async template (options = {}) {
59
- const source = await this.export()
60
- const output = await this.#deployment.template(options)
48
+ await this.export()
61
49
 
62
- await directory.remove(source)
63
-
64
- return output
50
+ return await this.#deployment.template(options)
65
51
  }
66
52
 
67
53
  variables () {
68
54
  return this.#deployment.variables()
69
55
  }
70
-
71
- /**
72
- * @param type {string}
73
- * @param [path] {string}
74
- * @returns {Promise<string>}
75
- */
76
- static async #target (type, path) {
77
- if (path === undefined) path = await directory.temp('toa-' + type)
78
- else path = await directory.ensure(path)
79
-
80
- return path
81
- }
82
56
  }
83
57
 
84
58
  /** @type {toa.deployment.installation.Options} */
85
- const OPTIONS = {
86
- wait: false
87
- }
59
+ const OPTIONS = { wait: false }
88
60
 
89
61
  exports.Operator = Operator
@@ -14,12 +14,12 @@ describe('env', () => {
14
14
  /** @type {toa.deployment.Deployment} */
15
15
  let deployment
16
16
 
17
- /** @type {toa.deployment.images.Registry} */
17
+ /** @type {toa.deployment.Registry} */
18
18
  let registry
19
19
 
20
20
  beforeEach(() => {
21
21
  deployment = /** @type {toa.deployment.Deployment} */ {}
22
- registry = /** @type {toa.deployment.images.Registry} */ {}
22
+ registry = /** @type {toa.deployment.Registry} */ {}
23
23
  })
24
24
 
25
25
  it('should be', async () => {
@@ -31,7 +31,10 @@ describe('env', () => {
31
31
  it('should return variables', async () => {
32
32
  const variables = { [generate()]: { name: generate(), value: generate() } }
33
33
 
34
- deployment.variables = jest.fn(() => variables)
34
+ deployment.variables =
35
+ /** @type {typeof toa.deployment.Operator.variables} */
36
+ jest.fn(() => variables)
37
+
35
38
  operator = new Operator(deployment, registry)
36
39
 
37
40
  const output = operator.variables()
@@ -1,18 +1,21 @@
1
1
  'use strict'
2
2
 
3
- const { directory: { remove } } = require('@toa.io/filesystem')
3
+ const workspace = require('./workspace')
4
4
 
5
5
  /**
6
- * @implements {toa.deployment.images.Registry}
6
+ * @implements {toa.deployment.Registry}
7
7
  */
8
8
  class Registry {
9
9
  /** @type {toa.norm.context.Registry} */
10
10
  #registry
11
+
11
12
  /** @type {toa.deployment.images.Factory} */
12
13
  #factory
14
+
13
15
  /** @type {toa.operations.Process} */
14
16
  #process
15
- /** @type {Array<toa.deployment.images.Image>} */
17
+
18
+ /** @type {toa.deployment.images.Image[]} */
16
19
  #images = []
17
20
 
18
21
  /**
@@ -34,15 +37,24 @@ class Registry {
34
37
  return this.#create('service', path, service)
35
38
  }
36
39
 
37
- async prepare (target) {
38
- await Promise.all(this.#images.map((image) => image.prepare(target)))
40
+ async prepare (root) {
41
+ const path = await workspace.create('images', root)
42
+
43
+ await Promise.all(this.#images.map((image) => image.prepare(path)))
44
+
45
+ return path
46
+ }
47
+
48
+ async build () {
49
+ await this.prepare()
50
+
51
+ for (const image of this.#images) await this.#build(image)
39
52
  }
40
53
 
41
54
  async push () {
42
- for (const image of this.#images) {
43
- await this.#push(image)
44
- await remove(image.context)
45
- }
55
+ await this.prepare()
56
+
57
+ for (const image of this.#images) await this.#push(image)
46
58
  }
47
59
 
48
60
  /**
@@ -53,7 +65,6 @@ class Registry {
53
65
  #create (type, ...args) {
54
66
  const image = this.#factory[type](...args)
55
67
 
56
- image.tag(this.#registry.base)
57
68
  this.#images.push(image)
58
69
 
59
70
  return image
@@ -61,39 +72,48 @@ class Registry {
61
72
 
62
73
  /**
63
74
  * @param {toa.deployment.images.Image} image
75
+ * @param {boolean} [push]
64
76
  * @returns {Promise<void>}
65
77
  */
66
- async #push (image) {
67
- const args = ['--context=default', 'buildx', 'build', '--push', '--tag', image.reference, image.context]
68
- const local = this.#registry.platforms === null
78
+ async #build (image, push = false) {
79
+ const args = ['--context=default', 'buildx', 'build']
80
+
81
+ if (push) args.push('--push')
82
+
83
+ args.push('--tag', image.reference, image.context)
84
+
85
+ const multiarch = this.#registry.platforms !== null
69
86
 
70
- if (local) {
71
- args.push('--builder', 'default')
72
- } else {
87
+ if (multiarch) {
73
88
  const platform = this.#registry.platforms.join(',')
74
89
 
75
90
  args.push('--platform', platform)
76
91
  args.push('--builder', BUILDER)
77
92
 
78
- await this.#builder()
79
- }
93
+ await this.#ensureBuilder()
94
+ } else args.push('--builder', 'default')
80
95
 
81
96
  await this.#process.execute('docker', args)
82
97
  }
83
98
 
84
- async #builder () {
99
+ async #push (image) {
100
+ await this.#build(image, true)
101
+ }
102
+
103
+ async #ensureBuilder () {
85
104
  const ls = 'buildx ls'.split(' ')
86
105
  const output = await this.#process.execute('docker', ls, { silently: true })
106
+ const exists = output.split('\n').findIndex((line) => line.startsWith('toa '))
87
107
 
88
- const exists = output.split('\n').find((line) => line.startsWith('toa '))
108
+ if (exists === -1) await this.#createBuilder()
109
+ }
89
110
 
90
- if (exists === undefined) {
91
- const create = `buildx create --name ${BUILDER} --use`.split(' ')
92
- const bootstrap = 'buildx inspect --bootstrap'.split(' ')
111
+ async #createBuilder () {
112
+ const create = `buildx create --name ${BUILDER} --use`.split(' ')
113
+ const bootstrap = 'buildx inspect --bootstrap'.split(' ')
93
114
 
94
- await this.#process.execute('docker', create)
95
- await this.#process.execute('docker', bootstrap)
96
- }
115
+ await this.#process.execute('docker', create)
116
+ await this.#process.execute('docker', bootstrap)
97
117
  }
98
118
  }
99
119
 
@@ -0,0 +1,17 @@
1
+ 'use strict'
2
+
3
+ const { directory } = require('@toa.io/filesystem')
4
+
5
+ /**
6
+ * @param {string} type
7
+ * @param {string} [path]
8
+ * @return {Promise<string>}
9
+ */
10
+ async function create (type, path) {
11
+ if (path === undefined) path = await directory.temp('toa-' + type)
12
+ else path = await directory.ensure(path)
13
+
14
+ return path
15
+ }
16
+
17
+ exports.create = create
package/src/process.js CHANGED
@@ -7,6 +7,8 @@ const execa = require('execa')
7
7
  */
8
8
  class Process {
9
9
  async execute (cmd, args, options = {}) {
10
+ console.log('toa>', cmd, args.join(' '))
11
+
10
12
  /** @type {execa.ExecaReturnValue<import('stream').Stream>} */
11
13
  const command = execa(cmd, args)
12
14
 
@@ -1,12 +1,10 @@
1
- // noinspection ES6UnusedImports
2
-
3
- import type { Deployable } from './deployment'
1
+ import type * as _deployment from './deployment'
4
2
 
5
3
  declare namespace toa.deployment {
6
4
 
7
- interface Composition extends Deployable {
8
- components: Array<string>
9
- }
5
+ interface Composition extends _deployment.Deployable {
6
+ components: Array<string>
7
+ }
10
8
 
11
9
  }
12
10
 
@@ -1,6 +1,4 @@
1
- // noinspection JSUnusedGlobalSymbols,ES6UnusedImports
2
-
3
- import { Service } from './service'
1
+ import * as _service from './service'
4
2
  import { dependencies } from '@toa.io/norm/types/context'
5
3
 
6
4
  declare namespace toa.deployment {
@@ -58,20 +56,17 @@ declare namespace toa.deployment {
58
56
 
59
57
  type Dependency = {
60
58
  references?: dependency.Reference[]
61
- services?: Service[] // deployment.Service
59
+ services?: _service.Service[] // deployment.Service
62
60
  proxies?: dependency.Proxy[]
63
61
  variables?: dependency.Variables
64
62
  }
65
63
 
66
64
  }
67
65
 
68
- export namespace dependency {
69
- export type Declaration = toa.deployment.dependency.Declaration
70
- export type Reference = toa.deployment.dependency.Reference
71
- export type Service = toa.deployment.dependency.Service
72
- export type Proxy = toa.deployment.dependency.Proxy
73
- export type Variables = toa.deployment.dependency.Variables
74
- export type Variable = toa.deployment.dependency.Variable
75
- }
76
-
66
+ export type Declaration = toa.deployment.dependency.Declaration
67
+ export type Reference = toa.deployment.dependency.Reference
68
+ export type Service = toa.deployment.dependency.Service
69
+ export type Proxy = toa.deployment.dependency.Proxy
70
+ export type Variables = toa.deployment.dependency.Variables
71
+ export type Variable = toa.deployment.dependency.Variable
77
72
  export type Dependency = toa.deployment.Dependency
@@ -1,8 +1,6 @@
1
- // noinspection ES6UnusedImports,JSUnusedGlobalSymbols
2
-
3
- import type { Composition } from './composition'
4
- import type { Service } from './service'
5
- import type { dependency } from './dependency'
1
+ import type * as _composition from './composition'
2
+ import type * as _service from './service'
3
+ import type * as _dependency from './dependency'
6
4
 
7
5
  declare namespace toa.deployment {
8
6
 
@@ -13,15 +11,15 @@ declare namespace toa.deployment {
13
11
  description?: string
14
12
  version: string
15
13
  appVersion: string
16
- dependencies: dependency.Reference[]
14
+ dependencies: _dependency.Reference[]
17
15
  }
18
16
 
19
17
  interface Contents {
20
- compositions?: Composition[]
18
+ compositions?: _composition.Composition[]
21
19
  components?: string[]
22
- services?: Service[]
23
- proxies?: dependency.Proxy[]
24
- variables?: dependency.Variables
20
+ services?: _service.Service[]
21
+ proxies?: _dependency.Proxy[]
22
+ variables?: _dependency.Variables
25
23
 
26
24
  [key: string]: Object
27
25
  }
@@ -38,7 +36,7 @@ declare namespace toa.deployment {
38
36
 
39
37
  namespace template {
40
38
  interface Options {
41
- namespace: string
39
+ namespace?: string
42
40
  }
43
41
  }
44
42
 
@@ -54,7 +52,7 @@ declare namespace toa.deployment {
54
52
 
55
53
  template(options: template.Options): Promise<string>
56
54
 
57
- variables(): dependency.Variables
55
+ variables(): _dependency.Variables
58
56
  }
59
57
 
60
58
  }
@@ -1,11 +1,13 @@
1
- // noinspection ES6UnusedImports
2
- import type { Operator } from './operator'
1
+ import type * as _operator from './operator'
2
+ import * as _registry from './registry'
3
3
 
4
4
  declare namespace toa.deployment {
5
5
 
6
- interface Factory {
7
- operator(): Operator
8
- }
6
+ interface Factory {
7
+ operator(): _operator.Operator
8
+
9
+ registry(): _registry.Registry
10
+ }
9
11
 
10
12
  }
11
13
 
@@ -1,13 +1,11 @@
1
1
  declare namespace toa.deployment.images {
2
2
 
3
- export interface Image {
4
- readonly reference: string
5
- readonly context: string
3
+ export interface Image {
4
+ readonly reference: string
5
+ readonly context: string
6
6
 
7
- tag(base: string): void
8
-
9
- prepare(root: string): Promise<string>
10
- }
7
+ prepare(root: string): Promise<string>
8
+ }
11
9
 
12
10
  }
13
11
 
@@ -1,5 +1,3 @@
1
- // noinspection ES6UnusedImports
2
-
3
1
  import * as _deployment from './deployment'
4
2
  import * as _dependency from './dependency'
5
3
 
@@ -8,15 +6,11 @@ declare namespace toa.deployment {
8
6
  interface Operator {
9
7
  export(path?: string): Promise<string>
10
8
 
11
- prepare(path?: string): Promise<string>
12
-
13
- build(): Promise<void>
14
-
15
9
  install(options?: _deployment.installation.Options): Promise<void>
16
10
 
17
11
  template(options?: _deployment.template.Options): Promise<string>
18
12
 
19
- variables(): _dependency.dependency.Variables
13
+ variables(): _dependency.Variables
20
14
  }
21
15
 
22
16
  }
@@ -0,0 +1,21 @@
1
+ import type * as _norm from '@toa.io/norm/types'
2
+ import type * as _dependency from './dependency'
3
+ import type * as _image from "./images/image"
4
+
5
+ declare namespace toa.deployment {
6
+
7
+ interface Registry {
8
+ composition(composition: _norm.Composition): _image.Image
9
+
10
+ service(path: string, service: _dependency.Service): _image.Image
11
+
12
+ prepare(path: string): Promise<string>
13
+
14
+ build(): Promise<void>
15
+
16
+ push(): Promise<void>
17
+ }
18
+
19
+ }
20
+
21
+ export type Registry = toa.deployment.Registry
@@ -1,20 +1,18 @@
1
- // noinspection ES6UnusedImports
2
-
3
- import type { Deployable } from './deployment'
1
+ import type * as _deployment from './deployment'
4
2
 
5
3
  declare namespace toa.deployment {
6
4
 
7
- interface Ingress {
8
- host: string
9
- class: string
10
- annotations?: object
11
- }
5
+ interface Ingress {
6
+ host: string
7
+ class: string
8
+ annotations?: object
9
+ }
10
+
11
+ interface Service extends _deployment.Deployable {
12
+ port: number
13
+ ingress?: Ingress
14
+ }
12
15
 
13
- interface Service extends Deployable {
14
- port: number
15
- ingress?: Ingress
16
- }
17
-
18
16
  }
19
17
 
20
18
  export type Service = toa.deployment.Service
@@ -1 +0,0 @@
1
- export { Dependency, dependency } from './dependency'
File without changes
File without changes