platformatic 0.24.0 → 0.26.0

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/cli.js CHANGED
@@ -3,7 +3,9 @@
3
3
  import commist from 'commist'
4
4
  import minimist from 'minimist'
5
5
  import { runDB } from '@platformatic/db/db.mjs'
6
+ import { run as runRuntime } from '@platformatic/runtime/runtime.mjs'
6
7
  import { runService } from '@platformatic/service/service.mjs'
8
+ import { runComposer } from '@platformatic/composer/composer.mjs'
7
9
  import { startCommand } from '@platformatic/start'
8
10
  import { login } from '@platformatic/authenticate/authenticate.js'
9
11
  import { command as client } from '@platformatic/client-cli'
@@ -38,12 +40,15 @@ const ensureCommand = async ({ output, help }) => {
38
40
  }
39
41
 
40
42
  program.register('db', async (args) => ensureCommand(await runDB(args)))
43
+ program.register('runtime', async (args) => ensureCommand(await runRuntime(args)))
41
44
  program.register('service', async (args) => ensureCommand(await runService(args)))
42
45
  program.register('start', startCommand)
46
+ program.register('composer', async (args) => ensureCommand(await runComposer(args)))
43
47
  program.register('upgrade', upgrade)
44
48
  program.register('client', client)
45
49
  program.register('help', help.toStdout)
46
50
  program.register('help db', async (args) => runDB(['help', ...args]))
51
+ program.register('help runtime', async (args) => runRuntime(['help', ...args]))
47
52
  program.register('help service', async (args) => runService(['help', ...args]))
48
53
  program.register({ command: 'login', strict: true }, login)
49
54
  program.register('gh', gh)
package/help/deploy.txt CHANGED
@@ -8,6 +8,7 @@ Options:
8
8
 
9
9
  -t, --type static/dynamic The type of the workspace.
10
10
  -c, --config FILE Specify a configuration file to use
11
+ -k, --keys FILE Specify a path to the workspace keys file
11
12
  -l --label TEXT The deploy label. Only for dynamic workspaces.
12
13
  -e --env FILE The environment file to use. Default: ".env"
13
14
  -s --secrets FILE The secrets file to use. Default: ".secrets.env"
@@ -16,7 +17,8 @@ Options:
16
17
 
17
18
  To deploy a Platformatic application to the cloud you should go to the
18
19
  Platformatic cloud dashboard and create a workspace. Then you can get your
19
- workspace id and key from the workspace settings page.
20
+ workspace id and key from the workspace settings page or download a workspace
21
+ env file and use it with the --keys option.
20
22
 
21
23
  Tp deploy an application to a dynamic workspace, you will need to specify the
22
24
  deploy label. You can get it in you cloud dashboard or specify a new one.
package/help/help.txt CHANGED
@@ -7,4 +7,5 @@ Welcome to Platformatic. Available commands are:
7
7
  * upgrade - upgrade the Platformatic configuration to the latest version.
8
8
  * gh - creates a new gh action for Platformatic deployments
9
9
  * deploy - deploy a Platformatic application to the cloud
10
+ * runtime - start Platformatic Runtime; type `platformatic runtime help` to know more.
10
11
  * start - start a Platformatic application
package/lib/deploy.js CHANGED
@@ -1,9 +1,11 @@
1
1
  'use strict'
2
2
 
3
- import { isAbsolute, dirname, relative } from 'path'
3
+ import { isAbsolute, dirname, relative, join } from 'path'
4
+ import { readFile } from 'fs/promises'
4
5
 
5
6
  import pino from 'pino'
6
7
  import pretty from 'pino-pretty'
8
+ import dotenv from 'dotenv'
7
9
  import inquirer from 'inquirer'
8
10
  import parseArgs from 'minimist'
9
11
  import deployClient from '@platformatic/deploy-client'
@@ -18,11 +20,100 @@ const logger = pino(pretty({
18
20
  ignore: 'hostname,pid'
19
21
  }))
20
22
 
