create-platformatic 2.0.0-alpha.7 → 2.0.0-alpha.8
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/package.json +9 -9
- package/test/cli/.gitkeep +0 -0
- package/test/cli/README.md +0 -8
- package/test/cli/composer.test.mjs +0 -84
- package/test/cli/db.test.mjs +0 -92
- package/test/cli/helper.mjs +0 -159
- package/test/cli/runtime.test.mjs +0 -112
- package/test/cli/service.test.mjs +0 -222
- package/test/cli/stackable.test.mjs +0 -114
- package/test/cli/timeout.mjs +0 -3
- package/test/unit/create-git-repository.test.mjs +0 -67
- package/test/unit/fetch-stackables.mjs +0 -71
- package/test/unit/utils.test.mjs +0 -293
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.8",
|
|
4
4
|
"description": "Create platformatic application interactive tool",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
"strip-ansi": "^7.1.0",
|
|
35
35
|
"undici": "^6.9.0",
|
|
36
36
|
"which": "^3.0.1",
|
|
37
|
-
"@platformatic/config": "2.0.0-alpha.
|
|
38
|
-
"@platformatic/generators": "2.0.0-alpha.
|
|
39
|
-
"@platformatic/utils": "2.0.0-alpha.
|
|
37
|
+
"@platformatic/config": "2.0.0-alpha.8",
|
|
38
|
+
"@platformatic/generators": "2.0.0-alpha.8",
|
|
39
|
+
"@platformatic/utils": "2.0.0-alpha.8"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/node": "^22.5.0",
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
"esmock": "^2.6.4",
|
|
50
50
|
"fastify": "^4.26.2",
|
|
51
51
|
"neostandard": "^0.11.1",
|
|
52
|
-
"typescript": "~5.
|
|
52
|
+
"typescript": "~5.6.0",
|
|
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.8",
|
|
55
|
+
"@platformatic/db": "2.0.0-alpha.8",
|
|
56
|
+
"@platformatic/runtime": "2.0.0-alpha.8",
|
|
57
|
+
"@platformatic/service": "2.0.0-alpha.8"
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|
|
60
60
|
"test:cli": "borp --pattern \"test/cli/*test.mjs\" --timeout=180000 --concurrency=1",
|
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,84 +0,0 @@
|
|
|
1
|
-
import { safeRemove } from '@platformatic/utils'
|
|
2
|
-
import { mkdtemp } from 'fs/promises'
|
|
3
|
-
import { equal } from 'node:assert'
|
|
4
|
-
import { join } from 'node:path'
|
|
5
|
-
import { test } from 'node:test'
|
|
6
|
-
import { tmpdir } from 'os'
|
|
7
|
-
import { isFileAccessible } from '../../src/utils.mjs'
|
|
8
|
-
import { executeCreatePlatformatic, getServices, keys, startMarketplace, walk } from './helper.mjs'
|
|
9
|
-
import { timeout } from './timeout.mjs'
|
|
10
|
-
|
|
11
|
-
let tmpDir
|
|
12
|
-
test.beforeEach(async () => {
|
|
13
|
-
tmpDir = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
test.afterEach(async () => {
|
|
17
|
-
try {
|
|
18
|
-
await safeRemove(tmpDir)
|
|
19
|
-
} catch (e) {
|
|
20
|
-
// on purpose, in win the resource might be still "busy"
|
|
21
|
-
}
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
test('Creates a Platformatic Composer', { timeout }, async t => {
|
|
25
|
-
const marketplaceHost = await startMarketplace(t)
|
|
26
|
-
// The actions must match IN ORDER
|
|
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
|
-
]
|
|
64
|
-
await executeCreatePlatformatic(tmpDir, actions, { marketplaceHost })
|
|
65
|
-
|
|
66
|
-
const baseProjectDir = join(tmpDir, 'platformatic')
|
|
67
|
-
const files = await walk(baseProjectDir)
|
|
68
|
-
console.log('==> created files', files)
|
|
69
|
-
equal(await isFileAccessible(join(baseProjectDir, '.gitignore')), true)
|
|
70
|
-
equal(await isFileAccessible(join(baseProjectDir, '.env')), true)
|
|
71
|
-
equal(await isFileAccessible(join(baseProjectDir, '.env.sample')), true)
|
|
72
|
-
equal(await isFileAccessible(join(baseProjectDir, 'platformatic.json')), true)
|
|
73
|
-
equal(await isFileAccessible(join(baseProjectDir, 'README.md')), true)
|
|
74
|
-
|
|
75
|
-
// Here check the generated service
|
|
76
|
-
const services = await getServices(join(baseProjectDir, 'services'))
|
|
77
|
-
equal(services.length, 1)
|
|
78
|
-
const baseServiceDir = join(baseProjectDir, 'services', services[0])
|
|
79
|
-
console.log(baseServiceDir)
|
|
80
|
-
equal(await isFileAccessible(join(baseServiceDir, 'platformatic.json')), true)
|
|
81
|
-
equal(await isFileAccessible(join(baseServiceDir, 'README.md')), true)
|
|
82
|
-
equal(await isFileAccessible(join(baseServiceDir, 'routes', 'root.js')), true)
|
|
83
|
-
equal(await isFileAccessible(join(baseServiceDir, 'plugins', 'example.js')), true)
|
|
84
|
-
})
|
package/test/cli/db.test.mjs
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { safeRemove } from '@platformatic/utils'
|
|
2
|
-
import { mkdtemp } from 'fs/promises'
|
|
3
|
-
import { equal } from 'node:assert'
|
|
4
|
-
import { join } from 'node:path'
|
|
5
|
-
import { test } from 'node:test'
|
|
6
|
-
import { tmpdir } from 'os'
|
|
7
|
-
import { isFileAccessible } from '../../src/utils.mjs'
|
|
8
|
-
import { executeCreatePlatformatic, getServices, keys, startMarketplace, walk } from './helper.mjs'
|
|
9
|
-
import { timeout } from './timeout.mjs'
|
|
10
|
-
|
|
11
|
-
let tmpDir
|
|
12
|
-
test.beforeEach(async () => {
|
|
13
|
-
tmpDir = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
test.afterEach(async () => {
|
|
17
|
-
try {
|
|
18
|
-
await safeRemove(tmpDir)
|
|
19
|
-
} catch (e) {
|
|
20
|
-
// on purpose, in win the resource might be still "busy"
|
|
21
|
-
}
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
test('Creates a Platformatic DB service with no migrations', { timeout }, async t => {
|
|
25
|
-
const marketplaceHost = await startMarketplace(t)
|
|
26
|
-
// The actions must match IN ORDER
|
|
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
|
-
]
|
|
71
|
-
await executeCreatePlatformatic(tmpDir, actions, { marketplaceHost })
|
|
72
|
-
|
|
73
|
-
const baseProjectDir = join(tmpDir, 'platformatic')
|
|
74
|
-
const files = await walk(baseProjectDir)
|
|
75
|
-
console.log('==> created files', files)
|
|
76
|
-
equal(await isFileAccessible(join(baseProjectDir, '.gitignore')), true)
|
|
77
|
-
equal(await isFileAccessible(join(baseProjectDir, '.env')), true)
|
|
78
|
-
equal(await isFileAccessible(join(baseProjectDir, '.env.sample')), true)
|
|
79
|
-
equal(await isFileAccessible(join(baseProjectDir, 'platformatic.json')), true)
|
|
80
|
-
equal(await isFileAccessible(join(baseProjectDir, 'README.md')), true)
|
|
81
|
-
|
|
82
|
-
// Here check the generated service
|
|
83
|
-
const services = await getServices(join(baseProjectDir, 'services'))
|
|
84
|
-
equal(services.length, 1)
|
|
85
|
-
const baseServiceDir = join(baseProjectDir, 'services', services[0])
|
|
86
|
-
console.log(baseServiceDir)
|
|
87
|
-
equal(await isFileAccessible(join(baseServiceDir, 'platformatic.json')), true)
|
|
88
|
-
equal(await isFileAccessible(join(baseServiceDir, 'README.md')), true)
|
|
89
|
-
equal(await isFileAccessible(join(baseServiceDir, 'migrations')), false)
|
|
90
|
-
equal(await isFileAccessible(join(baseServiceDir, 'routes', 'root.js')), true)
|
|
91
|
-
equal(await isFileAccessible(join(baseServiceDir, 'plugins', 'example.js')), true)
|
|
92
|
-
})
|
package/test/cli/helper.mjs
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import os from 'node:os'
|
|
2
|
-
import { execa } from 'execa'
|
|
3
|
-
import { join } from 'desm'
|
|
4
|
-
import stripAnsi from 'strip-ansi'
|
|
5
|
-
import { promisify } from 'node:util'
|
|
6
|
-
import { promises as fs } from 'node:fs'
|
|
7
|
-
import path from 'node:path'
|
|
8
|
-
import fastify from 'fastify'
|
|
9
|
-
|
|
10
|
-
const sleep = promisify(setTimeout)
|
|
11
|
-
|
|
12
|
-
export const keys = {
|
|
13
|
-
DOWN: '\x1B\x5B\x42',
|
|
14
|
-
UP: '\x1B\x5B\x41',
|
|
15
|
-
ENTER: '\x0D',
|
|
16
|
-
SPACE: '\x20',
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export const createPath = join(import.meta.url, '..', '..', 'create-platformatic.mjs')
|
|
20
|
-
|
|
21
|
-
const match = (str, match) => {
|
|
22
|
-
if (Array.isArray(match)) {
|
|
23
|
-
return match.some((m) => str.includes(m))
|
|
24
|
-
}
|
|
25
|
-
return str.includes(match)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export const walk = async (dir) => {
|
|
29
|
-
let files = await fs.readdir(dir)
|
|
30
|
-
files = await Promise.all(files.map(async file => {
|
|
31
|
-
const filePath = path.join(dir, file)
|
|
32
|
-
const stats = await fs.stat(filePath)
|
|
33
|
-
if (stats.isDirectory()) return walk(filePath)
|
|
34
|
-
else if (stats.isFile()) return filePath
|
|
35
|
-
}))
|
|
36
|
-
return files.reduce((all, folderContents) => all.concat(folderContents), [])
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export const getServices = async (dir) => {
|
|
40
|
-
const files = await fs.readdir(dir)
|
|
41
|
-
const services = []
|
|
42
|
-
for (const file of files) {
|
|
43
|
-
services.push(file)
|
|
44
|
-
}
|
|
45
|
-
return services
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Actions are in the form:
|
|
49
|
-
// {
|
|
50
|
-
// match: 'Server listening at',
|
|
51
|
-
// do: [keys.DOWN, keys.ENTER]
|
|
52
|
-
// }
|
|
53
|
-
export async function executeCreatePlatformatic (dir, actions = [], options = {}) {
|
|
54
|
-
const done = options.done || 'You are all set!'
|
|
55
|
-
const pkgMgrInstall = options.pkgMgrInstall || false
|
|
56
|
-
const pkgManager = options.pkgManager || 'npm'
|
|
57
|
-
const marketplaceHost = options.marketplaceHost
|
|
58
|
-
|
|
59
|
-
const runCreatePlatformatic = async () => {
|
|
60
|
-
const questions = [...actions]
|
|
61
|
-
try {
|
|
62
|
-
const execaOptions = {
|
|
63
|
-
cwd: dir,
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (pkgManager === 'pnpm') {
|
|
67
|
-
execaOptions.env = {
|
|
68
|
-
npm_config_user_agent: 'pnpm/6.14.1 npm/? node/v16.4.2 darwin x64',
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const child = execa('node', [
|
|
73
|
-
createPath,
|
|
74
|
-
`--install=${pkgMgrInstall.toString()}`,
|
|
75
|
-
`--marketplace-host=${marketplaceHost}`,
|
|
76
|
-
], execaOptions)
|
|
77
|
-
|
|
78
|
-
// We just need the "lastPrompt" printed before the process stopped to wait for an answer
|
|
79
|
-
// If we don't have any outptu from process for more than 500ms, we assume it's waiting for an answer
|
|
80
|
-
let lastPrompt = ''
|
|
81
|
-
|
|
82
|
-
child.stdout.on('data', (chunk) => {
|
|
83
|
-
const str = stripAnsi(chunk.toString()).trim()
|
|
84
|
-
if (str) {
|
|
85
|
-
lastPrompt = str
|
|
86
|
-
}
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
let expectedQuestion = questions.shift()
|
|
90
|
-
|
|
91
|
-
// We need this because the prompt prints an introduction before asking anything.
|
|
92
|
-
// If we don't like this, we could use a flag to recognize when the introduction is done
|
|
93
|
-
await sleep(5000)
|
|
94
|
-
|
|
95
|
-
while (true) {
|
|
96
|
-
if (!expectedQuestion) {
|
|
97
|
-
await sleep(500)
|
|
98
|
-
// We processed all expected questions, so now we wait for the process to be done.
|
|
99
|
-
// If the "done" string is not printed, the test will timeout
|
|
100
|
-
if (lastPrompt && lastPrompt.includes(done)) {
|
|
101
|
-
safeKill(child)
|
|
102
|
-
return
|
|
103
|
-
}
|
|
104
|
-
} else if (match(lastPrompt, expectedQuestion.match)) {
|
|
105
|
-
console.log('==> MATCH', expectedQuestion.match)
|
|
106
|
-
lastPrompt = ''
|
|
107
|
-
|
|
108
|
-
for (const key of expectedQuestion.do) {
|
|
109
|
-
child.stdin?.write(key)
|
|
110
|
-
const waitAfter = expectedQuestion.waitAfter || 500
|
|
111
|
-
await sleep(waitAfter)
|
|
112
|
-
}
|
|
113
|
-
expectedQuestion = questions.shift()
|
|
114
|
-
} else {
|
|
115
|
-
throw new Error(`Expected ${expectedQuestion.match}, got ${lastPrompt}`)
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
} catch (err) {
|
|
119
|
-
console.error(err)
|
|
120
|
-
throw err
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
await runCreatePlatformatic()
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export async function safeKill (child) {
|
|
127
|
-
child.kill('SIGINT')
|
|
128
|
-
if (os.platform() === 'win32') {
|
|
129
|
-
try {
|
|
130
|
-
await execa('taskkill', ['/pid', child.pid, '/f', '/t'])
|
|
131
|
-
} catch (err) {
|
|
132
|
-
if (err.stderr.indexOf('not found') === 0) {
|
|
133
|
-
console.error(`Failed to kill process ${child.pid}`)
|
|
134
|
-
console.error(err)
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export async function startMarketplace (t, opts = {}) {
|
|
141
|
-
const marketplace = fastify()
|
|
142
|
-
|
|
143
|
-
marketplace.get('/templates', async (request, reply) => {
|
|
144
|
-
if (opts.templatesCallback) {
|
|
145
|
-
return opts.templatesCallback(request, reply)
|
|
146
|
-
}
|
|
147
|
-
return [
|
|
148
|
-
{ name: '@platformatic/composer' },
|
|
149
|
-
{ name: '@platformatic/db' },
|
|
150
|
-
{ name: '@platformatic/service' },
|
|
151
|
-
]
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
await marketplace.listen({ port: 0 })
|
|
155
|
-
t.after(() => marketplace.close())
|
|
156
|
-
|
|
157
|
-
const address = marketplace.server.address()
|
|
158
|
-
return `http://127.0.0.1:${address.port}`
|
|
159
|
-
}
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import { safeRemove } from '@platformatic/utils'
|
|
2
|
-
import { equal } from 'node:assert'
|
|
3
|
-
import { mkdtemp } from 'node:fs/promises'
|
|
4
|
-
import { tmpdir } from 'node:os'
|
|
5
|
-
import { join } from 'node:path'
|
|
6
|
-
import { test } from 'node:test'
|
|
7
|
-
import { isFileAccessible } from '../../src/utils.mjs'
|
|
8
|
-
import { executeCreatePlatformatic, getServices, keys, startMarketplace, walk } from './helper.mjs'
|
|
9
|
-
import { timeout } from './timeout.mjs'
|
|
10
|
-
|
|
11
|
-
let tmpDir
|
|
12
|
-
test.beforeEach(async () => {
|
|
13
|
-
tmpDir = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
test.afterEach(async () => {
|
|
17
|
-
try {
|
|
18
|
-
await safeRemove(tmpDir)
|
|
19
|
-
} catch (e) {
|
|
20
|
-
// on purpose, in win the resource might be still "busy"
|
|
21
|
-
}
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
test('Creates a Platformatic Runtime with two Services', { timeout }, async t => {
|
|
25
|
-
const marketplaceHost = await startMarketplace(t)
|
|
26
|
-
// The actions must match IN ORDER
|
|
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.ENTER], // Service
|
|
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.ENTER], // yes
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
match: 'Which kind of project do you want to create?',
|
|
51
|
-
do: [keys.ENTER], // Service
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
match: 'What is the name of the service?',
|
|
55
|
-
do: [keys.ENTER],
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
match: 'Do you want to create another service?',
|
|
59
|
-
do: [keys.DOWN, keys.ENTER], // no
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
match: 'Which service should be exposed?',
|
|
63
|
-
do: [keys.ENTER],
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
match: 'Do you want to use TypeScript',
|
|
67
|
-
do: [keys.DOWN, keys.ENTER], // yes
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
match: 'What port do you want to use?',
|
|
71
|
-
do: [keys.ENTER],
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
match: 'Do you want to init the git repository',
|
|
75
|
-
do: [keys.DOWN, keys.ENTER], // yes
|
|
76
|
-
},
|
|
77
|
-
]
|
|
78
|
-
await executeCreatePlatformatic(tmpDir, actions, {
|
|
79
|
-
marketplaceHost,
|
|
80
|
-
pkgManager: 'pnpm',
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
const baseProjectDir = join(tmpDir, 'platformatic')
|
|
84
|
-
const files = await walk(baseProjectDir)
|
|
85
|
-
console.log('==> created files', files)
|
|
86
|
-
equal(await isFileAccessible(join(baseProjectDir, '.gitignore')), true)
|
|
87
|
-
equal(await isFileAccessible(join(baseProjectDir, '.env')), true)
|
|
88
|
-
equal(await isFileAccessible(join(baseProjectDir, '.env.sample')), true)
|
|
89
|
-
equal(await isFileAccessible(join(baseProjectDir, 'platformatic.json')), true)
|
|
90
|
-
equal(await isFileAccessible(join(baseProjectDir, 'README.md')), true)
|
|
91
|
-
equal(await isFileAccessible(join(baseProjectDir, '.git', 'config')), true)
|
|
92
|
-
|
|
93
|
-
// using pnpm will create workspace file
|
|
94
|
-
equal(await isFileAccessible(join(baseProjectDir, 'pnpm-workspace.yaml')), true)
|
|
95
|
-
|
|
96
|
-
// Here check the generated services
|
|
97
|
-
const services = await getServices(join(baseProjectDir, 'services'))
|
|
98
|
-
equal(services.length, 2)
|
|
99
|
-
const baseService0Dir = join(baseProjectDir, 'services', services[0])
|
|
100
|
-
equal(await isFileAccessible(join(baseService0Dir, 'platformatic.json')), true)
|
|
101
|
-
equal(await isFileAccessible(join(baseService0Dir, 'README.md')), true)
|
|
102
|
-
equal(await isFileAccessible(join(baseService0Dir, 'routes', 'root.ts')), true)
|
|
103
|
-
equal(await isFileAccessible(join(baseService0Dir, 'plugins', 'example.ts')), true)
|
|
104
|
-
equal(await isFileAccessible(join(baseService0Dir, 'global.d.ts')), true)
|
|
105
|
-
|
|
106
|
-
const baseService1Dir = join(baseProjectDir, 'services', services[1])
|
|
107
|
-
equal(await isFileAccessible(join(baseService1Dir, 'platformatic.json')), true)
|
|
108
|
-
equal(await isFileAccessible(join(baseService1Dir, 'README.md')), true)
|
|
109
|
-
equal(await isFileAccessible(join(baseService1Dir, 'routes', 'root.ts')), true)
|
|
110
|
-
equal(await isFileAccessible(join(baseService1Dir, 'plugins', 'example.ts')), true)
|
|
111
|
-
equal(await isFileAccessible(join(baseService1Dir, 'global.d.ts')), true)
|
|
112
|
-
})
|
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
import { createDirectory, safeRemove } from '@platformatic/utils'
|
|
2
|
-
import { equal, notEqual } from 'node:assert'
|
|
3
|
-
import { mkdtemp, readFile, writeFile } from 'node:fs/promises'
|
|
4
|
-
import { join } from 'node:path'
|
|
5
|
-
import { test } from 'node:test'
|
|
6
|
-
import { tmpdir } from 'os'
|
|
7
|
-
import { isFileAccessible } from '../../src/utils.mjs'
|
|
8
|
-
import { executeCreatePlatformatic, getServices, keys, startMarketplace, walk } from './helper.mjs'
|
|
9
|
-
import { timeout } from './timeout.mjs'
|
|
10
|
-
|
|
11
|
-
let tmpDir
|
|
12
|
-
test.beforeEach(async () => {
|
|
13
|
-
tmpDir = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
test.afterEach(async () => {
|
|
17
|
-
try {
|
|
18
|
-
await safeRemove(tmpDir)
|
|
19
|
-
} catch (e) {
|
|
20
|
-
// on purpose, in win the resource might be still "busy"
|
|
21
|
-
}
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
test('Creates a Platformatic Service with no typescript', { timeout }, async t => {
|
|
25
|
-
const marketplaceHost = await startMarketplace(t)
|
|
26
|
-
// The actions must match IN ORDER
|
|
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.ENTER], // Service
|
|
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
|
-
},
|
|
54
|
-
{
|
|
55
|
-
match: 'What port do you want to use?',
|
|
56
|
-
do: [keys.ENTER],
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
match: 'Do you want to init the git repository',
|
|
60
|
-
do: [keys.DOWN, keys.ENTER], // yes
|
|
61
|
-
},
|
|
62
|
-
]
|
|
63
|
-
await executeCreatePlatformatic(tmpDir, actions, { marketplaceHost })
|
|
64
|
-
|
|
65
|
-
const baseProjectDir = join(tmpDir, 'platformatic')
|
|
66
|
-
const files = await walk(baseProjectDir)
|
|
67
|
-
console.log('==> created files', files)
|
|
68
|
-
equal(await isFileAccessible(join(baseProjectDir, '.gitignore')), true)
|
|
69
|
-
equal(await isFileAccessible(join(baseProjectDir, '.env')), true)
|
|
70
|
-
equal(await isFileAccessible(join(baseProjectDir, '.env.sample')), true)
|
|
71
|
-
equal(await isFileAccessible(join(baseProjectDir, 'platformatic.json')), true)
|
|
72
|
-
equal(await isFileAccessible(join(baseProjectDir, 'README.md')), true)
|
|
73
|
-
|
|
74
|
-
// Here check the generated service
|
|
75
|
-
const services = await getServices(join(baseProjectDir, 'services'))
|
|
76
|
-
equal(services.length, 1)
|
|
77
|
-
const baseServiceDir = join(baseProjectDir, 'services', services[0])
|
|
78
|
-
console.log(baseServiceDir)
|
|
79
|
-
equal(await isFileAccessible(join(baseServiceDir, 'platformatic.json')), true)
|
|
80
|
-
equal(await isFileAccessible(join(baseServiceDir, 'README.md')), true)
|
|
81
|
-
equal(await isFileAccessible(join(baseServiceDir, 'routes', 'root.js')), true)
|
|
82
|
-
equal(await isFileAccessible(join(baseServiceDir, 'plugins', 'example.js')), true)
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
test('Creates a Platformatic Service with typescript', { timeout }, async t => {
|
|
86
|
-
const marketplaceHost = await startMarketplace(t)
|
|
87
|
-
// The actions must match IN ORDER
|
|
88
|
-
const actions = [
|
|
89
|
-
{
|
|
90
|
-
match: 'What kind of project do you want to create?',
|
|
91
|
-
do: [keys.ENTER], // Application
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
match: 'Where would you like to create your project?',
|
|
95
|
-
do: [keys.ENTER],
|
|
96
|
-
waitAfter: 8000,
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
match: 'Which kind of project do you want to create?',
|
|
100
|
-
do: [keys.ENTER], // Service
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
match: 'What is the name of the service?',
|
|
104
|
-
do: [keys.ENTER],
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
match: 'Do you want to create another service?',
|
|
108
|
-
do: [keys.DOWN, keys.ENTER], // no
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
// NOTE THAT HERE THE DEFAULT OPTION FOR SERVICE IS "YES"
|
|
112
|
-
match: 'Do you want to use TypeScript',
|
|
113
|
-
do: [keys.DOWN, keys.ENTER], // no
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
match: 'What port do you want to use?',
|
|
117
|
-
do: [keys.ENTER],
|
|
118
|
-
},
|
|
119
|
-
{
|
|
120
|
-
match: 'Do you want to init the git repository',
|
|
121
|
-
do: [keys.DOWN, keys.ENTER], // yes
|
|
122
|
-
},
|
|
123
|
-
]
|
|
124
|
-
await executeCreatePlatformatic(tmpDir, actions, { marketplaceHost })
|
|
125
|
-
|
|
126
|
-
const baseProjectDir = join(tmpDir, 'platformatic')
|
|
127
|
-
const files = await walk(baseProjectDir)
|
|
128
|
-
console.log('==> created files', files)
|
|
129
|
-
equal(await isFileAccessible(join(baseProjectDir, '.gitignore')), true)
|
|
130
|
-
equal(await isFileAccessible(join(baseProjectDir, '.env')), true)
|
|
131
|
-
equal(await isFileAccessible(join(baseProjectDir, '.env.sample')), true)
|
|
132
|
-
equal(await isFileAccessible(join(baseProjectDir, 'platformatic.json')), true)
|
|
133
|
-
equal(await isFileAccessible(join(baseProjectDir, 'README.md')), true)
|
|
134
|
-
|
|
135
|
-
// Here check the generated service
|
|
136
|
-
const services = await getServices(join(baseProjectDir, 'services'))
|
|
137
|
-
equal(services.length, 1)
|
|
138
|
-
const baseServiceDir = join(baseProjectDir, 'services', services[0])
|
|
139
|
-
console.log(baseServiceDir)
|
|
140
|
-
equal(await isFileAccessible(join(baseServiceDir, 'platformatic.json')), true)
|
|
141
|
-
equal(await isFileAccessible(join(baseServiceDir, 'README.md')), true)
|
|
142
|
-
equal(await isFileAccessible(join(baseServiceDir, 'routes', 'root.ts')), true)
|
|
143
|
-
equal(await isFileAccessible(join(baseServiceDir, 'plugins', 'example.ts')), true)
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
test('Creates a Platformatic Service in a non empty directory', { timeout, skip: true }, async t => {
|
|
147
|
-
const marketplaceHost = await startMarketplace(t)
|
|
148
|
-
const targetDirectory = join(tmpdir(), 'platformatic-service-test')
|
|
149
|
-
// const targetDirectory = '/tmp/tst'
|
|
150
|
-
async function generateServiceFileStructure (dir) {
|
|
151
|
-
const servicesDir = join(dir, 'services')
|
|
152
|
-
await createDirectory(servicesDir)
|
|
153
|
-
|
|
154
|
-
const serviceDir = join(servicesDir, 'foo')
|
|
155
|
-
await createDirectory(join(serviceDir, 'plugins'))
|
|
156
|
-
await createDirectory(join(serviceDir, 'routes'))
|
|
157
|
-
|
|
158
|
-
await writeFile(join(dir, '.env'), 'SAMPLE_ENV=foobar\n')
|
|
159
|
-
|
|
160
|
-
// creates 2 files. root.js will be overwritten
|
|
161
|
-
await writeFile(join(serviceDir, 'routes', 'root.js'), "console.log('hello world')")
|
|
162
|
-
await writeFile(join(serviceDir, 'routes', 'sample.js'), "console.log('hello world')")
|
|
163
|
-
}
|
|
164
|
-
// generate a sample file structure
|
|
165
|
-
await generateServiceFileStructure(targetDirectory)
|
|
166
|
-
|
|
167
|
-
test.after(async () => {
|
|
168
|
-
await safeRemove(targetDirectory)
|
|
169
|
-
})
|
|
170
|
-
// The actions must match IN ORDER
|
|
171
|
-
const actions = [
|
|
172
|
-
{
|
|
173
|
-
match: 'What kind of project do you want to create?',
|
|
174
|
-
do: [keys.ENTER], // Application
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
match: 'Where would you like to create your project?',
|
|
178
|
-
do: [targetDirectory, keys.ENTER],
|
|
179
|
-
waitAfter: 8000,
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
match: 'Confirm you want to use',
|
|
183
|
-
do: [keys.ENTER], // confirm use existing directory
|
|
184
|
-
},
|
|
185
|
-
{
|
|
186
|
-
// NOTE THAT HERE THE DEFAULT OPTION FOR SERVICE IS "YES"
|
|
187
|
-
match: 'Do you want to use TypeScript',
|
|
188
|
-
do: [keys.DOWN, keys.ENTER], // no
|
|
189
|
-
},
|
|
190
|
-
{
|
|
191
|
-
match: 'What port do you want to use?',
|
|
192
|
-
do: [keys.ENTER],
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
match: 'Do you want to create the github action to deploy',
|
|
196
|
-
do: [keys.DOWN, keys.ENTER],
|
|
197
|
-
},
|
|
198
|
-
{
|
|
199
|
-
match: 'Do you want to enable PR Previews in your application',
|
|
200
|
-
do: [keys.DOWN, keys.ENTER],
|
|
201
|
-
},
|
|
202
|
-
{
|
|
203
|
-
match: 'Do you want to init the git repository',
|
|
204
|
-
do: [keys.DOWN, keys.ENTER], // yes
|
|
205
|
-
},
|
|
206
|
-
]
|
|
207
|
-
await executeCreatePlatformatic(tmpDir, actions, { marketplaceHost })
|
|
208
|
-
|
|
209
|
-
equal(await isFileAccessible(join(targetDirectory, '.gitignore')), true)
|
|
210
|
-
equal(await isFileAccessible(join(targetDirectory, '.env')), true)
|
|
211
|
-
equal(await isFileAccessible(join(targetDirectory, '.env.sample')), true)
|
|
212
|
-
equal(await isFileAccessible(join(targetDirectory, 'platformatic.service.json')), true)
|
|
213
|
-
equal(await isFileAccessible(join(targetDirectory, 'README.md')), true)
|
|
214
|
-
equal(await isFileAccessible(join(targetDirectory, 'routes', 'root.js')), true)
|
|
215
|
-
equal(await isFileAccessible(join(targetDirectory, 'routes', 'sample.js')), true)
|
|
216
|
-
equal(await isFileAccessible(join(targetDirectory, 'plugins', 'example.js')), true)
|
|
217
|
-
equal(await isFileAccessible(join(targetDirectory, '.git', 'config')), true)
|
|
218
|
-
|
|
219
|
-
// check file contents
|
|
220
|
-
notEqual(await readFile(join(targetDirectory, 'routes', 'root.js'), 'utf8'), "console.log('hello world')")
|
|
221
|
-
equal(await readFile(join(targetDirectory, 'routes', 'sample.js'), 'utf8'), "console.log('hello world')")
|
|
222
|
-
})
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import { safeRemove } from '@platformatic/utils'
|
|
2
|
-
import { equal } from 'node:assert'
|
|
3
|
-
import { mkdtemp } from 'node:fs/promises'
|
|
4
|
-
import { join } from 'node:path'
|
|
5
|
-
import { test } from 'node:test'
|
|
6
|
-
import { tmpdir } from 'os'
|
|
7
|
-
import { isFileAccessible } from '../../src/utils.mjs'
|
|
8
|
-
import { executeCreatePlatformatic, keys, walk } from './helper.mjs'
|
|
9
|
-
import { timeout } from './timeout.mjs'
|
|
10
|
-
|
|
11
|
-
let tmpDir
|
|
12
|
-
test.beforeEach(async () => {
|
|
13
|
-
tmpDir = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
test.afterEach(async () => {
|
|
17
|
-
try {
|
|
18
|
-
await safeRemove(tmpDir)
|
|
19
|
-
} catch (e) {
|
|
20
|
-
// on purpose, in win the resource might be still "busy"
|
|
21
|
-
}
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
test('Creates a Platformatic Stackable without typescript', { timeout }, async () => {
|
|
25
|
-
// The actions must match IN ORDER
|
|
26
|
-
const actions = [
|
|
27
|
-
{
|
|
28
|
-
match: 'What kind of project do you want to create?',
|
|
29
|
-
do: [keys.DOWN, keys.ENTER], // Stackable
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
match: 'Where would you like to create your project?',
|
|
33
|
-
do: [keys.ENTER],
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
match: 'What is the name of the stackable?',
|
|
37
|
-
do: [keys.ENTER], // my-stackable
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
match: 'Do you want to use TypeScript',
|
|
41
|
-
do: [keys.ENTER], // no
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
match: 'Do you want to init the git repository',
|
|
45
|
-
do: [keys.DOWN, keys.ENTER], // yes
|
|
46
|
-
},
|
|
47
|
-
]
|
|
48
|
-
await executeCreatePlatformatic(tmpDir, actions, {
|
|
49
|
-
done: 'Stackable created successfully!',
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
const baseProjectDir = join(tmpDir, 'platformatic')
|
|
53
|
-
const files = await walk(baseProjectDir)
|
|
54
|
-
console.log('==> created files', files)
|
|
55
|
-
equal(await isFileAccessible(join(baseProjectDir, '.gitignore')), true)
|
|
56
|
-
equal(await isFileAccessible(join(baseProjectDir, 'index.js')), true)
|
|
57
|
-
equal(await isFileAccessible(join(baseProjectDir, 'index.d.ts')), true)
|
|
58
|
-
equal(await isFileAccessible(join(baseProjectDir, 'config.d.ts')), true)
|
|
59
|
-
equal(await isFileAccessible(join(baseProjectDir, 'package.json')), true)
|
|
60
|
-
equal(await isFileAccessible(join(baseProjectDir, 'plugins', 'example.js')), true)
|
|
61
|
-
equal(await isFileAccessible(join(baseProjectDir, 'lib', 'schema.js')), true)
|
|
62
|
-
equal(await isFileAccessible(join(baseProjectDir, 'lib', 'generator.js')), true)
|
|
63
|
-
equal(await isFileAccessible(join(baseProjectDir, 'cli', 'create.js')), true)
|
|
64
|
-
equal(await isFileAccessible(join(baseProjectDir, 'cli', 'start.js')), true)
|
|
65
|
-
equal(await isFileAccessible(join(baseProjectDir, 'test', 'index.test.js')), true)
|
|
66
|
-
equal(await isFileAccessible(join(baseProjectDir, 'test', 'schema.test.js')), true)
|
|
67
|
-
equal(await isFileAccessible(join(baseProjectDir, 'test', 'generator.test.js')), true)
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
test('Creates a Platformatic Stackable with typescript', { timeout }, async () => {
|
|
71
|
-
// The actions must match IN ORDER
|
|
72
|
-
const actions = [
|
|
73
|
-
{
|
|
74
|
-
match: 'What kind of project do you want to create?',
|
|
75
|
-
do: [keys.DOWN, keys.ENTER], // Stackable
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
match: 'Where would you like to create your project?',
|
|
79
|
-
do: [keys.ENTER],
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
match: 'What is the name of the stackable?',
|
|
83
|
-
do: [keys.ENTER], // my-stackable
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
match: 'Do you want to use TypeScript',
|
|
87
|
-
do: [keys.DOWN, keys.ENTER], // yes
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
match: 'Do you want to init the git repository',
|
|
91
|
-
do: [keys.ENTER], // no
|
|
92
|
-
},
|
|
93
|
-
]
|
|
94
|
-
await executeCreatePlatformatic(tmpDir, actions, {
|
|
95
|
-
done: 'Stackable created successfully!',
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
const baseProjectDir = join(tmpDir, 'platformatic')
|
|
99
|
-
const files = await walk(baseProjectDir)
|
|
100
|
-
console.log('==> created files', files)
|
|
101
|
-
equal(await isFileAccessible(join(baseProjectDir, '.gitignore')), true)
|
|
102
|
-
equal(await isFileAccessible(join(baseProjectDir, 'index.ts')), true)
|
|
103
|
-
equal(await isFileAccessible(join(baseProjectDir, 'index.d.ts')), true)
|
|
104
|
-
equal(await isFileAccessible(join(baseProjectDir, 'config.d.ts')), true)
|
|
105
|
-
equal(await isFileAccessible(join(baseProjectDir, 'package.json')), true)
|
|
106
|
-
equal(await isFileAccessible(join(baseProjectDir, 'plugins', 'example.ts')), true)
|
|
107
|
-
equal(await isFileAccessible(join(baseProjectDir, 'lib', 'schema.ts')), true)
|
|
108
|
-
equal(await isFileAccessible(join(baseProjectDir, 'lib', 'generator.ts')), true)
|
|
109
|
-
equal(await isFileAccessible(join(baseProjectDir, 'cli', 'create.ts')), true)
|
|
110
|
-
equal(await isFileAccessible(join(baseProjectDir, 'cli', 'start.ts')), true)
|
|
111
|
-
equal(await isFileAccessible(join(baseProjectDir, 'test', 'index.test.ts')), true)
|
|
112
|
-
equal(await isFileAccessible(join(baseProjectDir, 'test', 'schema.test.ts')), true)
|
|
113
|
-
equal(await isFileAccessible(join(baseProjectDir, 'test', 'generator.test.ts')), true)
|
|
114
|
-
})
|
package/test/cli/timeout.mjs
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { execa } from 'execa'
|
|
2
|
-
import { equal, match } from 'node:assert'
|
|
3
|
-
import { test } from 'node:test'
|
|
4
|
-
import { tmpdir } from 'os'
|
|
5
|
-
import { join } from 'path'
|
|
6
|
-
|
|
7
|
-
import { createDirectory } from '@platformatic/utils'
|
|
8
|
-
import { writeFile } from 'fs/promises'
|
|
9
|
-
import { createGitRepository, GIT_FIRST_COMMIT_MESSAGE, GIT_MAIN_BRANCH } from '../../src/create-git-repository.mjs'
|
|
10
|
-
import { isFileAccessible } from '../../src/utils.mjs'
|
|
11
|
-
|
|
12
|
-
const loggerSpy = {
|
|
13
|
-
_debug: [],
|
|
14
|
-
_info: [],
|
|
15
|
-
_error: [],
|
|
16
|
-
|
|
17
|
-
debug: function (...args) {
|
|
18
|
-
this._debug.push(args)
|
|
19
|
-
},
|
|
20
|
-
info: function (...args) {
|
|
21
|
-
this._info.push(args)
|
|
22
|
-
},
|
|
23
|
-
error: function (...args) {
|
|
24
|
-
this._error.push(args)
|
|
25
|
-
},
|
|
26
|
-
|
|
27
|
-
reset: function () {
|
|
28
|
-
this._debug = []
|
|
29
|
-
this._info = []
|
|
30
|
-
this._error = []
|
|
31
|
-
},
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const tmpDir = join(tmpdir(), 'test-create-platformatic-git-repo')
|
|
35
|
-
test.beforeEach(async () => {
|
|
36
|
-
loggerSpy.reset()
|
|
37
|
-
await createDirectory(tmpDir, true)
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
test('should create the git repo', async () => {
|
|
41
|
-
await writeFile(join(tmpDir, 'README.md'), '')
|
|
42
|
-
|
|
43
|
-
await createGitRepository(loggerSpy, tmpDir)
|
|
44
|
-
|
|
45
|
-
equal(loggerSpy._debug[0][0], 'Git repository initialized.')
|
|
46
|
-
equal(loggerSpy._debug[1][0], 'Git commit done.')
|
|
47
|
-
equal(loggerSpy._info[0][0], 'Git repository initialized.')
|
|
48
|
-
equal(loggerSpy._error.length, 0)
|
|
49
|
-
|
|
50
|
-
equal(await isFileAccessible(join(tmpDir, '.git/config')), true)
|
|
51
|
-
|
|
52
|
-
const lastCommit = await execa('git', ['show', '-1'], { cwd: tmpDir })
|
|
53
|
-
match(lastCommit.stdout, new RegExp(GIT_FIRST_COMMIT_MESSAGE))
|
|
54
|
-
|
|
55
|
-
const branch = await execa('git', ['branch'], { cwd: tmpDir })
|
|
56
|
-
match(branch.stdout, new RegExp(GIT_MAIN_BRANCH))
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
test('should not create the git repository if already exists', async () => {
|
|
60
|
-
await execa('git', ['init'], { cwd: tmpDir })
|
|
61
|
-
|
|
62
|
-
await createGitRepository(loggerSpy, tmpDir)
|
|
63
|
-
|
|
64
|
-
equal(loggerSpy._debug.length, 0)
|
|
65
|
-
equal(loggerSpy._info[0][0], 'Git repository already exists.')
|
|
66
|
-
equal(loggerSpy._error.length, 0)
|
|
67
|
-
})
|
|
@@ -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,293 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
import { safeRemove } from '@platformatic/utils'
|
|
4
|
-
import esmock from 'esmock'
|
|
5
|
-
import { mkdtemp, writeFile } from 'fs/promises'
|
|
6
|
-
import { deepEqual, equal, notEqual } from 'node:assert'
|
|
7
|
-
import { test } from 'node:test'
|
|
8
|
-
import { tmpdir } from 'os'
|
|
9
|
-
import { join } from 'path'
|
|
10
|
-
import semver from 'semver'
|
|
11
|
-
import {
|
|
12
|
-
addPrefixToEnv,
|
|
13
|
-
convertServiceNameToPrefix,
|
|
14
|
-
findComposerConfigFile,
|
|
15
|
-
findDBConfigFile,
|
|
16
|
-
findRuntimeConfigFile,
|
|
17
|
-
findServiceConfigFile,
|
|
18
|
-
getDependencyVersion,
|
|
19
|
-
isCurrentVersionSupported,
|
|
20
|
-
isFileAccessible,
|
|
21
|
-
minimumSupportedNodeVersions,
|
|
22
|
-
randomBetween,
|
|
23
|
-
sleep,
|
|
24
|
-
} from '../../src/utils.mjs'
|
|
25
|
-
|
|
26
|
-
test('getUsername from git', async () => {
|
|
27
|
-
const name = 'lukeskywalker'
|
|
28
|
-
const { getUsername } = await esmock.strict('../../src/utils.mjs', {
|
|
29
|
-
execa: {
|
|
30
|
-
execa: command => {
|
|
31
|
-
if (command === 'git') {
|
|
32
|
-
return { stdout: name }
|
|
33
|
-
}
|
|
34
|
-
return ''
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
})
|
|
38
|
-
const username = await getUsername()
|
|
39
|
-
equal(username, name)
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
test('getUsername from whoami', async () => {
|
|
43
|
-
const name = 'hansolo'
|
|
44
|
-
const { getUsername } = await esmock.strict('../../src/utils.mjs', {
|
|
45
|
-
execa: {
|
|
46
|
-
execa: command => {
|
|
47
|
-
if (command === 'whoami') {
|
|
48
|
-
return { stdout: name }
|
|
49
|
-
}
|
|
50
|
-
return ''
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
})
|
|
54
|
-
const username = await getUsername()
|
|
55
|
-
equal(username, name)
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
test('if getUsername from git failed, it tries whoim', async () => {
|
|
59
|
-
const name = 'lukeskywalker'
|
|
60
|
-
|
|
61
|
-
const { getUsername } = await esmock.strict('../../src/utils.mjs', {
|
|
62
|
-
execa: {
|
|
63
|
-
execa: command => {
|
|
64
|
-
if (command === 'git') {
|
|
65
|
-
throw new Error('git failed')
|
|
66
|
-
}
|
|
67
|
-
if (command === 'whoami') {
|
|
68
|
-
return { stdout: name }
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return ''
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
})
|
|
75
|
-
const username = await getUsername()
|
|
76
|
-
equal(username, name)
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
test('if both git usern.ame and whoami fail, no username is set', async () => {
|
|
80
|
-
const { getUsername } = await esmock.strict('../../src/utils.mjs', {
|
|
81
|
-
execa: {
|
|
82
|
-
execa: command => {
|
|
83
|
-
if (command === 'git') {
|
|
84
|
-
throw new Error('git failed')
|
|
85
|
-
}
|
|
86
|
-
if (command === 'whoami') {
|
|
87
|
-
throw new Error('whoami failed')
|
|
88
|
-
}
|
|
89
|
-
return ''
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
})
|
|
93
|
-
const username = await getUsername()
|
|
94
|
-
equal(username, null)
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
test('getUsername - no username found', async () => {
|
|
98
|
-
const { getUsername } = await esmock.strict('../../src/utils.mjs', {
|
|
99
|
-
execa: {
|
|
100
|
-
execa: command => {
|
|
101
|
-
return ''
|
|
102
|
-
},
|
|
103
|
-
},
|
|
104
|
-
})
|
|
105
|
-
const username = await getUsername()
|
|
106
|
-
equal(username, null)
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
test('randomBetween', async () => {
|
|
110
|
-
const min = 1
|
|
111
|
-
const max = 10
|
|
112
|
-
const random = randomBetween(min, max)
|
|
113
|
-
equal(random >= min && random <= max, true)
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
test('sleep', async () => {
|
|
117
|
-
const start = Date.now()
|
|
118
|
-
await sleep(100)
|
|
119
|
-
const end = Date.now()
|
|
120
|
-
// We cannot assert the exact drift because timers
|
|
121
|
-
// are imprecise
|
|
122
|
-
equal(end - start >= 90, true)
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
test('getDependencyVersion', async () => {
|
|
126
|
-
const fastifyVersion = await getDependencyVersion('fastify')
|
|
127
|
-
// We cannot assert the exact version because it changes
|
|
128
|
-
equal(semver.valid(fastifyVersion), fastifyVersion)
|
|
129
|
-
equal(semver.gt(fastifyVersion, '4.10.0'), true)
|
|
130
|
-
|
|
131
|
-
const typescriptVersion = await getDependencyVersion('typescript')
|
|
132
|
-
// We cannot assert the exact version because it changes
|
|
133
|
-
equal(semver.valid(typescriptVersion), typescriptVersion)
|
|
134
|
-
equal(semver.gt(typescriptVersion, '5.0.0'), true)
|
|
135
|
-
|
|
136
|
-
const platformaticConfig = await getDependencyVersion('@platformatic/config')
|
|
137
|
-
// We cannot assert the exact version because it changes
|
|
138
|
-
equal(semver.valid(platformaticConfig), platformaticConfig)
|
|
139
|
-
equal(semver.gt(platformaticConfig, '1.0.0'), true)
|
|
140
|
-
|
|
141
|
-
const typesVersion = await getDependencyVersion('@types/node')
|
|
142
|
-
// We cannot assert the exact version because it changes
|
|
143
|
-
equal(semver.valid(typesVersion), typesVersion)
|
|
144
|
-
equal(semver.gt(typesVersion, '20.0.0'), true)
|
|
145
|
-
|
|
146
|
-
const unkownVersion = await getDependencyVersion('@types/npm')
|
|
147
|
-
equal(unkownVersion, undefined)
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
test('findDBConfigFile', async () => {
|
|
151
|
-
const tmpDir1 = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
152
|
-
const tmpDir2 = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
153
|
-
const config = join(tmpDir1, 'platformatic.db.yml')
|
|
154
|
-
await writeFile(config, 'TEST')
|
|
155
|
-
equal(await findDBConfigFile(tmpDir1), 'platformatic.db.yml')
|
|
156
|
-
equal(await findDBConfigFile(tmpDir2), undefined)
|
|
157
|
-
await safeRemove(tmpDir1)
|
|
158
|
-
await safeRemove(tmpDir2)
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
test('findServiceConfigFile', async () => {
|
|
162
|
-
const tmpDir1 = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
163
|
-
const tmpDir2 = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
164
|
-
const config = join(tmpDir1, 'platformatic.service.toml')
|
|
165
|
-
await writeFile(config, 'TEST')
|
|
166
|
-
equal(await findServiceConfigFile(tmpDir1), 'platformatic.service.toml')
|
|
167
|
-
equal(await findServiceConfigFile(tmpDir2), undefined)
|
|
168
|
-
await safeRemove(tmpDir1)
|
|
169
|
-
await safeRemove(tmpDir2)
|
|
170
|
-
})
|
|
171
|
-
|
|
172
|
-
test('findComposerConfigFile', async () => {
|
|
173
|
-
const tmpDir1 = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
174
|
-
const tmpDir2 = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
175
|
-
const config = join(tmpDir1, 'platformatic.composer.yml')
|
|
176
|
-
await writeFile(config, 'TEST')
|
|
177
|
-
equal(await findComposerConfigFile(tmpDir1), 'platformatic.composer.yml')
|
|
178
|
-
equal(await findComposerConfigFile(tmpDir2), undefined)
|
|
179
|
-
await safeRemove(tmpDir1)
|
|
180
|
-
await safeRemove(tmpDir2)
|
|
181
|
-
})
|
|
182
|
-
|
|
183
|
-
test('findRuntimeConfigFile', async () => {
|
|
184
|
-
const tmpDir1 = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
185
|
-
const tmpDir2 = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
186
|
-
const config = join(tmpDir1, 'platformatic.runtime.yml')
|
|
187
|
-
await writeFile(config, 'TEST')
|
|
188
|
-
equal(await findRuntimeConfigFile(tmpDir1), 'platformatic.runtime.yml')
|
|
189
|
-
equal(await findRuntimeConfigFile(tmpDir2), undefined)
|
|
190
|
-
await safeRemove(tmpDir1)
|
|
191
|
-
await safeRemove(tmpDir2)
|
|
192
|
-
})
|
|
193
|
-
|
|
194
|
-
test('isFileAccessible', async () => {
|
|
195
|
-
const tmpDir1 = await mkdtemp(join(tmpdir(), 'test-create-platformatic-'))
|
|
196
|
-
const config = join(tmpDir1, 'platformatic.db.yml')
|
|
197
|
-
await writeFile(config, 'TEST')
|
|
198
|
-
equal(await isFileAccessible(config), true)
|
|
199
|
-
const config2 = join(tmpDir1, 'platformatic2.db.yml')
|
|
200
|
-
equal(await isFileAccessible(config2), false)
|
|
201
|
-
await safeRemove(tmpDir1)
|
|
202
|
-
})
|
|
203
|
-
|
|
204
|
-
test('minimumSupportedNodeVersions', async () => {
|
|
205
|
-
equal(Array.isArray(minimumSupportedNodeVersions), true)
|
|
206
|
-
notEqual(minimumSupportedNodeVersions.length, 0)
|
|
207
|
-
})
|
|
208
|
-
|
|
209
|
-
test('isCurrentVersionSupported', async () => {
|
|
210
|
-
const { major, minor, patch } = semver.minVersion(minimumSupportedNodeVersions[0])
|
|
211
|
-
{
|
|
212
|
-
// major - 1 not supported
|
|
213
|
-
const nodeVersion = `${major - 1}.${minor}.${patch}`
|
|
214
|
-
const supported = isCurrentVersionSupported(nodeVersion)
|
|
215
|
-
equal(supported, false)
|
|
216
|
-
}
|
|
217
|
-
{
|
|
218
|
-
// minor - 1 not supported
|
|
219
|
-
const nodeVersion = `${major}.${minor - 1}.${patch}`
|
|
220
|
-
const supported = isCurrentVersionSupported(nodeVersion)
|
|
221
|
-
equal(supported, false)
|
|
222
|
-
}
|
|
223
|
-
{
|
|
224
|
-
// v16 more than minimum is supported
|
|
225
|
-
const supported = isCurrentVersionSupported(`${major}.${minor + 2}.${patch}`)
|
|
226
|
-
equal(supported, true)
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// node version 20 test, to check greater and lesser major version
|
|
230
|
-
{
|
|
231
|
-
// v18.0.0 is not supported
|
|
232
|
-
const nodeVersion = '18.0.0'
|
|
233
|
-
const supported = isCurrentVersionSupported(nodeVersion)
|
|
234
|
-
equal(supported, false)
|
|
235
|
-
}
|
|
236
|
-
{
|
|
237
|
-
// v18.8.0 is supported
|
|
238
|
-
const nodeVersion = '18.8.0'
|
|
239
|
-
const supported = isCurrentVersionSupported(nodeVersion)
|
|
240
|
-
equal(supported, true)
|
|
241
|
-
}
|
|
242
|
-
{
|
|
243
|
-
// v20.5.1 is not supported
|
|
244
|
-
const supported = isCurrentVersionSupported('20.5.1')
|
|
245
|
-
equal(supported, false)
|
|
246
|
-
}
|
|
247
|
-
{
|
|
248
|
-
// v20.6.0 is supported
|
|
249
|
-
const nodeVersion = '20.6.0'
|
|
250
|
-
const supported = isCurrentVersionSupported(nodeVersion)
|
|
251
|
-
equal(supported, true)
|
|
252
|
-
}
|
|
253
|
-
{
|
|
254
|
-
// v19.0.0 is not supported
|
|
255
|
-
const supported = isCurrentVersionSupported('19.0.0')
|
|
256
|
-
equal(supported, false)
|
|
257
|
-
}
|
|
258
|
-
{
|
|
259
|
-
// v19.9.0 is not supported
|
|
260
|
-
const supported = isCurrentVersionSupported('19.9.0')
|
|
261
|
-
equal(supported, false)
|
|
262
|
-
}
|
|
263
|
-
for (const version of minimumSupportedNodeVersions) {
|
|
264
|
-
const supported = isCurrentVersionSupported(version)
|
|
265
|
-
equal(supported, true)
|
|
266
|
-
}
|
|
267
|
-
})
|
|
268
|
-
|
|
269
|
-
test('should convert service name to env prefix', async () => {
|
|
270
|
-
const expectations = {
|
|
271
|
-
'my-service': 'MY_SERVICE',
|
|
272
|
-
a: 'A',
|
|
273
|
-
MY_SERVICE: 'MY_SERVICE',
|
|
274
|
-
asderas123: 'ASDERAS123',
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
Object.entries(expectations).forEach(exp => {
|
|
278
|
-
const converted = convertServiceNameToPrefix(exp[0])
|
|
279
|
-
equal(exp[1], converted)
|
|
280
|
-
})
|
|
281
|
-
})
|
|
282
|
-
|
|
283
|
-
test('should add prefix to a key/value object', async () => {
|
|
284
|
-
const prefix = 'MY_PREFIX'
|
|
285
|
-
const env = {
|
|
286
|
-
PLT_HOSTNAME: 'myhost',
|
|
287
|
-
PORT: '3042',
|
|
288
|
-
}
|
|
289
|
-
deepEqual(addPrefixToEnv(env, prefix), {
|
|
290
|
-
MY_PREFIX_PLT_HOSTNAME: 'myhost',
|
|
291
|
-
MY_PREFIX_PORT: '3042',
|
|
292
|
-
})
|
|
293
|
-
})
|