create-platformatic 2.0.0-alpha.2 → 2.0.0-alpha.21
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 +19 -19
- 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
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { test } from 'node:test'
|
|
2
|
-
import { deepEqual } from 'node:assert'
|
|
3
|
-
import { MockAgent, setGlobalDispatcher } from 'undici'
|
|
4
|
-
import { fetchStackables } from '../../src/index.mjs'
|
|
5
|
-
import { setTimeout } from 'node:timers/promises'
|
|
6
|
-
|
|
7
|
-
const mockAgent = new MockAgent({
|
|
8
|
-
keepAliveTimeout: 10,
|
|
9
|
-
keepAliveMaxTimeout: 10
|
|
10
|
-
})
|
|
11
|
-
mockAgent.disableNetConnect()
|
|
12
|
-
|
|
13
|
-
setGlobalDispatcher(mockAgent)
|
|
14
|
-
|
|
15
|
-
const MARKETPLACE_HOST = 'https://marketplace.platformatic.dev'
|
|
16
|
-
|
|
17
|
-
const mockPool = mockAgent.get(MARKETPLACE_HOST)
|
|
18
|
-
const defaultStackables = ['@platformatic/composer', '@platformatic/db', '@platformatic/service']
|
|
19
|
-
|
|
20
|
-
test('should fetch stackables from the marketplace', async () => {
|
|
21
|
-
const mockStackables = [
|
|
22
|
-
{ name: 'mock-service-1' },
|
|
23
|
-
{ name: 'mock-service-2' },
|
|
24
|
-
{ name: 'mock-service-3' }
|
|
25
|
-
]
|
|
26
|
-
|
|
27
|
-
mockPool.intercept({ path: '/templates' }).reply(200, mockStackables)
|
|
28
|
-
|
|
29
|
-
const stackables = await fetchStackables()
|
|
30
|
-
deepEqual(stackables, mockStackables.map(s => s.name))
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
test('should fetch private stackables from the marketplace', async () => {
|
|
34
|
-
const mockStackables = [
|
|
35
|
-
{ name: 'mock-service-1' },
|
|
36
|
-
{ name: 'mock-service-2' },
|
|
37
|
-
{ name: 'mock-service-3' },
|
|
38
|
-
{ name: 'private-mock-service-1' }
|
|
39
|
-
]
|
|
40
|
-
|
|
41
|
-
mockPool.intercept({ path: '/templates' }).reply(200, mockStackables)
|
|
42
|
-
|
|
43
|
-
const stackables = await fetchStackables(MARKETPLACE_HOST)
|
|
44
|
-
deepEqual(stackables, mockStackables.map(s => s.name))
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
test('should fetch only public stackables if user api key is wrong', async () => {
|
|
48
|
-
const mockStackables = [
|
|
49
|
-
{ name: 'mock-service-1' },
|
|
50
|
-
{ name: 'mock-service-2' },
|
|
51
|
-
{ name: 'mock-service-3' }
|
|
52
|
-
]
|
|
53
|
-
|
|
54
|
-
mockPool.intercept({ path: '/templates' }).reply(401)
|
|
55
|
-
mockPool.intercept({ path: '/templates' }).reply(200, mockStackables)
|
|
56
|
-
|
|
57
|
-
const stackables = await fetchStackables(MARKETPLACE_HOST)
|
|
58
|
-
deepEqual(stackables, mockStackables.map(s => s.name))
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
test('should return default stackables if fetching from the marketplace takes too long', async () => {
|
|
62
|
-
mockPool.intercept({ path: '/templates' }).reply(200, async () => await setTimeout(6000, []))
|
|
63
|
-
const stackables = await fetchStackables()
|
|
64
|
-
deepEqual(stackables, defaultStackables)
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
test('should return default stackables if fetching from the marketplace errors', async () => {
|
|
68
|
-
mockPool.intercept({ path: '/templates' }).replyWithError(new Error())
|
|
69
|
-
const stackables = await fetchStackables()
|
|
70
|
-
deepEqual(stackables, defaultStackables)
|
|
71
|
-
})
|
package/test/unit/utils.test.mjs
DELETED
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
import { test } from 'node:test'
|
|
4
|
-
import { equal, deepEqual, notEqual, doesNotThrow } from 'node:assert'
|
|
5
|
-
import { randomBetween, sleep, getDependencyVersion, findDBConfigFile, findServiceConfigFile, isFileAccessible, isCurrentVersionSupported, minimumSupportedNodeVersions, findRuntimeConfigFile, findComposerConfigFile, convertServiceNameToPrefix, addPrefixToEnv, safeMkdir } from '../../src/utils.mjs'
|
|
6
|
-
import { tmpdir } from 'os'
|
|
7
|
-
import { join } from 'path'
|
|
8
|
-
import esmock from 'esmock'
|
|
9
|
-
import semver from 'semver'
|
|
10
|
-
import { mkdir, mkdtemp, rm, writeFile } from 'fs/promises'
|
|
11
|
-
|
|
12
|
-
test('getUsername from git', async () => {
|
|
13
|
-
const name = 'lukeskywalker'
|
|
14
|
-
const { getUsername } = await esmock.strict('../../src/utils.mjs', {
|
|
15
|
-
execa: {
|
|
16
|
-
execa: (command) => {
|
|
17
|
-
if (command === 'git') {
|
|
18
|
-
return { stdout: name }
|
|
19
|
-
}
|
|
20
|
-
return ''
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
})
|
|
24
|
-
const username = await getUsername()
|
|
25
|
-
equal(username, name)
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
test('getUsername from whoami', async () => {
|
|
29
|
-
const name = 'hansolo'
|
|
30
|
-
const { getUsername } = await esmock.strict('../../src/utils.mjs', {
|
|
31
|
-
execa: {
|
|
32
|
-
execa: (command) => {
|
|
33
|
-
if (command === 'whoami') {
|
|
34
|
-
return { stdout: name }
|
|
35
|
-
}
|
|
36
|
-
return ''
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
})
|
|
40
|
-
const username = await getUsername()
|
|
41
|
-
equal(username, name)
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
test('if getUsername from git failed, it tries whoim', async () => {
|
|
45
|
-
const name = 'lukeskywalker'
|
|
46
|
-
|
|
47
|
-
const { getUsername } = await esmock.strict('../../src/utils.mjs', {
|
|
48
|
-
execa: {
|
|
49
|
-
execa: (command) => {
|
|
50
|
-
if (command === 'git') {
|
|
51
|
-
throw new Error('git failed')
|
|
52
|
-
}
|
|
53
|
-
if (command === 'whoami') {
|
|
54
|
-
return { stdout: name }
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return ''
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
})
|
|
61
|
-
const username = await getUsername()
|
|
62
|
-
equal(username, name)
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
test('if both git usern.ame and whoami fail, no username is set', async () => {
|
|
66
|
-
const { getUsername } = await esmock.strict('../../src/utils.mjs', {
|
|
67
|
-
execa: {
|
|
68
|
-
execa: (command) => {
|
|
69
|
-
if (command === 'git') {
|
|
70
|
-
throw new Error('git failed')
|
|
71
|
-
}
|
|
72
|
-
if (command === 'whoami') {
|
|
73
|
-
throw new Error('whoami failed')
|
|
74
|
-
}
|
|
75
|
-
return ''
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
})
|
|
79
|
-
const username = await getUsername()
|
|
80
|
-
equal(username, null)
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
test('getUsername - no username found', async () => {
|
|
84
|
-
const { getUsername } = await esmock.strict('../../src/utils.mjs', {
|
|
85
|
-
execa: {
|
|
86
|
-
execa: (command) => {
|
|
87
|
-
return ''
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
})
|
|
91
|
-
const username = await getUsername()
|
|
92
|
-
equal(username, null)
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
test('randomBetween', async () => {
|
|
96
|
-
const min = 1
|
|
97
|
-
const max = 10
|
|
98
|
-
const random = randomBetween(min, max)
|
|
99
|
-
equal(random >= min && random <= max, true)
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
test('sleep', async () => {
|
|
103
|
-
const start = Date.now()
|
|
104
|
-
await sleep(100)
|
|
105
|
-
const end = Date.now()
|
|
106
|
-
// We cannot assert the exact drift because timers
|
|
107
|
-
// are imprecise
|
|
108
|
-
equal(end - start >= 90, true)
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
test('getDependencyVersion', async () => {
|
|
112
|
-
const fastifyVersion = await getDependencyVersion('fastify')
|
|
113
|
-
// We cannot assert the exact version because it changes
|
|
114
|
-
equal(semver.valid(fastifyVersion), fastifyVersion)
|
|
115
|
-
equal(semver.gt(fastifyVersion, '4.10.0'), true)
|
|
116
|
-
|
|
117
|
-
const typescriptVersion = await getDependencyVersion('typescript')
|
|
118
|
-
// We cannot assert the exact version because it changes
|
|
119
|
-
equal(semver.valid(typescriptVersion), typescriptVersion)
|
|
120
|
-
equal(semver.gt(typescriptVersion, '5.0.0'), true)
|
|
121
|
-
|
|
122
|
-
const platformaticConfig = await getDependencyVersion('@platformatic/config')
|
|
123
|
-
// We cannot assert the exact version because it changes
|
|
124
|
-
equal(semver.valid(platformaticConfig), platformaticConfig)
|
|
125
|
-
equal(semver.gt(platformaticConfig, '1.0.0'), true)
|
|
126
|
-
|
|
127
|
-
const typesVersion = await getDependencyVersion('@types/node')
|
|
128
|
-
// We cannot assert the exact version because it changes
|
|
129
|
-
equal(semver.valid(typesVersion), typesVersion)
|
|
130
|
-
equal(semver.gt(typesVersion, '20.0.0'), true)
|
|
131
|
-
|
|
132
|
-
const unkownVersion = await getDependencyVersion('@types/npm')
|
|
133
|
-
equal(unkownVersion, undefined)
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
test('findDBConfigFile', async () => {
|
|
137
|
-
const tmpDir1 = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
138
|
-
const tmpDir2 = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
139
|
-
const config = join(tmpDir1, 'platformatic.db.yml')
|
|
140
|
-
await writeFile(config, 'TEST')
|
|
141
|
-
equal(await findDBConfigFile(tmpDir1), 'platformatic.db.yml')
|
|
142
|
-
equal(await findDBConfigFile(tmpDir2), undefined)
|
|
143
|
-
await rm(tmpDir1, { recursive: true, force: true })
|
|
144
|
-
await rm(tmpDir2, { recursive: true, force: true })
|
|
145
|
-
})
|
|
146
|
-
|
|
147
|
-
test('findServiceConfigFile', async () => {
|
|
148
|
-
const tmpDir1 = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
149
|
-
const tmpDir2 = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
150
|
-
const config = join(tmpDir1, 'platformatic.service.toml')
|
|
151
|
-
await writeFile(config, 'TEST')
|
|
152
|
-
equal(await findServiceConfigFile(tmpDir1), 'platformatic.service.toml')
|
|
153
|
-
equal(await findServiceConfigFile(tmpDir2), undefined)
|
|
154
|
-
await rm(tmpDir1, { recursive: true, force: true })
|
|
155
|
-
await rm(tmpDir2, { recursive: true, force: true })
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
test('findComposerConfigFile', async () => {
|
|
159
|
-
const tmpDir1 = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
160
|
-
const tmpDir2 = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
161
|
-
const config = join(tmpDir1, 'platformatic.composer.yml')
|
|
162
|
-
await writeFile(config, 'TEST')
|
|
163
|
-
equal(await findComposerConfigFile(tmpDir1), 'platformatic.composer.yml')
|
|
164
|
-
equal(await findComposerConfigFile(tmpDir2), undefined)
|
|
165
|
-
await rm(tmpDir1, { recursive: true, force: true })
|
|
166
|
-
await rm(tmpDir2, { recursive: true, force: true })
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
test('findRuntimeConfigFile', async () => {
|
|
170
|
-
const tmpDir1 = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
171
|
-
const tmpDir2 = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
172
|
-
const config = join(tmpDir1, 'platformatic.runtime.yml')
|
|
173
|
-
await writeFile(config, 'TEST')
|
|
174
|
-
equal(await findRuntimeConfigFile(tmpDir1), 'platformatic.runtime.yml')
|
|
175
|
-
equal(await findRuntimeConfigFile(tmpDir2), undefined)
|
|
176
|
-
await rm(tmpDir1, { recursive: true, force: true })
|
|
177
|
-
await rm(tmpDir2, { recursive: true, force: true })
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
test('isFileAccessible', async () => {
|
|
181
|
-
const tmpDir1 = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
182
|
-
const config = join(tmpDir1, 'platformatic.db.yml')
|
|
183
|
-
await writeFile(config, 'TEST')
|
|
184
|
-
equal(await isFileAccessible(config), true)
|
|
185
|
-
const config2 = join(tmpDir1, 'platformatic2.db.yml')
|
|
186
|
-
equal(await isFileAccessible(config2), false)
|
|
187
|
-
await rm(tmpDir1, { recursive: true, force: true })
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
test('minimumSupportedNodeVersions', async () => {
|
|
191
|
-
equal(Array.isArray(minimumSupportedNodeVersions), true)
|
|
192
|
-
notEqual(minimumSupportedNodeVersions.length, 0)
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
test('isCurrentVersionSupported', async () => {
|
|
196
|
-
const { major, minor, patch } = semver.minVersion(minimumSupportedNodeVersions[0])
|
|
197
|
-
{
|
|
198
|
-
// major - 1 not supported
|
|
199
|
-
const nodeVersion = `${major - 1}.${minor}.${patch}`
|
|
200
|
-
const supported = isCurrentVersionSupported(nodeVersion)
|
|
201
|
-
equal(supported, false)
|
|
202
|
-
}
|
|
203
|
-
{
|
|
204
|
-
// minor - 1 not supported
|
|
205
|
-
const nodeVersion = `${major}.${minor - 1}.${patch}`
|
|
206
|
-
const supported = isCurrentVersionSupported(nodeVersion)
|
|
207
|
-
equal(supported, false)
|
|
208
|
-
}
|
|
209
|
-
{
|
|
210
|
-
// v16 more than minimum is supported
|
|
211
|
-
const supported = isCurrentVersionSupported(`${major}.${minor + 2}.${patch}`)
|
|
212
|
-
equal(supported, true)
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// node version 20 test, to check greater and lesser major version
|
|
216
|
-
{
|
|
217
|
-
// v18.0.0 is not supported
|
|
218
|
-
const nodeVersion = '18.0.0'
|
|
219
|
-
const supported = isCurrentVersionSupported(nodeVersion)
|
|
220
|
-
equal(supported, false)
|
|
221
|
-
}
|
|
222
|
-
{
|
|
223
|
-
// v18.8.0 is supported
|
|
224
|
-
const nodeVersion = '18.8.0'
|
|
225
|
-
const supported = isCurrentVersionSupported(nodeVersion)
|
|
226
|
-
equal(supported, true)
|
|
227
|
-
}
|
|
228
|
-
{
|
|
229
|
-
// v20.5.1 is not supported
|
|
230
|
-
const supported = isCurrentVersionSupported('20.5.1')
|
|
231
|
-
equal(supported, false)
|
|
232
|
-
}
|
|
233
|
-
{
|
|
234
|
-
// v20.6.0 is supported
|
|
235
|
-
const nodeVersion = '20.6.0'
|
|
236
|
-
const supported = isCurrentVersionSupported(nodeVersion)
|
|
237
|
-
equal(supported, true)
|
|
238
|
-
}
|
|
239
|
-
{
|
|
240
|
-
// v19.0.0 is not supported
|
|
241
|
-
const supported = isCurrentVersionSupported('19.0.0')
|
|
242
|
-
equal(supported, false)
|
|
243
|
-
}
|
|
244
|
-
{
|
|
245
|
-
// v19.9.0 is not supported
|
|
246
|
-
const supported = isCurrentVersionSupported('19.9.0')
|
|
247
|
-
equal(supported, false)
|
|
248
|
-
}
|
|
249
|
-
for (const version of minimumSupportedNodeVersions) {
|
|
250
|
-
const supported = isCurrentVersionSupported(version)
|
|
251
|
-
equal(supported, true)
|
|
252
|
-
}
|
|
253
|
-
})
|
|
254
|
-
|
|
255
|
-
test('should convert service name to env prefix', async () => {
|
|
256
|
-
const expectations = {
|
|
257
|
-
'my-service': 'MY_SERVICE',
|
|
258
|
-
a: 'A',
|
|
259
|
-
MY_SERVICE: 'MY_SERVICE',
|
|
260
|
-
asderas123: 'ASDERAS123'
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
Object.entries(expectations).forEach((exp) => {
|
|
264
|
-
const converted = convertServiceNameToPrefix(exp[0])
|
|
265
|
-
equal(exp[1], converted)
|
|
266
|
-
})
|
|
267
|
-
})
|
|
268
|
-
|
|
269
|
-
test('should add prefix to a key/value object', async () => {
|
|
270
|
-
const prefix = 'MY_PREFIX'
|
|
271
|
-
const env = {
|
|
272
|
-
PLT_HOSTNAME: 'myhost',
|
|
273
|
-
PORT: '3042'
|
|
274
|
-
}
|
|
275
|
-
deepEqual(addPrefixToEnv(env, prefix), {
|
|
276
|
-
MY_PREFIX_PLT_HOSTNAME: 'myhost',
|
|
277
|
-
MY_PREFIX_PORT: '3042'
|
|
278
|
-
})
|
|
279
|
-
})
|
|
280
|
-
|
|
281
|
-
test('safeMkdir should not throw if dir already exists', async () => {
|
|
282
|
-
const tempDirectory = join(tmpdir(), 'safeMkdirTest')
|
|
283
|
-
test.after(async () => {
|
|
284
|
-
await rm(tempDirectory, { recursive: true })
|
|
285
|
-
})
|
|
286
|
-
await mkdir(tempDirectory)
|
|
287
|
-
|
|
288
|
-
doesNotThrow(async () => {
|
|
289
|
-
await safeMkdir(tempDirectory)
|
|
290
|
-
})
|
|
291
|
-
})
|