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 +5 -0
- package/help/deploy.txt +3 -1
- package/help/help.txt +1 -0
- package/lib/deploy.js +97 -45
- package/lib/gh.js +7 -13
- package/package.json +17 -14
- package/test/deploy.test.js +183 -0
- package/test/fixtures/app-to-deploy/dynamic.txt +2 -0
- package/test/fixtures/app-to-deploy/static.txt +2 -0
- package/test/fixtures/app-to-deploy/wrong.txt +2 -0
- package/test/fixtures/platformatic.runtime.json +11 -0
- package/test/gh.test.js +8 -26
- package/test/platformatic.test.js +17 -0
- package/test/start.test.js +42 -0
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
|
|
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,
|
|
12
|
+
export const createGHAction = async (logger, env, config, buildTS, type, projectDir = process.cwd()) => {
|
|
13
13
|
if (type === 'static') {
|
|
14
|
-
await createStaticWorkspaceGHAction(logger,
|
|
14
|
+
await createStaticWorkspaceGHAction(logger, env, config, projectDir, buildTS)
|
|
15
15
|
return
|
|
16
16
|
}
|
|
17
|
-
await createDynamicWorkspaceGHAction(logger,
|
|
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,
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
47
|
+
"inquirer": "^9.2.6",
|
|
47
48
|
"minimist": "^1.2.8",
|
|
48
|
-
"pino": "^8.
|
|
49
|
+
"pino": "^8.14.1",
|
|
49
50
|
"pino-pretty": "^10.0.0",
|
|
50
|
-
"@platformatic/authenticate": "0.
|
|
51
|
-
"@platformatic/client-cli": "0.
|
|
52
|
-
"@platformatic/config": "0.
|
|
53
|
-
"@platformatic/
|
|
54
|
-
"@platformatic/
|
|
55
|
-
"@platformatic/
|
|
56
|
-
"@platformatic/
|
|
57
|
-
"@platformatic/
|
|
58
|
-
"
|
|
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
|
}
|
package/test/deploy.test.js
CHANGED
|
@@ -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
|
+
})
|
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'
|
|
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', '-
|
|
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', '-
|
|
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'
|
|
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'
|
|
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)
|
package/test/start.test.js
CHANGED
|
@@ -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
|
+
})
|