platformatic 1.6.0 → 1.7.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/help/deploy.txt +41 -0
- package/help/help.txt +1 -0
- package/help/login.txt +10 -0
- package/lib/deploy.js +208 -19
- package/lib/errors.js +3 -1
- package/package.json +13 -13
package/help/deploy.txt
CHANGED
|
@@ -21,3 +21,44 @@ Options:
|
|
|
21
21
|
> :information_source:
|
|
22
22
|
>
|
|
23
23
|
> When deploying an application to a ***dynamic workspace***, specify the deploy `--label` option. You can find it on your cloud dashboard or you can specify a new one.
|
|
24
|
+
>
|
|
25
|
+
> If you do not specify an environment file to use with the `-e` flag, **ensure that a default environment file named `.env` exists**.
|
|
26
|
+
|
|
27
|
+
Deploy a **static** Platformatic Cloud application.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
platformatic deploy \
|
|
31
|
+
-t static \
|
|
32
|
+
-c platformatic.db.json \
|
|
33
|
+
-e .env.prototype \
|
|
34
|
+
--workspace-id=00000000-0000-0000-0000-000000000000 \
|
|
35
|
+
--workspace-key=11111111111111111111111111111111
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Deploy a **static** Platformatic Cloud application with a workspace keys file. The keys file can be downloaded from the Platformatic Console when generating a new API key.
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
platformatic deploy \
|
|
42
|
+
-t static \
|
|
43
|
+
-c platformatic.db.json \
|
|
44
|
+
-k foo.plt.txt
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The `foo.plt.txt` must contain two variables for the workspace id and workspace API key.
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
# Contents of foo.plt.txt
|
|
51
|
+
PLATFORMATIC_STATIC_WORKSPACE_ID=00000000-0000-0000-0000-000000000000
|
|
52
|
+
PLATFORMATIC_STATIC_WORKSPACE_API_KEY=11111111111111111111111111111111
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Deploy a **dynamic** Platformatic Cloud application.
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
platformatic deploy \
|
|
59
|
+
-t dynamic \
|
|
60
|
+
-c platformatic.db.json \
|
|
61
|
+
-l dev \
|
|
62
|
+
--workspace-id=00000000-0000-0000-0000-000000000000 \
|
|
63
|
+
--workspace-key=11111111111111111111111111111111
|
|
64
|
+
```
|
package/help/help.txt
CHANGED
|
@@ -9,3 +9,4 @@ Welcome to Platformatic. Available commands are:
|
|
|
9
9
|
* `deploy` - deploy a Platformatic application to the cloud.
|
|
10
10
|
* `runtime` - start Platformatic Runtime; type `platformatic runtime help` to know more.
|
|
11
11
|
* `start` - start a Platformatic application.
|
|
12
|
+
* `login` - generate a Platformatic login api key.
|
package/help/login.txt
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Generate a Platformatic login api key.
|
|
2
|
+
|
|
3
|
+
``` bash
|
|
4
|
+
$ platformatic deploy
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
Options:
|
|
8
|
+
|
|
9
|
+
* `-c, --config FILE` - Specify a path to a global platformatic config file. Defaults to `~/.platformatic/config.json`.
|
|
10
|
+
* `--browser` - Automatically open default browser. If process stdout is a TTY, the default is `true`. Otherwise, the default is `false`.
|
package/lib/deploy.js
CHANGED
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
import { isAbsolute, dirname, relative, join } from 'path'
|
|
4
4
|
import { readFile } from 'fs/promises'
|
|
5
5
|
|
|
6
|
+
import { request } from 'undici'
|
|
6
7
|
import pino from 'pino'
|
|
7
8
|
import pretty from 'pino-pretty'
|
|
8
9
|
import dotenv from 'dotenv'
|
|
9
10
|
import inquirer from 'inquirer'
|
|
10
11
|
import parseArgs from 'minimist'
|
|
11
12
|
import deployClient from '@platformatic/deploy-client'
|
|
13
|
+
import { getUserApiKey } from '@platformatic/authenticate'
|
|
12
14
|
import errors from './errors.js'
|
|
13
15
|
|
|
14
16
|
export const DEPLOY_SERVICE_HOST = 'https://deploy.platformatic.cloud'
|
|
@@ -21,8 +23,12 @@ const logger = pino(pretty({
|
|
|
21
23
|
ignore: 'hostname,pid'
|
|
22
24
|
}))
|
|
23
25
|
|
|
24
|
-
async function
|
|
25
|
-
|
|
26
|
+
async function askMissingWorkspaceDetails (
|
|
27
|
+
workspaceType,
|
|
28
|
+
workspaceId,
|
|
29
|
+
workspaceKey,
|
|
30
|
+
userApiKey
|
|
31
|
+
) {
|
|
26
32
|
/* c8 ignore next 9 */
|
|
27
33
|
if (!workspaceType) {
|
|
28
34
|
const answer = await inquirer.prompt({
|
|
@@ -38,7 +44,6 @@ async function askWorkspaceDetails (args) {
|
|
|
38
44
|
throw new errors.InvalidWorkspaceTypeError(workspaceType, WORKSPACE_TYPES.join(', '))
|
|
39
45
|
}
|
|
40
46
|
|
|
41
|
-
let workspaceId = args['workspace-id']
|
|
42
47
|
/* c8 ignore next 8 */
|
|
43
48
|
if (!workspaceId) {
|
|
44
49
|
const answer = await inquirer.prompt({
|
|
@@ -53,9 +58,8 @@ async function askWorkspaceDetails (args) {
|
|
|
53
58
|
throw new errors.InvalidWorkspaceIdError()
|
|
54
59
|
}
|
|
55
60
|
|
|
56
|
-
let workspaceKey = args['workspace-key']
|
|
57
61
|
/* c8 ignore next 9 */
|
|
58
|
-
if (!workspaceKey) {
|
|
62
|
+
if (!workspaceKey && !userApiKey) {
|
|
59
63
|
const answer = await inquirer.prompt({
|
|
60
64
|
type: 'password',
|
|
61
65
|
name: 'workspaceKey',
|
|
@@ -72,6 +76,93 @@ async function askWorkspaceDetails (args) {
|
|
|
72
76
|
}
|
|
73
77
|
}
|
|
74
78
|
|
|
79
|
+
/* c8 ignore next 26 */
|
|
80
|
+
async function askToChooseApplication (applications) {
|
|
81
|
+
const applicationChoices = applications.map((application) => {
|
|
82
|
+
return {
|
|
83
|
+
name: application.name,
|
|
84
|
+
value: application
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
applicationChoices.push({
|
|
88
|
+
name: 'Deploy to another application',
|
|
89
|
+
value: null
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
const answer = await inquirer.prompt({
|
|
93
|
+
type: 'list',
|
|
94
|
+
name: 'application',
|
|
95
|
+
message: 'Select application to deploy:',
|
|
96
|
+
choices: applicationChoices
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
const chosenApplication = answer.application
|
|
100
|
+
if (chosenApplication === null) {
|
|
101
|
+
return null
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return chosenApplication
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* c8 ignore next 27 */
|
|
108
|
+
async function askToChooseWorkspace (workspaces) {
|
|
109
|
+
const workspaceChoices = workspaces.map((workspace) => {
|
|
110
|
+
return {
|
|
111
|
+
name: `${workspace.name} (${workspace.type})`,
|
|
112
|
+
value: workspace
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
workspaceChoices.push({
|
|
116
|
+
name: 'Deploy to another workspace',
|
|
117
|
+
value: null
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
const answer = await inquirer.prompt({
|
|
121
|
+
type: 'list',
|
|
122
|
+
name: 'workspace',
|
|
123
|
+
message: 'Select workspace to deploy:',
|
|
124
|
+
choices: workspaceChoices
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
const chosenWorkspace = answer.workspace
|
|
128
|
+
if (chosenWorkspace === null) {
|
|
129
|
+
return null
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return chosenWorkspace
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* c8 ignore next 19 */
|
|
136
|
+
async function askToChooseDeployLabel (labels) {
|
|
137
|
+
const entryPointChoices = labels.map((label) => {
|
|
138
|
+
return { name: label, value: label }
|
|
139
|
+
})
|
|
140
|
+
entryPointChoices.push({
|
|
141
|
+
name: 'Deploy to another label',
|
|
142
|
+
value: null
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
const answer = await inquirer.prompt({
|
|
146
|
+
type: 'list',
|
|
147
|
+
name: 'entryPoint',
|
|
148
|
+
message: 'Select entry point to deploy:',
|
|
149
|
+
choices: entryPointChoices
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
return answer.entryPoint
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* c8 ignore next 10 */
|
|
156
|
+
async function askToEnterDeployLabel () {
|
|
157
|
+
const answer = await inquirer.prompt({
|
|
158
|
+
type: 'input',
|
|
159
|
+
name: 'label',
|
|
160
|
+
message: 'Enter deploy label:',
|
|
161
|
+
default: 'cli:deploy-1'
|
|
162
|
+
})
|
|
163
|
+
return answer.label
|
|
164
|
+
}
|
|
165
|
+
|
|
75
166
|
async function readWorkspaceDetails (workspaceKeysPath) {
|
|
76
167
|
/* c8 ignore next 3 */
|
|
77
168
|
if (!isAbsolute(workspaceKeysPath)) {
|
|
@@ -106,6 +197,65 @@ async function readWorkspaceDetails (workspaceKeysPath) {
|
|
|
106
197
|
throw new errors.CouldNotFindWorkspaceKeysError()
|
|
107
198
|
}
|
|
108
199
|
|
|
200
|
+
/* c8 ignore next 18 */
|
|
201
|
+
async function getUserApplications (deployServiceHost, userApiKey) {
|
|
202
|
+
const { statusCode, body } = await request(`${deployServiceHost}/applications`, {
|
|
203
|
+
headers: {
|
|
204
|
+
'Content-Type': 'application/json',
|
|
205
|
+
'x-platformatic-user-api-key': userApiKey
|
|
206
|
+
}
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
if (statusCode !== 200) {
|
|
210
|
+
const error = await body.text()
|
|
211
|
+
console.error(error)
|
|
212
|
+
throw new errors.CouldNotFetchUserApplicationsError()
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const { applications } = await body.json()
|
|
216
|
+
return applications
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/* c8 ignore next 18 */
|
|
220
|
+
async function getWorkspaceLabels (deployServiceHost, workspaceId, userApiKey) {
|
|
221
|
+
const { statusCode, body } = await request(`${deployServiceHost}/entrypoints`, {
|
|
222
|
+
headers: {
|
|
223
|
+
'Content-Type': 'application/json',
|
|
224
|
+
'x-platformatic-workspace-id': workspaceId,
|
|
225
|
+
'x-platformatic-user-api-key': userApiKey
|
|
226
|
+
}
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
if (statusCode !== 200) {
|
|
230
|
+
const error = await body.text()
|
|
231
|
+
console.error(error)
|
|
232
|
+
throw new errors.CouldNotFetchDeployLabelsError()
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const { entryPoints } = await body.json()
|
|
236
|
+
return entryPoints.map((entryPoint) => entryPoint.label)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/* c8 ignore next 19 */
|
|
240
|
+
async function getUserWorkspaceDetails (deployServiceHost, userApiKey) {
|
|
241
|
+
const applications = await getUserApplications(deployServiceHost, userApiKey)
|
|
242
|
+
if (applications.length === 0) return null
|
|
243
|
+
|
|
244
|
+
const application = await askToChooseApplication(applications)
|
|
245
|
+
if (application === null) return null
|
|
246
|
+
|
|
247
|
+
const workspaces = application.workspaces
|
|
248
|
+
if (workspaces.length === 0) return null
|
|
249
|
+
|
|
250
|
+
const workspaceDetails = await askToChooseWorkspace(workspaces)
|
|
251
|
+
if (workspaceDetails === null) return null
|
|
252
|
+
|
|
253
|
+
return {
|
|
254
|
+
workspaceType: workspaceDetails.type,
|
|
255
|
+
workspaceId: workspaceDetails.id
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
109
259
|
export async function deploy (argv) {
|
|
110
260
|
try {
|
|
111
261
|
const args = parseArgs(argv, {
|
|
@@ -134,24 +284,63 @@ export async function deploy (argv) {
|
|
|
134
284
|
}
|
|
135
285
|
})
|
|
136
286
|
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
287
|
+
const deployServiceHost = args['deploy-service-host']
|
|
288
|
+
|
|
289
|
+
let workspaceId = args['workspace-id']
|
|
290
|
+
let workspaceType = args.type
|
|
141
291
|
|
|
142
|
-
|
|
292
|
+
let workspaceKey = args['workspace-key']
|
|
293
|
+
let userApiKey = null
|
|
294
|
+
|
|
295
|
+
if (!workspaceId) {
|
|
296
|
+
if (args.keys) {
|
|
297
|
+
const workspaceDetails = await readWorkspaceDetails(args.keys)
|
|
298
|
+
workspaceId = workspaceDetails.workspaceId
|
|
299
|
+
workspaceType = workspaceDetails.workspaceType
|
|
300
|
+
workspaceKey = workspaceDetails.workspaceKey
|
|
301
|
+
/* c8 ignore next 10 */
|
|
302
|
+
} else {
|
|
303
|
+
userApiKey = await getUserApiKey()
|
|
304
|
+
if (userApiKey) {
|
|
305
|
+
const workspaceDetails = await getUserWorkspaceDetails(deployServiceHost, userApiKey)
|
|
306
|
+
if (workspaceDetails) {
|
|
307
|
+
workspaceId = workspaceDetails.workspaceId
|
|
308
|
+
workspaceType = workspaceDetails.workspaceType
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const workspaceDetails = await askMissingWorkspaceDetails(
|
|
315
|
+
workspaceType,
|
|
316
|
+
workspaceId,
|
|
317
|
+
workspaceKey,
|
|
318
|
+
userApiKey
|
|
319
|
+
)
|
|
320
|
+
workspaceId = workspaceDetails.workspaceId
|
|
321
|
+
workspaceType = workspaceDetails.workspaceType
|
|
322
|
+
workspaceKey = workspaceDetails.workspaceKey
|
|
143
323
|
|
|
144
324
|
let label = args.label
|
|
325
|
+
|
|
145
326
|
if (workspaceType === 'dynamic') {
|
|
146
|
-
|
|
327
|
+
/* c8 ignore next 17 */
|
|
147
328
|
if (!label) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
329
|
+
userApiKey = userApiKey || await getUserApiKey()
|
|
330
|
+
|
|
331
|
+
if (userApiKey) {
|
|
332
|
+
const workspaceLabels = await getWorkspaceLabels(
|
|
333
|
+
deployServiceHost,
|
|
334
|
+
workspaceId,
|
|
335
|
+
userApiKey
|
|
336
|
+
)
|
|
337
|
+
if (workspaceLabels.length !== 0) {
|
|
338
|
+
label = await askToChooseDeployLabel(workspaceLabels)
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
if (!label) {
|
|
342
|
+
label = await askToEnterDeployLabel()
|
|
343
|
+
}
|
|
155
344
|
}
|
|
156
345
|
|
|
157
346
|
const labelPrefix = label.split(':')[0]
|
|
@@ -171,12 +360,12 @@ export async function deploy (argv) {
|
|
|
171
360
|
|
|
172
361
|
const pathToEnvFile = args.env || '.env'
|
|
173
362
|
const pathToSecretsFile = args.secrets || '.secrets.env'
|
|
174
|
-
const deployServiceHost = args['deploy-service-host']
|
|
175
363
|
|
|
176
364
|
await deployClient.deploy({
|
|
177
365
|
deployServiceHost,
|
|
178
366
|
workspaceId,
|
|
179
367
|
workspaceKey,
|
|
368
|
+
userApiKey,
|
|
180
369
|
pathToProject,
|
|
181
370
|
pathToConfig,
|
|
182
371
|
pathToEnvFile,
|
package/lib/errors.js
CHANGED
|
@@ -7,7 +7,9 @@ const ERROR_PREFIX = 'PLT_CLI'
|
|
|
7
7
|
const errors = {
|
|
8
8
|
InvalidWorkspaceTypeError: createError(`${ERROR_PREFIX}_INVALID_WORKSPACE_TYPE`, 'Invalid workspace type provided: "%s". Type must be one of: %s'),
|
|
9
9
|
InvalidWorkspaceIdError: createError(`${ERROR_PREFIX}_INVALID_WORKSPACE_ID`, 'Invalid workspace id provided. Workspace id must be a valid uuid.'),
|
|
10
|
-
CouldNotFindWorkspaceKeysError: createError(`${ERROR_PREFIX}_COULD_NOT_FIND_WORKSPACE_KEYS`, 'Could not find workspace keys in provided file.')
|
|
10
|
+
CouldNotFindWorkspaceKeysError: createError(`${ERROR_PREFIX}_COULD_NOT_FIND_WORKSPACE_KEYS`, 'Could not find workspace keys in provided file.'),
|
|
11
|
+
CouldNotFetchUserApplicationsError: createError(`${ERROR_PREFIX}_COULD_NOT_FETCH_USER_APPLICATIONS`, 'Could not fetch user applications'),
|
|
12
|
+
CouldNotFetchDeployLabelsError: createError(`${ERROR_PREFIX}_COULD_NOT_FETCH_DEPLOY_LABELS`, 'Could not fetch deploy labels')
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
export default errors
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "platformatic",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Platformatic CLI",
|
|
5
5
|
"main": "cli.js",
|
|
6
6
|
"type": "module",
|
|
@@ -49,18 +49,18 @@
|
|
|
49
49
|
"pino": "^8.15.3",
|
|
50
50
|
"pino-pretty": "^10.2.0",
|
|
51
51
|
"undici": "^5.25.4",
|
|
52
|
-
"@platformatic/authenticate": "1.
|
|
53
|
-
"@platformatic/client-cli": "1.
|
|
54
|
-
"@platformatic/composer": "1.
|
|
55
|
-
"@platformatic/config": "1.
|
|
56
|
-
"@platformatic/db": "1.
|
|
57
|
-
"@platformatic/deploy-client": "1.
|
|
58
|
-
"@platformatic/frontend-template": "1.
|
|
59
|
-
"@platformatic/metaconfig": "1.
|
|
60
|
-
"@platformatic/runtime": "1.
|
|
61
|
-
"@platformatic/service": "1.
|
|
62
|
-
"@platformatic/utils": "^1.
|
|
63
|
-
"create-platformatic": "1.
|
|
52
|
+
"@platformatic/authenticate": "1.7.0",
|
|
53
|
+
"@platformatic/client-cli": "1.7.0",
|
|
54
|
+
"@platformatic/composer": "1.7.0",
|
|
55
|
+
"@platformatic/config": "1.7.0",
|
|
56
|
+
"@platformatic/db": "1.7.0",
|
|
57
|
+
"@platformatic/deploy-client": "1.7.0",
|
|
58
|
+
"@platformatic/frontend-template": "1.7.0",
|
|
59
|
+
"@platformatic/metaconfig": "1.7.0",
|
|
60
|
+
"@platformatic/runtime": "1.7.0",
|
|
61
|
+
"@platformatic/service": "1.7.0",
|
|
62
|
+
"@platformatic/utils": "^1.7.0",
|
|
63
|
+
"create-platformatic": "1.7.0"
|
|
64
64
|
},
|
|
65
65
|
"scripts": {
|
|
66
66
|
"test": "standard | snazzy && c8 node ./test/runner.js",
|