23
+ async function askWorkspaceDetails (args) {
24
+ let workspaceType = args.type
25
+ /* c8 ignore next 9 */
26
+ if (!workspaceType) {
27
+ const answer = await inquirer.prompt({
28
+ type: 'list',
29
+ name: 'workspaceType',
30
+ message: 'Select workspace type:',
31
+ choices: WORKSPACE_TYPES
32
+ })
33
+ workspaceType = answer.workspaceType
34
+ }
35
+
36
+ if (!WORKSPACE_TYPES.includes(workspaceType)) {
37
+ throw new Error(
38
+ `Invalid workspace type provided: "${workspaceType}". ` +
39
+ `Type must be one of: ${WORKSPACE_TYPES.join(', ')}.`
40
+ )
41
+ }
42
+
43
+ let workspaceId = args['workspace-id']
44
+ /* c8 ignore next 8 */
45
+ if (!workspaceId) {
46
+ const answer = await inquirer.prompt({
47
+ type: 'input',
48
+ name: 'workspaceId',
49
+ message: 'Enter workspace id:'
50
+ })
51
+ workspaceId = answer.workspaceId
52
+ }
53
+
54
+ if (!UUID_REGEX.test(workspaceId)) {
55
+ throw new Error('Invalid workspace id provided. Workspace id must be a valid uuid.')
56
+ }
57
+
58
+ let workspaceKey = args['workspace-key']
59
+ /* c8 ignore next 9 */
60
+ if (!workspaceKey) {
61
+ const answer = await inquirer.prompt({
62
+ type: 'password',
63
+ name: 'workspaceKey',
64
+ message: 'Enter workspace key:',
65
+ mask: '*'
66
+ })
67
+ workspaceKey = answer.workspaceKey
68
+ }
69
+
70
+ return {
71
+ workspaceType,
72
+ workspaceId,
73
+ workspaceKey
74
+ }
75
+ }
76
+
77
+ async function readWorkspaceDetails (workspaceKeysPath) {
78
+ /* c8 ignore next 3 */
79
+ if (!isAbsolute(workspaceKeysPath)) {
80
+ workspaceKeysPath = join(process.cwd(), workspaceKeysPath)
81
+ }
82
+
83
+ const workspaceFile = await readFile(workspaceKeysPath, 'utf8')
84
+ const workspaceEnvVars = dotenv.parse(workspaceFile)
85
+
86
+ if (
87
+ workspaceEnvVars.PLATFORMATIC_DYNAMIC_WORKSPACE_ID &&
88
+ workspaceEnvVars.PLATFORMATIC_DYNAMIC_WORKSPACE_API_KEY
89
+ ) {
90
+ return {
91
+ workspaceType: 'dynamic',
92
+ workspaceId: workspaceEnvVars.PLATFORMATIC_DYNAMIC_WORKSPACE_ID,
93
+ workspaceKey: workspaceEnvVars.PLATFORMATIC_DYNAMIC_WORKSPACE_API_KEY
94
+ }
95
+ }
96
+
97
+ if (
98
+ workspaceEnvVars.PLATFORMATIC_STATIC_WORKSPACE_ID &&
99
+ workspaceEnvVars.PLATFORMATIC_STATIC_WORKSPACE_API_KEY
100
+ ) {
101
+ return {
102
+ workspaceType: 'static',
103
+ workspaceId: workspaceEnvVars.PLATFORMATIC_STATIC_WORKSPACE_ID,
104
+ workspaceKey: workspaceEnvVars.PLATFORMATIC_STATIC_WORKSPACE_API_KEY
105
+ }
106
+ }
107
+
108
+ throw new Error('Could not find workspace keys in provided file.')
109
+ }
110
+
21
111
  export async function deploy (argv) {
22
112
  try {
23
113
  const args = parseArgs(argv, {
24
114
  alias: {
25
115
  config: 'c',
116
+ keys: 'k',
26
117
  type: 't',
27
118
  label: 'l',
28
119
  env: 'e',
@@ -42,51 +133,12 @@ export async function deploy (argv) {
42
133
  }
43
134
  })
44
135
 
45
- let workspaceType = args.type
46
- /* c8 ignore next 9 */
47
- if (!workspaceType) {
48
- const answer = await inquirer.prompt({
49
- type: 'list',
50
- name: 'workspaceType',
51
- message: 'Select workspace type:',
52
- choices: WORKSPACE_TYPES
53
- })
54
- workspaceType = answer.workspaceType
55
- }
56
-
57
- if (!WORKSPACE_TYPES.includes(workspaceType)) {
58
- throw new Error(
59
- `Invalid workspace type provided: "${workspaceType}". ` +
60
- `Type must be one of: ${WORKSPACE_TYPES.join(', ')}.`
61
- )
62
- }
63
-
64
- let workspaceId = args['workspace-id']
65
- /* c8 ignore next 8 */
66
- if (!workspaceId) {
67
- const answer = await inquirer.prompt({
68
- type: 'input',
69
- name: 'workspaceId',
70
- message: 'Enter workspace id:'
71
- })
72
- workspaceId = answer.workspaceId
73
- }
136
+ const workspaceKeysPath = args.keys
137
+ const workspaceDetails = workspaceKeysPath
138
+ ? await readWorkspaceDetails(workspaceKeysPath)
139
+ : await askWorkspaceDetails(args)
74
140
 
75
- if (!UUID_REGEX.test(workspaceId)) {
76
- throw new Error('Invalid workspace id provided. Workspace id must be a valid uuid.')
77
- }
78
-
79
- let workspaceKey = args['workspace-key']
80
- /* c8 ignore next 9 */
81
- if (!workspaceKey) {
82
- const answer = await inquirer.prompt({
83
- type: 'password',
84
- name: 'workspaceKey',
85
- message: 'Enter workspace key:',
86
- mask: '*'
87
- })
88
- workspaceKey = answer.workspaceKey
89
- }
141
+ const { workspaceType, workspaceId, workspaceKey } = workspaceDetails
90
142
 
91
143
  let label = args.label
92
144
  if (workspaceType === 'dynamic') {
package/lib/gh.js CHANGED
@@ -9,12 +9,12 @@ import pino from 'pino'
9
9
  import pretty from 'pino-pretty'
10
10
  import ConfigManager from '@platformatic/config'
11
11
 
12
- export const createGHAction = async (logger, workspaceId, env, config, buildTS, type, projectDir = process.cwd()) => {
12
+ export const createGHAction = async (logger, env, config, buildTS, type, projectDir = process.cwd()) => {
13
13
  if (type === 'static') {
14
- await createStaticWorkspaceGHAction(logger, workspaceId, env, config, projectDir, buildTS)
14
+ await createStaticWorkspaceGHAction(logger, env, config, projectDir, buildTS)
15
15
  return
16
16
  }
17
- await createDynamicWorkspaceGHAction(logger, workspaceId, env, config, projectDir, buildTS)
17
+ await createDynamicWorkspaceGHAction(logger, env, config, projectDir, buildTS)
18
18
  }
19
19
 
20
20
  const logger = pino(pretty({
@@ -43,18 +43,11 @@ export const gh = async (argv) => {
43
43
  config: 'c',
44
44
  type: 't',
45
45
  help: 'h',
46
- build: 'b',
47
- workspace: 'w'
46
+ build: 'b'
48
47
  },
49
48
  boolean: ['build']
50
49
  })
51
50
 
52
- // Validations:
53
- if (!args.workspace) {
54
- logger.error('Workspace ID is required')
55
- process.exit(1)
56
- }
57
-
58
51
  if (!['static', 'dynamic'].includes(args.type)) {
59
52
  logger.error(`Invalid type: [${args.type}]. Type must be either static or dynamic`)
60
53
  process.exit(1)
@@ -80,8 +73,9 @@ export const gh = async (argv) => {
80
73
  plt_custom_variable: 'change-me',
81
74
  custom_variable1: 'change-me'
82
75
  }
83
- await createGHAction(logger, args.workspace, env, configFilename, args.build, args.type)
76
+ await createGHAction(logger, env, configFilename, args.build, args.type)
84
77
 
78
+ const workspaceName = args.type === 'static' ? 'PLATFORMATIC_STATIC_WORKSPACE_ID ' : 'PLATFORMATIC_DYNAMIC_WORKSPACE_ID'
85
79
  const secretName = args.type === 'static' ? 'PLATFORMATIC_STATIC_WORKSPACE_API_KEY' : 'PLATFORMATIC_DYNAMIC_WORKSPACE_API_KEY'
86
- logger.info(`Github action successfully created for workspace ${args.workspace}, please add ${secretName} as repository secret.`)
80
+ logger.info(`Github action successfully created please add ${workspaceName} and ${secretName} as repository secrets.`)
87
81
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "platformatic",
3
- "version": "0.24.0",
3
+ "version": "0.26.0",
4
4
  "description": "Platformatic CLI",
5
5
  "main": "cli.js",
6
6
  "type": "module",
@@ -36,30 +36,33 @@
36
36
  "split2": "^4.2.0",
37
37
  "standard": "^17.0.0",
38
38
  "tap": "^16.3.4",
39
- "undici": "^5.22.0"
39
+ "undici": "^5.22.1"
40
40
  },
41
41
  "dependencies": {
42
42
  "colorette": "^2.0.20",
43
43
  "commist": "^3.2.0",
44
44
  "desm": "^1.3.0",
45
+ "dotenv": "^16.1.1",
45
46
  "help-me": "^4.2.0",
46
- "inquirer": "^9.2.0",
47
+ "inquirer": "^9.2.6",
47
48
  "minimist": "^1.2.8",
48
- "pino": "^8.12.0",
49
+ "pino": "^8.14.1",
49
50
  "pino-pretty": "^10.0.0",
50
- "@platformatic/authenticate": "0.24.0",
51
- "@platformatic/client-cli": "0.24.0",
52
- "@platformatic/config": "0.24.0",
53
- "@platformatic/db": "0.24.0",
54
- "@platformatic/deploy-client": "0.24.0",
55
- "@platformatic/metaconfig": "0.24.0",
56
- "@platformatic/service": "0.24.0",
57
- "@platformatic/start": "0.24.0",
58
- "create-platformatic": "0.24.0"
51
+ "@platformatic/authenticate": "0.26.0",
52
+ "@platformatic/client-cli": "0.26.0",
53
+ "@platformatic/config": "0.26.0",
54
+ "@platformatic/composer": "0.26.0",
55
+ "@platformatic/db": "0.26.0",
56
+ "@platformatic/deploy-client": "0.26.0",
57
+ "@platformatic/metaconfig": "0.26.0",
58
+ "@platformatic/runtime": "0.26.0",
59
+ "@platformatic/service": "0.26.0",
60
+ "@platformatic/start": "0.26.0",
61
+ "create-platformatic": "0.26.0"
59
62
  },
60
63
  "scripts": {
61
64
  "test": "standard | snazzy && c8 --100 tap --no-coverage test/*.test.js",
62
65
  "lint": "standard | snazzy",
63
- "license": "license-checker --production --onlyAllow 'Apache-2.0;MIT;ISC;BSD-2-Clause'"
66
+ "license": "license-checker --production --onlyAllow 'Apache-2.0;MIT;ISC;BSD-2-Clause;BSD-3-Clause'"
64
67
  }
65
68
  }
@@ -29,6 +29,9 @@ test('should deploy to a static workspace to the cloud', async (t) => {
29
29
  t.same(
30
30
  request.body,
31
31
  {
32
+ metadata: {
33
+ appType: 'db'
34
+ },
32
35
  variables: {
33
36
  PLT_ENV_VARIABLE1: 'platformatic_variable1',
34
37
  PLT_ENV_VARIABLE2: 'platformatic_variable2'
@@ -80,6 +83,9 @@ test('should deploy to a dynamic workspace to the cloud', async (t) => {
80
83
  request.body,
81
84
  {
82
85
  label,
86
+ metadata: {
87
+ appType: 'db'
88
+ },
83
89
  variables: {
84
90
  PLT_ENV_VARIABLE1: 'platformatic_variable1',
85
91
  PLT_ENV_VARIABLE2: 'platformatic_variable2'
@@ -174,6 +180,9 @@ test('should deploy to a dynamic workspace to the cloud', async (t) => {
174
180
  request.body,
175
181
  {
176
182
  label,
183
+ metadata: {
184
+ appType: 'db'
185
+ },
177
186
  variables: {
178
187
  PLT_ENV_VARIABLE1: 'platformatic_variable1',
179
188
  PLT_ENV_VARIABLE2: 'platformatic_variable2'
@@ -198,3 +207,177 @@ test('should deploy to a dynamic workspace to the cloud', async (t) => {
198
207
  '--deploy-service-host', deployServiceHost
199
208
  ])
200
209
  })
210
+
211
+ test('should deploy to a static workspace with a keys option', async (t) => {
212
+ const workspaceId = 'b3d7f7e0-8c03-11e8-9eb6-529269fb1459'
213
+ const workspaceKey = 'b3d7f7e08c0311e89eb6529269fb1459'
214
+
215
+ const pathToConfig = join(import.meta.url, './fixtures/app-to-deploy/platformatic.db.json')
216
+ const pathToKeys = join(import.meta.url, './fixtures/app-to-deploy/static.txt')
217
+
218
+ const machineHost = await startMachine(t)
219
+ const deployServiceHost = await startDeployService(t, {
220
+ createBundleCallback: (request, reply) => {
221
+ t.equal(request.headers['x-platformatic-workspace-id'], workspaceId)
222
+ t.equal(request.headers['x-platformatic-api-key'], workspaceKey)
223
+ t.match(request.body, {
224
+ bundle: {
225
+ appType: 'db',
226
+ configPath: 'platformatic.db.json'
227
+ }
228
+ })
229
+ t.ok(request.body.bundle.checksum)
230
+ },
231
+ createDeploymentCallback: (request, reply) => {
232
+ t.equal(request.headers['x-platformatic-workspace-id'], workspaceId)
233
+ t.equal(request.headers['x-platformatic-api-key'], workspaceKey)
234
+ t.same(
235
+ request.body,
236
+ {
237
+ metadata: {
238
+ appType: 'db'
239
+ },
240
+ variables: {
241
+ PLT_ENV_VARIABLE1: 'platformatic_variable1',
242
+ PLT_ENV_VARIABLE2: 'platformatic_variable2'
243
+ },
244
+ secrets: {
245
+ PLT_SECRET_1: 'platformatic_secret_1',
246
+ PLT_SECRET_2: 'platformatic_secret_2'
247
+ }
248
+ }
249
+ )
250
+ reply.code(200).send({ entryPointUrl: machineHost })
251
+ }
252
+ })
253
+
254
+ await execa('node', [
255
+ cliPath, 'deploy',
256
+ '--keys', pathToKeys,
257
+ '--config', pathToConfig,
258
+ '--deploy-service-host', deployServiceHost
259
+ ])
260
+ })
261
+
262
+ test('should deploy to a static workspace with a keys option', async (t) => {
263
+ const workspaceId = 'b3d7f7e0-8c03-11e8-9eb6-529269fb1459'
264
+ const workspaceKey = 'b3d7f7e08c0311e89eb6529269fb1459'
265
+
266
+ const pathToConfig = join(import.meta.url, './fixtures/app-to-deploy/platformatic.db.json')
267
+ const pathToKeys = './static.txt'
268
+
269
+ const machineHost = await startMachine(t)
270
+ const deployServiceHost = await startDeployService(t, {
271
+ createBundleCallback: (request, reply) => {
272
+ t.equal(request.headers['x-platformatic-workspace-id'], workspaceId)
273
+ t.equal(request.headers['x-platformatic-api-key'], workspaceKey)
274
+ t.match(request.body, {
275
+ bundle: {
276
+ appType: 'db',
277
+ configPath: 'platformatic.db.json'
278
+ }
279
+ })
280
+ t.ok(request.body.bundle.checksum)
281
+ },
282
+ createDeploymentCallback: (request, reply) => {
283
+ t.equal(request.headers['x-platformatic-workspace-id'], workspaceId)
284
+ t.equal(request.headers['x-platformatic-api-key'], workspaceKey)
285
+ t.same(
286
+ request.body,
287
+ {
288
+ metadata: {
289
+ appType: 'db'
290
+ },
291
+ variables: {
292
+ PLT_ENV_VARIABLE1: 'platformatic_variable1',
293
+ PLT_ENV_VARIABLE2: 'platformatic_variable2'
294
+ },
295
+ secrets: {
296
+ PLT_SECRET_1: 'platformatic_secret_1',
297
+ PLT_SECRET_2: 'platformatic_secret_2'
298
+ }
299
+ }
300
+ )
301
+ reply.code(200).send({ entryPointUrl: machineHost })
302
+ }
303
+ })
304
+
305
+ await execa('node', [
306
+ cliPath, 'deploy',
307
+ '--keys', pathToKeys,
308
+ '--config', pathToConfig,
309
+ '--deploy-service-host', deployServiceHost
310
+ ], {
311
+ cwd: join(import.meta.url, './fixtures/app-to-deploy')
312
+ })
313
+ })
314
+
315
+ test('should deploy to a dynamic workspace with a keys option', async (t) => {
316
+ const workspaceId = 'b3d7f7e0-8c03-11e8-9eb6-529269fb1459'
317
+ const workspaceKey = 'b3d7f7e08c0311e89eb6529269fb1459'
318
+ const label = 'cli:deploy-2'
319
+
320
+ const pathToConfig = join(import.meta.url, './fixtures/app-to-deploy/platformatic.db.json')
321
+ const pathToKeys = join(import.meta.url, './fixtures/app-to-deploy/dynamic.txt')
322
+
323
+ const machineHost = await startMachine(t)
324
+ const deployServiceHost = await startDeployService(t, {
325
+ createBundleCallback: (request, reply) => {
326
+ t.equal(request.headers['x-platformatic-workspace-id'], workspaceId)
327
+ t.equal(request.headers['x-platformatic-api-key'], workspaceKey)
328
+ t.match(request.body, {
329
+ bundle: {
330
+ appType: 'db',
331
+ configPath: 'platformatic.db.json'
332
+ }
333
+ })
334
+ t.ok(request.body.bundle.checksum)
335
+ },
336
+ createDeploymentCallback: (request, reply) => {
337
+ t.equal(request.headers['x-platformatic-workspace-id'], workspaceId)
338
+ t.equal(request.headers['x-platformatic-api-key'], workspaceKey)
339
+ t.same(
340
+ request.body,
341
+ {
342
+ label,
343
+ metadata: {
344
+ appType: 'db'
345
+ },
346
+ variables: {
347
+ PLT_ENV_VARIABLE1: 'platformatic_variable1',
348
+ PLT_ENV_VARIABLE2: 'platformatic_variable2'
349
+ },
350
+ secrets: {
351
+ PLT_SECRET_1: 'platformatic_secret_1',
352
+ PLT_SECRET_2: 'platformatic_secret_2'
353
+ }
354
+ }
355
+ )
356
+ reply.code(200).send({ entryPointUrl: machineHost })
357
+ }
358
+ })
359
+
360
+ await execa('node', [
361
+ cliPath, 'deploy',
362
+ '--keys', pathToKeys,
363
+ '--config', pathToConfig,
364
+ '--label', label,
365
+ '--deploy-service-host', deployServiceHost
366
+ ])
367
+ })
368
+
369
+ test('should throw if workspace env file is wrong', async (t) => {
370
+ const pathToConfig = join(import.meta.url, './fixtures/app-to-deploy/platformatic.db.json')
371
+ const pathToKeys = join(import.meta.url, './fixtures/app-to-deploy/wrong.txt')
372
+
373
+ try {
374
+ await execa('node', [
375
+ cliPath, 'deploy',
376
+ '--keys', pathToKeys,
377
+ '--config', pathToConfig
378
+ ])
379
+ t.fail('should have failed')
380
+ } catch (err) {
381
+ t.ok(err.message.includes('Could not find workspace keys in provided file.'))
382
+ }
383
+ })
@@ -0,0 +1,2 @@
1
+ PLATFORMATIC_DYNAMIC_WORKSPACE_ID=b3d7f7e0-8c03-11e8-9eb6-529269fb1459
2
+ PLATFORMATIC_DYNAMIC_WORKSPACE_API_KEY=b3d7f7e08c0311e89eb6529269fb1459
@@ -0,0 +1,2 @@
1
+ PLATFORMATIC_STATIC_WORKSPACE_ID=b3d7f7e0-8c03-11e8-9eb6-529269fb1459
2
+ PLATFORMATIC_STATIC_WORKSPACE_API_KEY=b3d7f7e08c0311e89eb6529269fb1459
@@ -0,0 +1,2 @@
1
+ WRONG_DYNAMIC_WORKSPACE_ID=b3d7f7e0-8c03-11e8-9eb6-529269fb1459
2
+ WRONG_DYNAMIC_WORKSPACE_API_KEY=b3d7f7e08c0311e89eb6529269fb1459
@@ -0,0 +1,11 @@
1
+ {
2
+ "$schema": "https://platformatic.dev/schemas/v0.23.0/runtime",
3
+ "entrypoint": "serviceApp",
4
+ "services": [
5
+ {
6
+ "id": "serviceApp",
7
+ "path": "../",
8
+ "config": "platformatic.service.json"
9
+ }
10
+ ]
11
+ }
package/test/gh.test.js CHANGED
@@ -8,23 +8,23 @@ import { dirname, join } from 'path'
8
8
  import mkdirp from 'mkdirp'
9
9
 
10
10
  let count = 0
11
- const workspaceId = 'WORKSPACE-ID-TEST'
12
11
 
13
12
  test('creates a deploy config for static workspace', async (t) => {
14
13
  const dest = join(tmpdir(), `test-cli-gh-${process.pid}-${count++}`)
15
14
 
15
+ t.comment(`working in ${dest}`)
16
16
  await mkdirp(dest)
17
17
  await cp(
18
18
  join(dirname(fileURLToPath(import.meta.url)), 'fixtures', 'v0.16.0.db.json'),
19
19
  join(dest, 'platformatic.db.json'))
20
20
 
21
- await execa('node', [cliPath, 'gh', '-w', workspaceId], {
21
+ await execa('node', [cliPath, 'gh'], {
22
22
  cwd: dest
23
23
  })
24
24
 
25
25
  const deployWorkflow = await readFile(join(dest, '.github', 'workflows', 'platformatic-static-workspace-deploy.yml'), 'utf8')
26
+ t.ok(deployWorkflow.indexOf('PLATFORMATIC_STATIC_WORKSPACE_ID') !== -1)
26
27
  t.ok(deployWorkflow.indexOf('PLATFORMATIC_STATIC_WORKSPACE_API_KEY') !== -1)
27
- t.ok(deployWorkflow.indexOf('WORKSPACE-ID-TEST') !== -1)
28
28
  })
29
29
 
30
30
  test('creates a deploy config for dynamic workspace', async (t) => {
@@ -35,31 +35,13 @@ test('creates a deploy config for dynamic workspace', async (t) => {
35
35
  join(dirname(fileURLToPath(import.meta.url)), 'fixtures', 'v0.16.0.db.json'),
36
36
  join(dest, 'platformatic.db.json'))
37
37
 
38
- await execa('node', [cliPath, 'gh', '-w', workspaceId, '-t', 'dynamic'], {
38
+ await execa('node', [cliPath, 'gh', '-t', 'dynamic'], {
39
39
  cwd: dest
40
40
  })
41
41
 
42
42
  const deployWorkflow = await readFile(join(dest, '.github', 'workflows', 'platformatic-dynamic-workspace-deploy.yml'), 'utf8')
43
+ t.ok(deployWorkflow.indexOf('PLATFORMATIC_DYNAMIC_WORKSPACE_ID') !== -1)
43
44
  t.ok(deployWorkflow.indexOf('PLATFORMATIC_DYNAMIC_WORKSPACE_API_KEY') !== -1)
44
- t.ok(deployWorkflow.indexOf('WORKSPACE-ID-TEST') !== -1)
45
- })
46
-
47
- test('creation fails if workspace is missing', async (t) => {
48
- const dest = join(tmpdir(), `test-cli-gh-${process.pid}-${count++}`)
49
-
50
- await mkdirp(dest)
51
- await cp(
52
- join(dirname(fileURLToPath(import.meta.url)), 'fixtures', 'v0.16.0.db.json'),
53
- join(dest, 'platformatic.db.json'))
54
-
55
- try {
56
- await execa('node', [cliPath, 'gh'], {
57
- cwd: dest
58
- })
59
- t.fail('should have failed')
60
- } catch ({ stdout }) {
61
- t.ok(stdout.indexOf('Workspace ID is required') !== -1)
62
- }
63
45
  })
64
46
 
65
47
  test('creation fails if workspace type is not static or dynamic', async (t) => {
@@ -71,7 +53,7 @@ test('creation fails if workspace type is not static or dynamic', async (t) => {
71
53
  join(dest, 'platformatic.db.json'))
72
54
 
73
55
  try {
74
- await execa('node', [cliPath, 'gh', '-w', workspaceId, '-t', 'XXXXX'], {
56
+ await execa('node', [cliPath, 'gh', '-t', 'XXXXX'], {
75
57
  cwd: dest
76
58
  })
77
59
  t.fail('should have failed')
@@ -84,7 +66,7 @@ test('creation fails if no config file is found', async (t) => {
84
66
  const dest = join(tmpdir(), `test-cli-gh-${process.pid}-${count++}`)
85
67
  await mkdirp(dest)
86
68
  try {
87
- await execa('node', [cliPath, 'gh', '-w', workspaceId], {
69
+ await execa('node', [cliPath, 'gh'], {
88
70
  cwd: dest
89
71
  })
90
72
  t.fail('should have failed')
@@ -103,7 +85,7 @@ test('creates a deploy must warn that a .env exists', async (t) => {
103
85
 
104
86
  await writeFile(join(dest, '.env'), 'TEST=1')
105
87
 
106
- const { stdout } = await execa('node', [cliPath, 'gh', '-w', workspaceId], {
88
+ const { stdout } = await execa('node', [cliPath, 'gh'], {
107
89
  cwd: dest
108
90
  })
109
91
  t.ok(stdout.indexOf('Found .env file') !== -1)
@@ -22,6 +22,9 @@ const help = await readFile(join(import.meta.url, '..', 'help', 'help.txt'), 'ut
22
22
  // This reads a file from packages/db
23
23
  const helpDB = await readFile(join(import.meta.url, '..', '..', 'db', 'help', 'help.txt'), 'utf8')
24
24
 
25
+ // This reads a file from packages/runtime
26
+ const helpRuntime = await readFile(join(import.meta.url, '..', '..', 'runtime', 'help', 'help.txt'), 'utf8')
27
+
25
28
  // This reads a file from packages/service
26
29
  const helpService = await readFile(join(import.meta.url, '..', '..', 'service', 'help', 'help.txt'), 'utf8')
27
30
 
@@ -39,6 +42,15 @@ test('db', async (t) => {
39
42
  }
40
43
  })
41
44
 
45
+ test('runtime', async (t) => {
46
+ try {
47
+ await execa('node', [cliPath, 'runtime', 'start'])
48
+ t.fail('bug')
49
+ } catch (err) {
50
+ t.ok(err.stderr.includes('Missing config file'))
51
+ }
52
+ })
53
+
42
54
  test('login', async (t) => {
43
55
  try {
44
56
  await execa('node', [cliPath, 'login'])
@@ -105,6 +117,11 @@ test('prints the help if not commands are specified', async (t) => {
105
117
  t.equal(stdout + EOL, help)
106
118
  })
107
119
 
120
+ test('prints the help of runtime', async (t) => {
121
+ const { stdout } = await execa('node', [cliPath, 'help', 'runtime'])
122
+ t.equal(stdout + EOL, helpRuntime)
123
+ })
124
+
108
125
  test('prints the help of service', async (t) => {
109
126
  const { stdout } = await execa('node', [cliPath, 'help', 'service'])
110
127
  t.equal(stdout + EOL, helpService)
@@ -1,3 +1,4 @@
1
+ import assert from 'node:assert'
1
2
  import { spawn } from 'node:child_process'
2
3
  import { cp } from 'node:fs/promises'
3
4
  import { tmpdir } from 'node:os'
@@ -38,3 +39,44 @@ test('starts a server', async ({ teardown }) => {
38
39
  }
39
40
  }
40
41
  })
42
+
43
+ test('starts a runtime application', async ({ teardown }) => {
44
+ const srcDir = join(dirname(fileURLToPath(import.meta.url)), 'fixtures')
45
+ const destDir = join(tmpdir(), `test-cli-${process.pid}-${count++}`)
46
+ let found = false
47
+
48
+ await cp(
49
+ join(srcDir, 'platformatic.runtime.json'),
50
+ join(destDir, 'platformatic.runtime.json')
51
+ )
52
+ await cp(
53
+ join(srcDir, 'platformatic.service.json'),
54
+ join(destDir, 'platformatic.service.json')
55
+ )
56
+
57
+ const child = spawn(process.execPath, [cliPath, 'start'], {
58
+ cwd: destDir,
59
+ timeout: 10_000
60
+ })
61
+
62
+ teardown(async () => {
63
+ try {
64
+ child.kill('SIGKILL')
65
+ } catch {} // Ignore error.
66
+ })
67
+
68
+ let stdout = ''
69
+
70
+ child.stdout.setEncoding('utf8')
71
+
72
+ for await (const chunk of child.stdout) {
73
+ stdout += chunk
74
+
75
+ if (/server listening at/i.test(stdout)) {
76
+ found = true
77
+ break
78
+ }
79
+ }
80
+
81
+ assert(found)
82
+ })