create-platformatic 1.53.3 → 2.0.0-alpha.10
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 +27 -27
- package/src/index.mjs +70 -94
- package/src/utils.mjs +14 -22
- package/test/cli/.gitkeep +0 -0
- package/test/cli/README.md +0 -8
- package/test/cli/composer.test.mjs +0 -80
- package/test/cli/db.test.mjs +0 -86
- package/test/cli/helper.mjs +0 -159
- package/test/cli/runtime.test.mjs +0 -104
- package/test/cli/service.test.mjs +0 -200
- package/test/cli/stackable.test.mjs +0 -101
- package/test/cli/timeout.mjs +0 -3
- package/test/unit/create-git-repository.test.mjs +0 -61
- package/test/unit/fetch-stackables.mjs +0 -71
- package/test/unit/utils.test.mjs +0 -291
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": "
|
|
3
|
+
"version": "2.0.0-alpha.10",
|
|
4
4
|
"description": "Create platformatic application interactive tool",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
"license": "Apache-2.0",
|
|
16
16
|
"author": "Matteo Collina <hello@matteocollina.com>",
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@types/node": "^20.16.5",
|
|
19
18
|
"boring-name-generator": "^1.0.3",
|
|
20
19
|
"chalk": "^5.3.0",
|
|
21
20
|
"columnify": "^1.6.0",
|
|
@@ -24,42 +23,43 @@
|
|
|
24
23
|
"es-main": "^1.3.0",
|
|
25
24
|
"execa": "^8.0.1",
|
|
26
25
|
"help-me": "^5.0.0",
|
|
27
|
-
"inquirer": "^9.
|
|
28
|
-
"log-update": "^6.
|
|
26
|
+
"inquirer": "^9.2.16",
|
|
27
|
+
"log-update": "^6.0.0",
|
|
29
28
|
"minimist": "^1.2.8",
|
|
30
29
|
"ora": "^6.3.1",
|
|
31
|
-
"pino": "^
|
|
32
|
-
"pino-pretty": "^11.
|
|
30
|
+
"pino": "^9.0.0",
|
|
31
|
+
"pino-pretty": "^11.0.0",
|
|
33
32
|
"resolve": "^1.22.8",
|
|
34
|
-
"semver": "^7.6.
|
|
33
|
+
"semver": "^7.6.0",
|
|
35
34
|
"strip-ansi": "^7.1.0",
|
|
36
|
-
"undici": "^6.
|
|
35
|
+
"undici": "^6.9.0",
|
|
37
36
|
"which": "^3.0.1",
|
|
38
|
-
"@platformatic/config": "
|
|
39
|
-
"@platformatic/
|
|
40
|
-
"@platformatic/
|
|
37
|
+
"@platformatic/config": "2.0.0-alpha.10",
|
|
38
|
+
"@platformatic/utils": "2.0.0-alpha.10",
|
|
39
|
+
"@platformatic/generators": "2.0.0-alpha.10"
|
|
41
40
|
},
|
|
42
41
|
"devDependencies": {
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
42
|
+
"@types/node": "^22.5.0",
|
|
43
|
+
"ajv": "^8.12.0",
|
|
44
|
+
"borp": "^0.17.0",
|
|
45
|
+
"c8": "^10.0.0",
|
|
46
46
|
"cross-env": "^7.0.3",
|
|
47
47
|
"dotenv": "^16.4.5",
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"typescript": "~5.
|
|
53
|
-
"yaml": "^2.
|
|
54
|
-
"@platformatic/composer": "
|
|
55
|
-
"@platformatic/db": "
|
|
56
|
-
"@platformatic/
|
|
57
|
-
"@platformatic/
|
|
48
|
+
"eslint": "9",
|
|
49
|
+
"esmock": "^2.6.4",
|
|
50
|
+
"fastify": "5.0.0-alpha.4",
|
|
51
|
+
"neostandard": "^0.11.1",
|
|
52
|
+
"typescript": "~5.6.0",
|
|
53
|
+
"yaml": "^2.4.1",
|
|
54
|
+
"@platformatic/composer": "2.0.0-alpha.10",
|
|
55
|
+
"@platformatic/db": "2.0.0-alpha.10",
|
|
56
|
+
"@platformatic/service": "2.0.0-alpha.10",
|
|
57
|
+
"@platformatic/runtime": "2.0.0-alpha.10"
|
|
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,41 +1,43 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import path, { basename, join } from 'node:path'
|
|
3
|
-
import inquirer from 'inquirer'
|
|
1
|
+
import { createDirectory, getPkgManager } from '@platformatic/utils'
|
|
4
2
|
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
|
-
import { StackableGenerator } from '@platformatic/generators'
|
|
9
|
-
import pino from 'pino'
|
|
10
|
-
import pretty from 'pino-pretty'
|
|
11
3
|
import { execa } from 'execa'
|
|
4
|
+
import inquirer from 'inquirer'
|
|
12
5
|
import parseArgs from 'minimist'
|
|
13
|
-
import
|
|
14
|
-
import {
|
|
15
|
-
import { writeFile } from 'node:fs/promises'
|
|
16
|
-
import { request } from 'undici'
|
|
6
|
+
import { writeFile, readFile } from 'node:fs/promises'
|
|
7
|
+
import path, { basename, join } from 'node:path'
|
|
17
8
|
import { setTimeout } from 'node:timers/promises'
|
|
9
|
+
import { pathToFileURL } from 'node:url'
|
|
10
|
+
import ora from 'ora'
|
|
11
|
+
import pino from 'pino'
|
|
12
|
+
import pretty from 'pino-pretty'
|
|
18
13
|
import resolve from 'resolve'
|
|
14
|
+
import { request } from 'undici'
|
|
15
|
+
import { createGitRepository } from './create-git-repository.mjs'
|
|
16
|
+
import { say } from './say.mjs'
|
|
17
|
+
import { getUsername, getVersion, isCurrentVersionSupported, minimumSupportedNodeVersions } from './utils.mjs'
|
|
19
18
|
|
|
20
19
|
const MARKETPLACE_HOST = 'https://marketplace.platformatic.dev'
|
|
20
|
+
const defaultStackables = ['@platformatic/composer', '@platformatic/db', '@platformatic/service']
|
|
21
21
|
|
|
22
22
|
export async function fetchStackables (marketplaceHost) {
|
|
23
|
+
// Skip the remote network request if we are running tests
|
|
24
|
+
if (process.env.MARKETPLACE_TEST) {
|
|
25
|
+
return [...defaultStackables]
|
|
26
|
+
}
|
|
27
|
+
|
|
23
28
|
marketplaceHost = marketplaceHost || MARKETPLACE_HOST
|
|
24
29
|
|
|
25
30
|
const stackablesRequest = request(marketplaceHost + '/templates')
|
|
26
31
|
const stackablesRequestTimeout = setTimeout(5000, new Error('Request timed out'))
|
|
27
32
|
|
|
28
33
|
try {
|
|
29
|
-
const { statusCode, body } = await Promise.race([
|
|
30
|
-
stackablesRequest,
|
|
31
|
-
stackablesRequestTimeout
|
|
32
|
-
])
|
|
34
|
+
const { statusCode, body } = await Promise.race([stackablesRequest, stackablesRequestTimeout])
|
|
33
35
|
if (statusCode === 200) {
|
|
34
36
|
return (await body.json()).map(stackable => stackable.name)
|
|
35
37
|
}
|
|
36
38
|
} catch (err) {}
|
|
37
39
|
|
|
38
|
-
return [
|
|
40
|
+
return [...defaultStackables]
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
export async function chooseStackable (stackables) {
|
|
@@ -44,7 +46,7 @@ export async function chooseStackable (stackables) {
|
|
|
44
46
|
name: 'type',
|
|
45
47
|
message: 'Which kind of project do you want to create?',
|
|
46
48
|
default: stackables.indexOf('@platformatic/service'),
|
|
47
|
-
choices: stackables
|
|
49
|
+
choices: stackables,
|
|
48
50
|
})
|
|
49
51
|
|
|
50
52
|
return options.type
|
|
@@ -57,10 +59,24 @@ async function importOrLocal ({ pkgManager, name, projectDir, pkg }) {
|
|
|
57
59
|
try {
|
|
58
60
|
const fileToImport = resolve.sync(pkg, { basedir: projectDir })
|
|
59
61
|
return await import(pathToFileURL(fileToImport))
|
|
60
|
-
} catch {
|
|
62
|
+
} catch {}
|
|
63
|
+
|
|
64
|
+
let version = ''
|
|
65
|
+
|
|
66
|
+
if (defaultStackables.includes(pkg)) {
|
|
67
|
+
// Let's find if we are using one of the default stackables
|
|
68
|
+
// If we are, we have to use the "local" version of the package
|
|
69
|
+
|
|
70
|
+
const meta = await JSON.parse(await readFile(join(import.meta.dirname, '..', 'package.json'), 'utf-8'))
|
|
71
|
+
if (meta.version.includes('-')) {
|
|
72
|
+
version = `@${meta.version}`
|
|
73
|
+
} else {
|
|
74
|
+
version = `@^${meta.version}`
|
|
75
|
+
}
|
|
76
|
+
}
|
|
61
77
|
|
|
62
|
-
const spinner = ora(`Installing ${pkg}...`).start()
|
|
63
|
-
await execa(pkgManager, ['install', pkg], { cwd: projectDir })
|
|
78
|
+
const spinner = ora(`Installing ${pkg + version}...`).start()
|
|
79
|
+
await execa(pkgManager, ['install', pkg + version], { cwd: projectDir })
|
|
64
80
|
spinner.succeed()
|
|
65
81
|
|
|
66
82
|
const fileToImport = resolve.sync(pkg, { basedir: projectDir })
|
|
@@ -68,13 +84,13 @@ async function importOrLocal ({ pkgManager, name, projectDir, pkg }) {
|
|
|
68
84
|
}
|
|
69
85
|
}
|
|
70
86
|
|
|
71
|
-
export const createPlatformatic = async
|
|
87
|
+
export const createPlatformatic = async argv => {
|
|
72
88
|
const args = parseArgs(argv, {
|
|
73
89
|
default: {
|
|
74
|
-
install: true
|
|
90
|
+
install: true,
|
|
75
91
|
},
|
|
76
92
|
boolean: ['install'],
|
|
77
|
-
string: ['global-config', 'marketplace-host']
|
|
93
|
+
string: ['global-config', 'marketplace-host'],
|
|
78
94
|
})
|
|
79
95
|
|
|
80
96
|
const username = await getUsername()
|
|
@@ -90,29 +106,15 @@ export const createPlatformatic = async (argv) => {
|
|
|
90
106
|
await say(`Please use one of the following Node.js versions >= ${supportedVersions}.`)
|
|
91
107
|
}
|
|
92
108
|
|
|
93
|
-
const logger = pino(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
109
|
+
const logger = pino(
|
|
110
|
+
pretty({
|
|
111
|
+
translateTime: 'SYS:HH:MM:ss',
|
|
112
|
+
ignore: 'hostname,pid',
|
|
113
|
+
})
|
|
114
|
+
)
|
|
97
115
|
|
|
98
116
|
const pkgManager = getPkgManager()
|
|
99
|
-
|
|
100
|
-
const { projectType } = await inquirer.prompt({
|
|
101
|
-
type: 'list',
|
|
102
|
-
name: 'projectType',
|
|
103
|
-
message: 'What kind of project do you want to create?',
|
|
104
|
-
default: 'application',
|
|
105
|
-
choices: [
|
|
106
|
-
{ name: 'Application', value: 'application' },
|
|
107
|
-
{ name: 'Stackable', value: 'stackable' }
|
|
108
|
-
]
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
if (projectType === 'application') {
|
|
112
|
-
await createApplication(args, logger, pkgManager)
|
|
113
|
-
} else {
|
|
114
|
-
await createStackable(args, logger, pkgManager)
|
|
115
|
-
}
|
|
117
|
+
await createApplication(args, logger, pkgManager)
|
|
116
118
|
}
|
|
117
119
|
|
|
118
120
|
async function createApplication (args, logger, pkgManager) {
|
|
@@ -120,29 +122,29 @@ async function createApplication (args, logger, pkgManager) {
|
|
|
120
122
|
type: 'input',
|
|
121
123
|
name: 'dir',
|
|
122
124
|
message: 'Where would you like to create your project?',
|
|
123
|
-
default: 'platformatic'
|
|
125
|
+
default: 'platformatic',
|
|
124
126
|
})
|
|
125
127
|
|
|
126
128
|
const projectDir = path.resolve(process.cwd(), optionsDir.dir)
|
|
127
129
|
const projectName = basename(projectDir)
|
|
128
130
|
|
|
129
|
-
await
|
|
131
|
+
await createDirectory(projectDir)
|
|
130
132
|
|
|
131
133
|
const runtime = await importOrLocal({
|
|
132
134
|
pkgManager,
|
|
133
135
|
name: projectName,
|
|
134
136
|
projectDir,
|
|
135
|
-
pkg: '@platformatic/runtime'
|
|
137
|
+
pkg: '@platformatic/runtime',
|
|
136
138
|
})
|
|
137
139
|
|
|
138
140
|
const generator = new runtime.Generator({
|
|
139
141
|
logger,
|
|
140
142
|
name: projectName,
|
|
141
|
-
inquirer
|
|
143
|
+
inquirer,
|
|
142
144
|
})
|
|
143
145
|
generator.setConfig({
|
|
144
146
|
...generator.config,
|
|
145
|
-
targetDirectory: projectDir
|
|
147
|
+
targetDirectory: projectDir,
|
|
146
148
|
})
|
|
147
149
|
|
|
148
150
|
await generator.populateFromExistingConfig()
|
|
@@ -162,7 +164,7 @@ async function createApplication (args, logger, pkgManager) {
|
|
|
162
164
|
pkgManager,
|
|
163
165
|
name: projectName,
|
|
164
166
|
projectDir,
|
|
165
|
-
pkg: stackableName
|
|
167
|
+
pkg: stackableName,
|
|
166
168
|
})
|
|
167
169
|
|
|
168
170
|
const { serviceName } = await inquirer.prompt({
|
|
@@ -170,7 +172,7 @@ async function createApplication (args, logger, pkgManager) {
|
|
|
170
172
|
name: 'serviceName',
|
|
171
173
|
message: 'What is the name of the service?',
|
|
172
174
|
default: generateName().dashed,
|
|
173
|
-
validate:
|
|
175
|
+
validate: value => {
|
|
174
176
|
if (value.length === 0) {
|
|
175
177
|
return 'Please enter a name'
|
|
176
178
|
}
|
|
@@ -184,19 +186,19 @@ async function createApplication (args, logger, pkgManager) {
|
|
|
184
186
|
}
|
|
185
187
|
|
|
186
188
|
return true
|
|
187
|
-
}
|
|
189
|
+
},
|
|
188
190
|
})
|
|
189
191
|
|
|
190
192
|
names.push(serviceName)
|
|
191
193
|
|
|
192
194
|
const stackableGenerator = new stackable.Generator({
|
|
193
195
|
logger,
|
|
194
|
-
inquirer
|
|
196
|
+
inquirer,
|
|
195
197
|
})
|
|
196
198
|
|
|
197
199
|
stackableGenerator.setConfig({
|
|
198
200
|
...stackableGenerator.config,
|
|
199
|
-
serviceName
|
|
201
|
+
serviceName,
|
|
200
202
|
})
|
|
201
203
|
|
|
202
204
|
generator.addService(stackableGenerator, serviceName)
|
|
@@ -209,8 +211,11 @@ async function createApplication (args, logger, pkgManager) {
|
|
|
209
211
|
name: 'shouldBreak',
|
|
210
212
|
message: 'Do you want to create another service?',
|
|
211
213
|
default: false,
|
|
212
|
-
choices: [
|
|
213
|
-
|
|
214
|
+
choices: [
|
|
215
|
+
{ name: 'yes', value: false },
|
|
216
|
+
{ name: 'no', value: true },
|
|
217
|
+
],
|
|
218
|
+
},
|
|
214
219
|
])
|
|
215
220
|
|
|
216
221
|
if (shouldBreak) {
|
|
@@ -226,8 +231,8 @@ async function createApplication (args, logger, pkgManager) {
|
|
|
226
231
|
type: 'list',
|
|
227
232
|
name: 'entrypoint',
|
|
228
233
|
message: 'Which service should be exposed?',
|
|
229
|
-
choices: names.map(name => ({ name, value: name }))
|
|
230
|
-
}
|
|
234
|
+
choices: names.map(name => ({ name, value: name })),
|
|
235
|
+
},
|
|
231
236
|
])
|
|
232
237
|
entrypoint = results.entrypoint
|
|
233
238
|
} else {
|
|
@@ -247,7 +252,10 @@ async function createApplication (args, logger, pkgManager) {
|
|
|
247
252
|
name: 'initGitRepository',
|
|
248
253
|
message: 'Do you want to init the git repository?',
|
|
249
254
|
default: false,
|
|
250
|
-
choices: [
|
|
255
|
+
choices: [
|
|
256
|
+
{ name: 'yes', value: true },
|
|
257
|
+
{ name: 'no', value: false },
|
|
258
|
+
],
|
|
251
259
|
})
|
|
252
260
|
|
|
253
261
|
if (initGitRepository) {
|
|
@@ -259,7 +267,7 @@ async function createApplication (args, logger, pkgManager) {
|
|
|
259
267
|
const content = `packages:
|
|
260
268
|
# all packages in direct subdirs of packages/
|
|
261
269
|
- 'services/*'`
|
|
262
|
-
await
|
|
270
|
+
await writeFile(join(projectDir, 'pnpm-workspace.yaml'), content)
|
|
263
271
|
}
|
|
264
272
|
|
|
265
273
|
if (args.install) {
|
|
@@ -272,35 +280,3 @@ async function createApplication (args, logger, pkgManager) {
|
|
|
272
280
|
await generator.postInstallActions()
|
|
273
281
|
logger.info('You are all set! Run `npm start` to start your project.')
|
|
274
282
|
}
|
|
275
|
-
|
|
276
|
-
async function createStackable (args, logger, pkgManager) {
|
|
277
|
-
logger.info('Creating a stackable project...')
|
|
278
|
-
|
|
279
|
-
const generator = new StackableGenerator({ logger, inquirer })
|
|
280
|
-
await generator.ask()
|
|
281
|
-
await generator.prepare()
|
|
282
|
-
await generator.writeFiles()
|
|
283
|
-
|
|
284
|
-
const projectDir = path.resolve(process.cwd(), generator.config.targetDirectory)
|
|
285
|
-
|
|
286
|
-
const { initGitRepository } = await inquirer.prompt({
|
|
287
|
-
type: 'list',
|
|
288
|
-
name: 'initGitRepository',
|
|
289
|
-
message: 'Do you want to init the git repository?',
|
|
290
|
-
default: false,
|
|
291
|
-
choices: [{ name: 'yes', value: true }, { name: 'no', value: false }]
|
|
292
|
-
})
|
|
293
|
-
|
|
294
|
-
if (initGitRepository) {
|
|
295
|
-
await createGitRepository(logger, projectDir)
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
if (args.install) {
|
|
299
|
-
const spinner = ora('Installing dependencies...').start()
|
|
300
|
-
await execa(pkgManager, ['install'], { cwd: projectDir })
|
|
301
|
-
spinner.succeed()
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
await generator.postInstallActions()
|
|
305
|
-
logger.info('Stackable created successfully! Run `npm run create` to create an application.')
|
|
306
|
-
}
|
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
|
-
}
|
package/test/cli/.gitkeep
DELETED
|
File without changes
|
package/test/cli/README.md
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
To have this test working, you need to link 'platformatic' globally with:
|
|
2
|
-
|
|
3
|
-
```bash
|
|
4
|
-
# in platformatic root
|
|
5
|
-
cd packages/cli
|
|
6
|
-
pnpm link --global
|
|
7
|
-
```
|
|
8
|
-
The reason is that the type generation is done expecting the 'platformatic' command to be in the cli, see: https://github.com/platformatic/platformatic/blob/main/packages/create-platformatic/src/service/create-service-cli.mjs#L120
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { test } from 'node:test'
|
|
2
|
-
import { equal } from 'node:assert'
|
|
3
|
-
import { timeout } from './timeout.mjs'
|
|
4
|
-
import { isFileAccessible } from '../../src/utils.mjs'
|
|
5
|
-
import { join } from 'node:path'
|
|
6
|
-
import { tmpdir } from 'os'
|
|
7
|
-
import { mkdtemp, rm } from 'fs/promises'
|
|
8
|
-
import {
|
|
9
|
-
executeCreatePlatformatic,
|
|
10
|
-
startMarketplace,
|
|
11
|
-
keys,
|
|
12
|
-
walk,
|
|
13
|
-
getServices
|
|
14
|
-
} from './helper.mjs'
|
|
15
|
-
|
|
16
|
-
let tmpDir
|
|
17
|
-
test.beforeEach(async () => {
|
|
18
|
-
tmpDir = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
test.afterEach(async () => {
|
|
22
|
-
try {
|
|
23
|
-
await rm(tmpDir, { recursive: true, force: true })
|
|
24
|
-
} catch (e) {
|
|
25
|
-
// on purpose, in win the resource might be still "busy"
|
|
26
|
-
}
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
test('Creates a Platformatic Composer', { timeout }, async (t) => {
|
|
30
|
-
const marketplaceHost = await startMarketplace(t)
|
|
31
|
-
// The actions must match IN ORDER
|
|
32
|
-
const actions = [{
|
|
33
|
-
match: 'What kind of project do you want to create?',
|
|
34
|
-
do: [keys.ENTER] // Application
|
|
35
|
-
}, {
|
|
36
|
-
match: 'Where would you like to create your project?',
|
|
37
|
-
do: [keys.ENTER],
|
|
38
|
-
waitAfter: 8000
|
|
39
|
-
}, {
|
|
40
|
-
match: 'Which kind of project do you want to create?',
|
|
41
|
-
do: [keys.UP, keys.UP, keys.ENTER] // Composer
|
|
42
|
-
}, {
|
|
43
|
-
match: 'What is the name of the service?',
|
|
44
|
-
do: [keys.ENTER]
|
|
45
|
-
}, {
|
|
46
|
-
match: 'Do you want to create another service?',
|
|
47
|
-
do: [keys.DOWN, keys.ENTER] // no
|
|
48
|
-
}, {
|
|
49
|
-
// NOTE THAT HERE THE DEFAULT OPTION FOR SERVICE IS "YES"
|
|
50
|
-
match: 'Do you want to use TypeScript',
|
|
51
|
-
do: [keys.ENTER], // no
|
|
52
|
-
waitAfter: 8000
|
|
53
|
-
}, {
|
|
54
|
-
match: 'What port do you want to use?',
|
|
55
|
-
do: [keys.ENTER]
|
|
56
|
-
}, {
|
|
57
|
-
match: 'Do you want to init the git repository',
|
|
58
|
-
do: [keys.DOWN, keys.ENTER] // yes
|
|
59
|
-
}]
|
|
60
|
-
await executeCreatePlatformatic(tmpDir, actions, { marketplaceHost })
|
|
61
|
-
|
|
62
|
-
const baseProjectDir = join(tmpDir, 'platformatic')
|
|
63
|
-
const files = await walk(baseProjectDir)
|
|
64
|
-
console.log('==> created files', files)
|
|
65
|
-
equal(await isFileAccessible(join(baseProjectDir, '.gitignore')), true)
|
|
66
|
-
equal(await isFileAccessible(join(baseProjectDir, '.env')), true)
|
|
67
|
-
equal(await isFileAccessible(join(baseProjectDir, '.env.sample')), true)
|
|
68
|
-
equal(await isFileAccessible(join(baseProjectDir, 'platformatic.json')), true)
|
|
69
|
-
equal(await isFileAccessible(join(baseProjectDir, 'README.md')), true)
|
|
70
|
-
|
|
71
|
-
// Here check the generated service
|
|
72
|
-
const services = await getServices(join(baseProjectDir, 'services'))
|
|
73
|
-
equal(services.length, 1)
|
|
74
|
-
const baseServiceDir = join(baseProjectDir, 'services', services[0])
|
|
75
|
-
console.log(baseServiceDir)
|
|
76
|
-
equal(await isFileAccessible(join(baseServiceDir, 'platformatic.json')), true)
|
|
77
|
-
equal(await isFileAccessible(join(baseServiceDir, 'README.md')), true)
|
|
78
|
-
equal(await isFileAccessible(join(baseServiceDir, 'routes', 'root.js')), true)
|
|
79
|
-
equal(await isFileAccessible(join(baseServiceDir, 'plugins', 'example.js')), true)
|
|
80
|
-
})
|
package/test/cli/db.test.mjs
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { test } from 'node:test'
|
|
2
|
-
import { equal } from 'node:assert'
|
|
3
|
-
import { timeout } from './timeout.mjs'
|
|
4
|
-
import { isFileAccessible } from '../../src/utils.mjs'
|
|
5
|
-
import { join } from 'node:path'
|
|
6
|
-
import { tmpdir } from 'os'
|
|
7
|
-
import { mkdtemp, rm } from 'fs/promises'
|
|
8
|
-
import {
|
|
9
|
-
executeCreatePlatformatic,
|
|
10
|
-
startMarketplace,
|
|
11
|
-
keys,
|
|
12
|
-
walk,
|
|
13
|
-
getServices
|
|
14
|
-
} from './helper.mjs'
|
|
15
|
-
|
|
16
|
-
let tmpDir
|
|
17
|
-
test.beforeEach(async () => {
|
|
18
|
-
tmpDir = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
test.afterEach(async () => {
|
|
22
|
-
try {
|
|
23
|
-
await rm(tmpDir, { recursive: true, force: true })
|
|
24
|
-
} catch (e) {
|
|
25
|
-
// on purpose, in win the resource might be still "busy"
|
|
26
|
-
}
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
test('Creates a Platformatic DB service with no migrations', { timeout }, async (t) => {
|
|
30
|
-
const marketplaceHost = await startMarketplace(t)
|
|
31
|
-
// The actions must match IN ORDER
|
|
32
|
-
const actions = [{
|
|
33
|
-
match: 'What kind of project do you want to create?',
|
|
34
|
-
do: [keys.ENTER] // Application
|
|
35
|
-
}, {
|
|
36
|
-
match: 'Where would you like to create your project?',
|
|
37
|
-
do: [keys.ENTER],
|
|
38
|
-
waitAfter: 8000
|
|
39
|
-
}, {
|
|
40
|
-
match: 'Which kind of project do you want to create?',
|
|
41
|
-
do: [keys.UP, keys.ENTER] // DB
|
|
42
|
-
}, {
|
|
43
|
-
match: 'What is the name of the service?',
|
|
44
|
-
do: [keys.ENTER]
|
|
45
|
-
}, {
|
|
46
|
-
match: 'What is the connection string?',
|
|
47
|
-
do: [keys.ENTER]
|
|
48
|
-
}, {
|
|
49
|
-
match: 'Do you want to create default migrations',
|
|
50
|
-
do: [keys.DOWN, keys.ENTER] // no
|
|
51
|
-
}, {
|
|
52
|
-
match: 'Do you want to create another service?',
|
|
53
|
-
do: [keys.DOWN, keys.ENTER] // no
|
|
54
|
-
}, {
|
|
55
|
-
// NOTE THAT HERE THE DEFAULT OPTION FOR SERVICE IS "YES"
|
|
56
|
-
match: 'Do you want to use TypeScript',
|
|
57
|
-
do: [keys.ENTER] // no
|
|
58
|
-
}, {
|
|
59
|
-
match: 'What port do you want to use?',
|
|
60
|
-
do: [keys.ENTER]
|
|
61
|
-
}, {
|
|
62
|
-
match: 'Do you want to init the git repository',
|
|
63
|
-
do: [keys.DOWN, keys.ENTER] // yes
|
|
64
|
-
}]
|
|
65
|
-
await executeCreatePlatformatic(tmpDir, actions, { marketplaceHost })
|
|
66
|
-
|
|
67
|
-
const baseProjectDir = join(tmpDir, 'platformatic')
|
|
68
|
-
const files = await walk(baseProjectDir)
|
|
69
|
-
console.log('==> created files', files)
|
|
70
|
-
equal(await isFileAccessible(join(baseProjectDir, '.gitignore')), true)
|
|
71
|
-
equal(await isFileAccessible(join(baseProjectDir, '.env')), true)
|
|
72
|
-
equal(await isFileAccessible(join(baseProjectDir, '.env.sample')), true)
|
|
73
|
-
equal(await isFileAccessible(join(baseProjectDir, 'platformatic.json')), true)
|
|
74
|
-
equal(await isFileAccessible(join(baseProjectDir, 'README.md')), true)
|
|
75
|
-
|
|
76
|
-
// Here check the generated service
|
|
77
|
-
const services = await getServices(join(baseProjectDir, 'services'))
|
|
78
|
-
equal(services.length, 1)
|
|
79
|
-
const baseServiceDir = join(baseProjectDir, 'services', services[0])
|
|
80
|
-
console.log(baseServiceDir)
|
|
81
|
-
equal(await isFileAccessible(join(baseServiceDir, 'platformatic.json')), true)
|
|
82
|
-
equal(await isFileAccessible(join(baseServiceDir, 'README.md')), true)
|
|
83
|
-
equal(await isFileAccessible(join(baseServiceDir, 'migrations')), false)
|
|
84
|
-
equal(await isFileAccessible(join(baseServiceDir, 'routes', 'root.js')), true)
|
|
85
|
-
equal(await isFileAccessible(join(baseServiceDir, 'plugins', 'example.js')), true)
|
|
86
|
-
})
|