create-platformatic 2.0.0-alpha.2 → 2.0.0-alpha.4
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/create-platformatic.mjs +2 -2
- package/eslint.config.js +3 -0
- package/package.json +15 -15
- package/src/index.mjs +52 -44
- package/src/utils.mjs +14 -22
- package/test/cli/composer.test.mjs +45 -41
- package/test/cli/db.test.mjs +52 -46
- package/test/cli/helper.mjs +5 -5
- package/test/cli/runtime.test.mjs +60 -52
- package/test/cli/service.test.mjs +126 -104
- package/test/cli/stackable.test.mjs +53 -40
- package/test/unit/create-git-repository.test.mjs +17 -11
- package/test/unit/fetch-stackables.mjs +4 -4
- package/test/unit/utils.test.mjs +46 -44
package/create-platformatic.mjs
CHANGED
package/eslint.config.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-platformatic",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.4",
|
|
4
4
|
"description": "Create platformatic application interactive tool",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -35,31 +35,31 @@
|
|
|
35
35
|
"strip-ansi": "^7.1.0",
|
|
36
36
|
"undici": "^6.9.0",
|
|
37
37
|
"which": "^3.0.1",
|
|
38
|
-
"@platformatic/
|
|
39
|
-
"@platformatic/
|
|
40
|
-
"@platformatic/
|
|
38
|
+
"@platformatic/generators": "2.0.0-alpha.4",
|
|
39
|
+
"@platformatic/config": "2.0.0-alpha.4",
|
|
40
|
+
"@platformatic/utils": "2.0.0-alpha.4"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"ajv": "^8.12.0",
|
|
44
|
-
"borp": "^0.
|
|
44
|
+
"borp": "^0.17.0",
|
|
45
45
|
"c8": "^10.0.0",
|
|
46
46
|
"cross-env": "^7.0.3",
|
|
47
47
|
"dotenv": "^16.4.5",
|
|
48
|
+
"eslint": "9",
|
|
48
49
|
"esmock": "^2.6.4",
|
|
49
50
|
"fastify": "^4.26.2",
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"typescript": "~5.5.0",
|
|
51
|
+
"neostandard": "^0.11.1",
|
|
52
|
+
"typescript": "~5.5.4",
|
|
53
53
|
"yaml": "^2.4.1",
|
|
54
|
-
"@platformatic/composer": "2.0.0-alpha.
|
|
55
|
-
"@platformatic/db": "2.0.0-alpha.
|
|
56
|
-
"@platformatic/runtime": "2.0.0-alpha.
|
|
57
|
-
"@platformatic/service": "2.0.0-alpha.
|
|
54
|
+
"@platformatic/composer": "2.0.0-alpha.4",
|
|
55
|
+
"@platformatic/db": "2.0.0-alpha.4",
|
|
56
|
+
"@platformatic/runtime": "2.0.0-alpha.4",
|
|
57
|
+
"@platformatic/service": "2.0.0-alpha.4"
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|
|
60
|
-
"test:cli": "borp --pattern \"test/cli/*test.mjs\" --timeout
|
|
61
|
-
"test:unit": "pnpm run lint && cross-env NODE_OPTIONS=\"--loader=esmock --no-warnings\" borp --pattern \"test/unit/*test.mjs\" --timeout
|
|
60
|
+
"test:cli": "borp --pattern \"test/cli/*test.mjs\" --timeout=180000 --concurrency=1",
|
|
61
|
+
"test:unit": "pnpm run lint && cross-env NODE_OPTIONS=\"--loader=esmock --no-warnings\" borp --pattern \"test/unit/*test.mjs\" --timeout=180000 --concurrency=1",
|
|
62
62
|
"test": "npm run test:unit && npm run test:cli",
|
|
63
|
-
"lint": "
|
|
63
|
+
"lint": "eslint"
|
|
64
64
|
}
|
|
65
65
|
}
|
package/src/index.mjs
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { say } from './say.mjs'
|
|
2
|
-
import path, { basename, join } from 'node:path'
|
|
3
|
-
import inquirer from 'inquirer'
|
|
4
|
-
import generateName from 'boring-name-generator'
|
|
5
|
-
import { getUsername, getVersion, minimumSupportedNodeVersions, isCurrentVersionSupported, safeMkdir } from './utils.mjs'
|
|
6
|
-
import { createGitRepository } from './create-git-repository.mjs'
|
|
7
|
-
import { getPkgManager } from '@platformatic/utils'
|
|
8
1
|
import { StackableGenerator } from '@platformatic/generators'
|
|
9
|
-
import
|
|
10
|
-
import
|
|
2
|
+
import { createDirectory, getPkgManager } from '@platformatic/utils'
|
|
3
|
+
import generateName from 'boring-name-generator'
|
|
11
4
|
import { execa } from 'execa'
|
|
5
|
+
import inquirer from 'inquirer'
|
|
12
6
|
import parseArgs from 'minimist'
|
|
13
|
-
import ora from 'ora'
|
|
14
|
-
import { pathToFileURL } from 'node:url'
|
|
15
7
|
import { writeFile } from 'node:fs/promises'
|
|
16
|
-
import {
|
|
8
|
+
import path, { basename, join } from 'node:path'
|
|
17
9
|
import { setTimeout } from 'node:timers/promises'
|
|
10
|
+
import { pathToFileURL } from 'node:url'
|
|
11
|
+
import ora from 'ora'
|
|
12
|
+
import pino from 'pino'
|
|
13
|
+
import pretty from 'pino-pretty'
|
|
18
14
|
import resolve from 'resolve'
|
|
15
|
+
import { request } from 'undici'
|
|
16
|
+
import { createGitRepository } from './create-git-repository.mjs'
|
|
17
|
+
import { say } from './say.mjs'
|
|
18
|
+
import { getUsername, getVersion, isCurrentVersionSupported, minimumSupportedNodeVersions } from './utils.mjs'
|
|
19
19
|
|
|
20
20
|
const MARKETPLACE_HOST = 'https://marketplace.platformatic.dev'
|
|
21
21
|
|
|
@@ -26,10 +26,7 @@ export async function fetchStackables (marketplaceHost) {
|
|
|
26
26
|
const stackablesRequestTimeout = setTimeout(5000, new Error('Request timed out'))
|
|
27
27
|
|
|
28
28
|
try {
|
|
29
|
-
const { statusCode, body } = await Promise.race([
|
|
30
|
-
stackablesRequest,
|
|
31
|
-
stackablesRequestTimeout
|
|
32
|
-
])
|
|
29
|
+
const { statusCode, body } = await Promise.race([stackablesRequest, stackablesRequestTimeout])
|
|
33
30
|
if (statusCode === 200) {
|
|
34
31
|
return (await body.json()).map(stackable => stackable.name)
|
|
35
32
|
}
|
|
@@ -44,7 +41,7 @@ export async function chooseStackable (stackables) {
|
|
|
44
41
|
name: 'type',
|
|
45
42
|
message: 'Which kind of project do you want to create?',
|
|
46
43
|
default: stackables.indexOf('@platformatic/service'),
|
|
47
|
-
choices: stackables
|
|
44
|
+
choices: stackables,
|
|
48
45
|
})
|
|
49
46
|
|
|
50
47
|
return options.type
|
|
@@ -57,7 +54,7 @@ async function importOrLocal ({ pkgManager, name, projectDir, pkg }) {
|
|
|
57
54
|
try {
|
|
58
55
|
const fileToImport = resolve.sync(pkg, { basedir: projectDir })
|
|
59
56
|
return await import(pathToFileURL(fileToImport))
|
|
60
|
-
} catch {
|
|
57
|
+
} catch {}
|
|
61
58
|
|
|
62
59
|
const spinner = ora(`Installing ${pkg}...`).start()
|
|
63
60
|
await execa(pkgManager, ['install', pkg], { cwd: projectDir })
|
|
@@ -68,13 +65,13 @@ async function importOrLocal ({ pkgManager, name, projectDir, pkg }) {
|
|
|
68
65
|
}
|
|
69
66
|
}
|
|
70
67
|
|
|
71
|
-
export const createPlatformatic = async
|
|
68
|
+
export const createPlatformatic = async argv => {
|
|
72
69
|
const args = parseArgs(argv, {
|
|
73
70
|
default: {
|
|
74
|
-
install: true
|
|
71
|
+
install: true,
|
|
75
72
|
},
|
|
76
73
|
boolean: ['install'],
|
|
77
|
-
string: ['global-config', 'marketplace-host']
|
|
74
|
+
string: ['global-config', 'marketplace-host'],
|
|
78
75
|
})
|
|
79
76
|
|
|
80
77
|
const username = await getUsername()
|
|
@@ -90,10 +87,12 @@ export const createPlatformatic = async (argv) => {
|
|
|
90
87
|
await say(`Please use one of the following Node.js versions >= ${supportedVersions}.`)
|
|
91
88
|
}
|
|
92
89
|
|
|
93
|
-
const logger = pino(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
90
|
+
const logger = pino(
|
|
91
|
+
pretty({
|
|
92
|
+
translateTime: 'SYS:HH:MM:ss',
|
|
93
|
+
ignore: 'hostname,pid',
|
|
94
|
+
})
|
|
95
|
+
)
|
|
97
96
|
|
|
98
97
|
const pkgManager = getPkgManager()
|
|
99
98
|
|
|
@@ -104,8 +103,8 @@ export const createPlatformatic = async (argv) => {
|
|
|
104
103
|
default: 'application',
|
|
105
104
|
choices: [
|
|
106
105
|
{ name: 'Application', value: 'application' },
|
|
107
|
-
{ name: 'Stackable', value: 'stackable' }
|
|
108
|
-
]
|
|
106
|
+
{ name: 'Stackable', value: 'stackable' },
|
|
107
|
+
],
|
|
109
108
|
})
|
|
110
109
|
|
|
111
110
|
if (projectType === 'application') {
|
|
@@ -120,29 +119,29 @@ async function createApplication (args, logger, pkgManager) {
|
|
|
120
119
|
type: 'input',
|
|
121
120
|
name: 'dir',
|
|
122
121
|
message: 'Where would you like to create your project?',
|
|
123
|
-
default: 'platformatic'
|
|
122
|
+
default: 'platformatic',
|
|
124
123
|
})
|
|
125
124
|
|
|
126
125
|
const projectDir = path.resolve(process.cwd(), optionsDir.dir)
|
|
127
126
|
const projectName = basename(projectDir)
|
|
128
127
|
|
|
129
|
-
await
|
|
128
|
+
await createDirectory(projectDir)
|
|
130
129
|
|
|
131
130
|
const runtime = await importOrLocal({
|
|
132
131
|
pkgManager,
|
|
133
132
|
name: projectName,
|
|
134
133
|
projectDir,
|
|
135
|
-
pkg: '@platformatic/runtime'
|
|
134
|
+
pkg: '@platformatic/runtime',
|
|
136
135
|
})
|
|
137
136
|
|
|
138
137
|
const generator = new runtime.Generator({
|
|
139
138
|
logger,
|
|
140
139
|
name: projectName,
|
|
141
|
-
inquirer
|
|
140
|
+
inquirer,
|
|
142
141
|
})
|
|
143
142
|
generator.setConfig({
|
|
144
143
|
...generator.config,
|
|
145
|
-
targetDirectory: projectDir
|
|
144
|
+
targetDirectory: projectDir,
|
|
146
145
|
})
|
|
147
146
|
|
|
148
147
|
await generator.populateFromExistingConfig()
|
|
@@ -162,7 +161,7 @@ async function createApplication (args, logger, pkgManager) {
|
|
|
162
161
|
pkgManager,
|
|
163
162
|
name: projectName,
|
|
164
163
|
projectDir,
|
|
165
|
-
pkg: stackableName
|
|
164
|
+
pkg: stackableName,
|
|
166
165
|
})
|
|
167
166
|
|
|
168
167
|
const { serviceName } = await inquirer.prompt({
|
|
@@ -170,7 +169,7 @@ async function createApplication (args, logger, pkgManager) {
|
|
|
170
169
|
name: 'serviceName',
|
|
171
170
|
message: 'What is the name of the service?',
|
|
172
171
|
default: generateName().dashed,
|
|
173
|
-
validate:
|
|
172
|
+
validate: value => {
|
|
174
173
|
if (value.length === 0) {
|
|
175
174
|
return 'Please enter a name'
|
|
176
175
|
}
|
|
@@ -184,19 +183,19 @@ async function createApplication (args, logger, pkgManager) {
|
|
|
184
183
|
}
|
|
185
184
|
|
|
186
185
|
return true
|
|
187
|
-
}
|
|
186
|
+
},
|
|
188
187
|
})
|
|
189
188
|
|
|
190
189
|
names.push(serviceName)
|
|
191
190
|
|
|
192
191
|
const stackableGenerator = new stackable.Generator({
|
|
193
192
|
logger,
|
|
194
|
-
inquirer
|
|
193
|
+
inquirer,
|
|
195
194
|
})
|
|
196
195
|
|
|
197
196
|
stackableGenerator.setConfig({
|
|
198
197
|
...stackableGenerator.config,
|
|
199
|
-
serviceName
|
|
198
|
+
serviceName,
|
|
200
199
|
})
|
|
201
200
|
|
|
202
201
|
generator.addService(stackableGenerator, serviceName)
|
|
@@ -209,8 +208,11 @@ async function createApplication (args, logger, pkgManager) {
|
|
|
209
208
|
name: 'shouldBreak',
|
|
210
209
|
message: 'Do you want to create another service?',
|
|
211
210
|
default: false,
|
|
212
|
-
choices: [
|
|
213
|
-
|
|
211
|
+
choices: [
|
|
212
|
+
{ name: 'yes', value: false },
|
|
213
|
+
{ name: 'no', value: true },
|
|
214
|
+
],
|
|
215
|
+
},
|
|
214
216
|
])
|
|
215
217
|
|
|
216
218
|
if (shouldBreak) {
|
|
@@ -226,8 +228,8 @@ async function createApplication (args, logger, pkgManager) {
|
|
|
226
228
|
type: 'list',
|
|
227
229
|
name: 'entrypoint',
|
|
228
230
|
message: 'Which service should be exposed?',
|
|
229
|
-
choices: names.map(name => ({ name, value: name }))
|
|
230
|
-
}
|
|
231
|
+
choices: names.map(name => ({ name, value: name })),
|
|
232
|
+
},
|
|
231
233
|
])
|
|
232
234
|
entrypoint = results.entrypoint
|
|
233
235
|
} else {
|
|
@@ -247,7 +249,10 @@ async function createApplication (args, logger, pkgManager) {
|
|
|
247
249
|
name: 'initGitRepository',
|
|
248
250
|
message: 'Do you want to init the git repository?',
|
|
249
251
|
default: false,
|
|
250
|
-
choices: [
|
|
252
|
+
choices: [
|
|
253
|
+
{ name: 'yes', value: true },
|
|
254
|
+
{ name: 'no', value: false },
|
|
255
|
+
],
|
|
251
256
|
})
|
|
252
257
|
|
|
253
258
|
if (initGitRepository) {
|
|
@@ -259,7 +264,7 @@ async function createApplication (args, logger, pkgManager) {
|
|
|
259
264
|
const content = `packages:
|
|
260
265
|
# all packages in direct subdirs of packages/
|
|
261
266
|
- 'services/*'`
|
|
262
|
-
await
|
|
267
|
+
await writeFile(join(projectDir, 'pnpm-workspace.yaml'), content)
|
|
263
268
|
}
|
|
264
269
|
|
|
265
270
|
if (args.install) {
|
|
@@ -288,7 +293,10 @@ async function createStackable (args, logger, pkgManager) {
|
|
|
288
293
|
name: 'initGitRepository',
|
|
289
294
|
message: 'Do you want to init the git repository?',
|
|
290
295
|
default: false,
|
|
291
|
-
choices: [
|
|
296
|
+
choices: [
|
|
297
|
+
{ name: 'yes', value: true },
|
|
298
|
+
{ name: 'no', value: false },
|
|
299
|
+
],
|
|
292
300
|
})
|
|
293
301
|
|
|
294
302
|
if (initGitRepository) {
|
package/src/utils.mjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
+
import * as desm from 'desm'
|
|
1
2
|
import { execa } from 'execa'
|
|
2
|
-
import { access, constants,
|
|
3
|
-
import { resolve, join, dirname } from 'path'
|
|
3
|
+
import { access, constants, readFile } from 'fs/promises'
|
|
4
4
|
import { createRequire } from 'module'
|
|
5
|
+
import { dirname, join, resolve } from 'path'
|
|
5
6
|
import semver from 'semver'
|
|
6
|
-
import * as desm from 'desm'
|
|
7
7
|
import * as url from 'url'
|
|
8
8
|
|
|
9
9
|
import ConfigManager from '@platformatic/config'
|
|
10
10
|
|
|
11
|
-
export const sleep = ms => new Promise(
|
|
11
|
+
export const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
|
|
12
12
|
export const randomBetween = (min, max) => Math.floor(Math.random() * (max - min + 1) + min)
|
|
13
13
|
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
|
|
14
14
|
|
|
@@ -32,7 +32,7 @@ export const getUsername = async () => {
|
|
|
32
32
|
return stdout.trim()
|
|
33
33
|
}
|
|
34
34
|
} catch (err) {
|
|
35
|
-
|
|
35
|
+
// ignore: git failed
|
|
36
36
|
}
|
|
37
37
|
try {
|
|
38
38
|
const { stdout } = await execa('whoami')
|
|
@@ -40,7 +40,7 @@ export const getUsername = async () => {
|
|
|
40
40
|
return stdout.trim()
|
|
41
41
|
}
|
|
42
42
|
} catch (err) {
|
|
43
|
-
|
|
43
|
+
// ignore: whoami failed
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
return null
|
|
@@ -64,18 +64,18 @@ export async function isDirectoryWriteable (directory) {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
export const findConfigFile = async
|
|
68
|
-
export const findDBConfigFile = async
|
|
69
|
-
export const findServiceConfigFile = async
|
|
70
|
-
export const findComposerConfigFile = async
|
|
71
|
-
export const findRuntimeConfigFile = async
|
|
67
|
+
export const findConfigFile = async directory => ConfigManager.findConfigFile(directory)
|
|
68
|
+
export const findDBConfigFile = async directory => ConfigManager.findConfigFile(directory, 'db')
|
|
69
|
+
export const findServiceConfigFile = async directory => ConfigManager.findConfigFile(directory, 'service')
|
|
70
|
+
export const findComposerConfigFile = async directory => ConfigManager.findConfigFile(directory, 'composer')
|
|
71
|
+
export const findRuntimeConfigFile = async directory => ConfigManager.findConfigFile(directory, 'runtime')
|
|
72
72
|
|
|
73
73
|
/**
|
|
74
74
|
* Gets the version of the specified dependency package from package.json
|
|
75
75
|
* @param {string} dependencyName
|
|
76
76
|
* @returns string
|
|
77
77
|
*/
|
|
78
|
-
export const getDependencyVersion = async
|
|
78
|
+
export const getDependencyVersion = async dependencyName => {
|
|
79
79
|
const rootPackageJson = join(__dirname, '..', 'package.json')
|
|
80
80
|
const packageJsonContents = JSON.parse(await readFile(rootPackageJson, 'utf8'))
|
|
81
81
|
const dependencies = packageJsonContents.dependencies
|
|
@@ -103,7 +103,7 @@ export const getDependencyVersion = async (dependencyName) => {
|
|
|
103
103
|
// some deps are resolved not at their root level
|
|
104
104
|
// for instance 'typescript' will be risolved in its own ./lib directory
|
|
105
105
|
// next loop is to find the nearest parent directory that contains a package.json file
|
|
106
|
-
while (!await isFileAccessible(join(dependencyPath, 'package.json'))) {
|
|
106
|
+
while (!(await isFileAccessible(join(dependencyPath, 'package.json')))) {
|
|
107
107
|
dependencyPath = join(dependencyPath, '..')
|
|
108
108
|
if (dependencyPath === '/') {
|
|
109
109
|
throw new Error(`Cannot find package.json for ${dependencyName}`)
|
|
@@ -118,7 +118,7 @@ export const getDependencyVersion = async (dependencyName) => {
|
|
|
118
118
|
|
|
119
119
|
export const minimumSupportedNodeVersions = ['18.8.0', '20.6.0']
|
|
120
120
|
|
|
121
|
-
export const isCurrentVersionSupported =
|
|
121
|
+
export const isCurrentVersionSupported = currentVersion => {
|
|
122
122
|
// TODO: add try/catch if some unsupported node version is passed
|
|
123
123
|
for (const version of minimumSupportedNodeVersions) {
|
|
124
124
|
if (semver.major(currentVersion) === semver.major(version) && semver.gte(currentVersion, version)) {
|
|
@@ -138,11 +138,3 @@ export function addPrefixToEnv (env, prefix) {
|
|
|
138
138
|
})
|
|
139
139
|
return output
|
|
140
140
|
}
|
|
141
|
-
|
|
142
|
-
export async function safeMkdir (dir) {
|
|
143
|
-
try {
|
|
144
|
-
await mkdir(dir, { recursive: true })
|
|
145
|
-
} catch (err) {
|
|
146
|
-
// do nothing
|
|
147
|
-
}
|
|
148
|
-
}
|
|
@@ -1,17 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { safeRemove } from '@platformatic/utils'
|
|
2
|
+
import { mkdtemp } from 'fs/promises'
|
|
2
3
|
import { equal } from 'node:assert'
|
|
3
|
-
import { timeout } from './timeout.mjs'
|
|
4
|
-
import { isFileAccessible } from '../../src/utils.mjs'
|
|
5
4
|
import { join } from 'node:path'
|
|
5
|
+
import { test } from 'node:test'
|
|
6
6
|
import { tmpdir } from 'os'
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
startMarketplace,
|
|
11
|
-
keys,
|
|
12
|
-
walk,
|
|
13
|
-
getServices
|
|
14
|
-
} from './helper.mjs'
|
|
7
|
+
import { isFileAccessible } from '../../src/utils.mjs'
|
|
8
|
+
import { executeCreatePlatformatic, getServices, keys, startMarketplace, walk } from './helper.mjs'
|
|
9
|
+
import { timeout } from './timeout.mjs'
|
|
15
10
|
|
|
16
11
|
let tmpDir
|
|
17
12
|
test.beforeEach(async () => {
|
|
@@ -20,43 +15,52 @@ test.beforeEach(async () => {
|
|
|
20
15
|
|
|
21
16
|
test.afterEach(async () => {
|
|
22
17
|
try {
|
|
23
|
-
await
|
|
18
|
+
await safeRemove(tmpDir)
|
|
24
19
|
} catch (e) {
|
|
25
20
|
// on purpose, in win the resource might be still "busy"
|
|
26
21
|
}
|
|
27
22
|
})
|
|
28
23
|
|
|
29
|
-
test('Creates a Platformatic Composer', { timeout }, async
|
|
24
|
+
test('Creates a Platformatic Composer', { timeout }, async t => {
|
|
30
25
|
const marketplaceHost = await startMarketplace(t)
|
|
31
26
|
// The actions must match IN ORDER
|
|
32
|
-
const actions = [
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
27
|
+
const actions = [
|
|
28
|
+
{
|
|
29
|
+
match: 'What kind of project do you want to create?',
|
|
30
|
+
do: [keys.ENTER], // Application
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
match: 'Where would you like to create your project?',
|
|
34
|
+
do: [keys.ENTER],
|
|
35
|
+
waitAfter: 8000,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
match: 'Which kind of project do you want to create?',
|
|
39
|
+
do: [keys.UP, keys.UP, keys.ENTER], // Composer
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
match: 'What is the name of the service?',
|
|
43
|
+
do: [keys.ENTER],
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
match: 'Do you want to create another service?',
|
|
47
|
+
do: [keys.DOWN, keys.ENTER], // no
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
// NOTE THAT HERE THE DEFAULT OPTION FOR SERVICE IS "YES"
|
|
51
|
+
match: 'Do you want to use TypeScript',
|
|
52
|
+
do: [keys.ENTER], // no
|
|
53
|
+
waitAfter: 8000,
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
match: 'What port do you want to use?',
|
|
57
|
+
do: [keys.ENTER],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
match: 'Do you want to init the git repository',
|
|
61
|
+
do: [keys.DOWN, keys.ENTER], // yes
|
|
62
|
+
},
|
|
63
|
+
]
|
|
60
64
|
await executeCreatePlatformatic(tmpDir, actions, { marketplaceHost })
|
|
61
65
|
|
|
62
66
|
const baseProjectDir = join(tmpDir, 'platformatic')
|
package/test/cli/db.test.mjs
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { safeRemove } from '@platformatic/utils'
|
|
2
|
+
import { mkdtemp } from 'fs/promises'
|
|
2
3
|
import { equal } from 'node:assert'
|
|
3
|
-
import { timeout } from './timeout.mjs'
|
|
4
|
-
import { isFileAccessible } from '../../src/utils.mjs'
|
|
5
4
|
import { join } from 'node:path'
|
|
5
|
+
import { test } from 'node:test'
|
|
6
6
|
import { tmpdir } from 'os'
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
startMarketplace,
|
|
11
|
-
keys,
|
|
12
|
-
walk,
|
|
13
|
-
getServices
|
|
14
|
-
} from './helper.mjs'
|
|
7
|
+
import { isFileAccessible } from '../../src/utils.mjs'
|
|
8
|
+
import { executeCreatePlatformatic, getServices, keys, startMarketplace, walk } from './helper.mjs'
|
|
9
|
+
import { timeout } from './timeout.mjs'
|
|
15
10
|
|
|
16
11
|
let tmpDir
|
|
17
12
|
test.beforeEach(async () => {
|
|
@@ -20,48 +15,59 @@ test.beforeEach(async () => {
|
|
|
20
15
|
|
|
21
16
|
test.afterEach(async () => {
|
|
22
17
|
try {
|
|
23
|
-
await
|
|
18
|
+
await safeRemove(tmpDir)
|
|
24
19
|
} catch (e) {
|
|
25
20
|
// on purpose, in win the resource might be still "busy"
|
|
26
21
|
}
|
|
27
22
|
})
|
|
28
23
|
|
|
29
|
-
test('Creates a Platformatic DB service with no migrations', { timeout }, async
|
|
24
|
+
test('Creates a Platformatic DB service with no migrations', { timeout }, async t => {
|
|
30
25
|
const marketplaceHost = await startMarketplace(t)
|
|
31
26
|
// The actions must match IN ORDER
|
|
32
|
-
const actions = [
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
27
|
+
const actions = [
|
|
28
|
+
{
|
|
29
|
+
match: 'What kind of project do you want to create?',
|
|
30
|
+
do: [keys.ENTER], // Application
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
match: 'Where would you like to create your project?',
|
|
34
|
+
do: [keys.ENTER],
|
|
35
|
+
waitAfter: 8000,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
match: 'Which kind of project do you want to create?',
|
|
39
|
+
do: [keys.UP, keys.ENTER], // DB
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
match: 'What is the name of the service?',
|
|
43
|
+
do: [keys.ENTER],
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
match: 'What is the connection string?',
|
|
47
|
+
do: [keys.ENTER],
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
match: 'Do you want to create default migrations',
|
|
51
|
+
do: [keys.DOWN, keys.ENTER], // no
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
match: 'Do you want to create another service?',
|
|
55
|
+
do: [keys.DOWN, keys.ENTER], // no
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
// NOTE THAT HERE THE DEFAULT OPTION FOR SERVICE IS "YES"
|
|
59
|
+
match: 'Do you want to use TypeScript',
|
|
60
|
+
do: [keys.ENTER], // no
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
match: 'What port do you want to use?',
|
|
64
|
+
do: [keys.ENTER],
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
match: 'Do you want to init the git repository',
|
|
68
|
+
do: [keys.DOWN, keys.ENTER], // yes
|
|
69
|
+
},
|
|
70
|
+
]
|
|
65
71
|
await executeCreatePlatformatic(tmpDir, actions, { marketplaceHost })
|
|
66
72
|
|
|
67
73
|
const baseProjectDir = join(tmpDir, 'platformatic')
|
package/test/cli/helper.mjs
CHANGED
|
@@ -13,7 +13,7 @@ export const keys = {
|
|
|
13
13
|
DOWN: '\x1B\x5B\x42',
|
|
14
14
|
UP: '\x1B\x5B\x41',
|
|
15
15
|
ENTER: '\x0D',
|
|
16
|
-
SPACE: '\x20'
|
|
16
|
+
SPACE: '\x20',
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const createPath = join(import.meta.url, '..', '..', 'create-platformatic.mjs')
|
|
@@ -60,19 +60,19 @@ export async function executeCreatePlatformatic (dir, actions = [], options = {}
|
|
|
60
60
|
const questions = [...actions]
|
|
61
61
|
try {
|
|
62
62
|
const execaOptions = {
|
|
63
|
-
cwd: dir
|
|
63
|
+
cwd: dir,
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
if (pkgManager === 'pnpm') {
|
|
67
67
|
execaOptions.env = {
|
|
68
|
-
npm_config_user_agent: 'pnpm/6.14.1 npm/? node/v16.4.2 darwin x64'
|
|
68
|
+
npm_config_user_agent: 'pnpm/6.14.1 npm/? node/v16.4.2 darwin x64',
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
const child = execa('node', [
|
|
73
73
|
createPath,
|
|
74
74
|
`--install=${pkgMgrInstall.toString()}`,
|
|
75
|
-
`--marketplace-host=${marketplaceHost}
|
|
75
|
+
`--marketplace-host=${marketplaceHost}`,
|
|
76
76
|
], execaOptions)
|
|
77
77
|
|
|
78
78
|
// We just need the "lastPrompt" printed before the process stopped to wait for an answer
|
|
@@ -147,7 +147,7 @@ export async function startMarketplace (t, opts = {}) {
|
|
|
147
147
|
return [
|
|
148
148
|
{ name: '@platformatic/composer' },
|
|
149
149
|
{ name: '@platformatic/db' },
|
|
150
|
-
{ name: '@platformatic/service' }
|
|
150
|
+
{ name: '@platformatic/service' },
|
|
151
151
|
]
|
|
152
152
|
})
|
|
153
153
|
|