create-platformatic 0.24.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +12 -11
- package/src/{ask-project-dir.mjs → ask-dir.mjs} +2 -2
- package/src/cli-options.mjs +14 -0
- package/src/composer/README.md +30 -0
- package/src/composer/create-composer-cli.mjs +107 -0
- package/src/composer/create-composer.mjs +76 -0
- package/src/db/create-db-cli.mjs +43 -22
- package/src/ghaction.mjs +15 -40
- package/src/index.mjs +58 -14
- package/src/runtime/README.md +32 -0
- package/src/runtime/create-runtime-cli.mjs +155 -0
- package/src/runtime/create-runtime.mjs +40 -0
- package/src/service/create-service-cli.mjs +28 -22
- package/src/service/create-service.mjs +3 -0
- package/src/utils.mjs +2 -0
- package/test/cli-options.test.mjs +43 -1
- package/test/composer/create-composer.test.mjs +75 -0
- package/test/ghaction-dynamic.test.mjs +12 -28
- package/test/ghaction-static.test.mjs +12 -28
- package/test/runtime/create-runtime.test.mjs +70 -0
- package/test/utils.test.mjs +23 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-platformatic",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"description": "Create platformatic-db interactive tool",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"license": "Apache-2.0",
|
|
16
16
|
"author": "Marco Piraccini <marco.piraccini@gmail.com>",
|
|
17
17
|
"dependencies": {
|
|
18
|
+
"boring-name-generator": "^1.0.3",
|
|
18
19
|
"chalk": "^5.2.0",
|
|
19
20
|
"commist": "^3.2.0",
|
|
20
21
|
"desm": "^1.3.0",
|
|
@@ -22,30 +23,30 @@
|
|
|
22
23
|
"execa": "^7.1.1",
|
|
23
24
|
"fastify": "^4.17.0",
|
|
24
25
|
"help-me": "^4.2.0",
|
|
25
|
-
"inquirer": "^9.2.
|
|
26
|
+
"inquirer": "^9.2.6",
|
|
26
27
|
"log-update": "^5.0.1",
|
|
27
28
|
"minimist": "^1.2.8",
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"pino": "^8.12.0",
|
|
29
|
+
"ora": "^6.3.1",
|
|
30
|
+
"pino": "^8.14.1",
|
|
31
31
|
"pino-pretty": "^10.0.0",
|
|
32
32
|
"pupa": "^3.1.0",
|
|
33
|
-
"semver": "^7.5.
|
|
34
|
-
"undici": "^5.22.
|
|
35
|
-
"
|
|
33
|
+
"semver": "^7.5.1",
|
|
34
|
+
"undici": "^5.22.1",
|
|
35
|
+
"which": "^3.0.1",
|
|
36
|
+
"@platformatic/config": "0.26.0"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
38
39
|
"ajv": "^8.12.0",
|
|
39
40
|
"c8": "^7.13.0",
|
|
40
41
|
"cross-env": "^7.0.3",
|
|
41
42
|
"dotenv": "^16.0.3",
|
|
42
|
-
"esmock": "^2.2.
|
|
43
|
+
"esmock": "^2.2.3",
|
|
43
44
|
"snazzy": "^9.0.0",
|
|
44
45
|
"standard": "^17.0.0",
|
|
45
46
|
"tap": "^16.3.4",
|
|
46
47
|
"yaml": "^2.2.2",
|
|
47
|
-
"@platformatic/db": "0.
|
|
48
|
-
"@platformatic/service": "0.
|
|
48
|
+
"@platformatic/db": "0.26.0",
|
|
49
|
+
"@platformatic/service": "0.26.0"
|
|
49
50
|
},
|
|
50
51
|
"scripts": {
|
|
51
52
|
"test": "standard | snazzy && cross-env NODE_OPTIONS=\"--loader=esmock --no-warnings\" c8 --100 tap --no-coverage test/*test.mjs test/*/*test.mjs",
|
|
@@ -2,11 +2,11 @@ import { validatePath } from './utils.mjs'
|
|
|
2
2
|
import inquirer from 'inquirer'
|
|
3
3
|
import { resolve } from 'path'
|
|
4
4
|
|
|
5
|
-
const askProjectDir = async (logger, defaultName) => {
|
|
5
|
+
const askProjectDir = async (logger, defaultName, message = 'Where would you like to create your project?') => {
|
|
6
6
|
const options = await inquirer.prompt({
|
|
7
7
|
type: 'input',
|
|
8
8
|
name: 'dir',
|
|
9
|
-
message
|
|
9
|
+
message,
|
|
10
10
|
default: defaultName,
|
|
11
11
|
validate: validatePath
|
|
12
12
|
})
|
package/src/cli-options.mjs
CHANGED
|
@@ -18,3 +18,17 @@ export const getUseTypescript = typescript => {
|
|
|
18
18
|
choices: [{ name: 'yes', value: true }, { name: 'no', value: false }]
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
+
|
|
22
|
+
let port = 3042
|
|
23
|
+
export const getPort = (nextPort) => {
|
|
24
|
+
if (nextPort === undefined) {
|
|
25
|
+
nextPort = port++
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
type: 'input',
|
|
30
|
+
name: 'port',
|
|
31
|
+
message: 'What port do you want to use?',
|
|
32
|
+
default: nextPort
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Platformatic Composer API
|
|
2
|
+
|
|
3
|
+
This is a generated [Platformatic Composer](https://oss.platformatic.dev/docs/reference/composer/introduction) application.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
Platformatic supports macOS, Linux and Windows ([WSL](https://docs.microsoft.com/windows/wsl/) recommended).
|
|
8
|
+
You'll need to have [Node.js](https://nodejs.org/) >= v18.8.0
|
|
9
|
+
|
|
10
|
+
## Setup
|
|
11
|
+
|
|
12
|
+
1. Install dependencies:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
Run the API with:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm start
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Explore
|
|
27
|
+
- ⚡ The Platformatic Composer server is running at http://localhost:3042/
|
|
28
|
+
- 📔 View the REST API's Swagger documentation at http://localhost:3042/documentation/
|
|
29
|
+
|
|
30
|
+
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { getVersion, getDependencyVersion, isFileAccessible } from '../utils.mjs'
|
|
2
|
+
import { createPackageJson } from '../create-package-json.mjs'
|
|
3
|
+
import { createGitignore } from '../create-gitignore.mjs'
|
|
4
|
+
import { getPkgManager } from '../get-pkg-manager.mjs'
|
|
5
|
+
import parseArgs from 'minimist'
|
|
6
|
+
import { join } from 'path'
|
|
7
|
+
import inquirer from 'inquirer'
|
|
8
|
+
import { readFile, writeFile, mkdir } from 'fs/promises'
|
|
9
|
+
import pino from 'pino'
|
|
10
|
+
import pretty from 'pino-pretty'
|
|
11
|
+
import { execa } from 'execa'
|
|
12
|
+
import ora from 'ora'
|
|
13
|
+
import createComposer from './create-composer.mjs'
|
|
14
|
+
import askDir from '../ask-dir.mjs'
|
|
15
|
+
import { askDynamicWorkspaceCreateGHAction, askStaticWorkspaceGHAction } from '../ghaction.mjs'
|
|
16
|
+
import { getRunPackageManagerInstall, getPort } from '../cli-options.mjs'
|
|
17
|
+
|
|
18
|
+
export const createReadme = async (logger, dir = '.') => {
|
|
19
|
+
const readmeFileName = join(dir, 'README.md')
|
|
20
|
+
let isReadmeExists = await isFileAccessible(readmeFileName)
|
|
21
|
+
if (isReadmeExists) {
|
|
22
|
+
logger.debug(`${readmeFileName} found, asking to overwrite it.`)
|
|
23
|
+
const { shouldReplace } = await inquirer.prompt([{
|
|
24
|
+
type: 'list',
|
|
25
|
+
name: 'shouldReplace',
|
|
26
|
+
message: 'Do you want to overwrite the existing README.md?',
|
|
27
|
+
default: true,
|
|
28
|
+
choices: [{ name: 'yes', value: true }, { name: 'no', value: false }]
|
|
29
|
+
}])
|
|
30
|
+
isReadmeExists = !shouldReplace
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (isReadmeExists) {
|
|
34
|
+
logger.debug(`${readmeFileName} found, skipping creation of README.md file.`)
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const readmeFile = new URL('README.md', import.meta.url)
|
|
39
|
+
const readme = await readFile(readmeFile, 'utf-8')
|
|
40
|
+
await writeFile(readmeFileName, readme)
|
|
41
|
+
logger.debug(`${readmeFileName} successfully created.`)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const createPlatformaticComposer = async (_args, opts) => {
|
|
45
|
+
const logger = opts.logger || pino(pretty({
|
|
46
|
+
translateTime: 'SYS:HH:MM:ss',
|
|
47
|
+
ignore: 'hostname,pid'
|
|
48
|
+
}))
|
|
49
|
+
|
|
50
|
+
const args = parseArgs(_args, {
|
|
51
|
+
default: {
|
|
52
|
+
hostname: '127.0.0.1'
|
|
53
|
+
},
|
|
54
|
+
alias: {
|
|
55
|
+
h: 'hostname',
|
|
56
|
+
p: 'port'
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
const version = await getVersion()
|
|
61
|
+
const pkgManager = getPkgManager()
|
|
62
|
+
|
|
63
|
+
const projectDir = opts.dir || await askDir(logger, '.')
|
|
64
|
+
|
|
65
|
+
const toAsk = [getPort(args.port)]
|
|
66
|
+
|
|
67
|
+
if (!opts.skipPackageJson) {
|
|
68
|
+
toAsk.push(getRunPackageManagerInstall(pkgManager))
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const { runPackageManagerInstall, port } = await inquirer.prompt(toAsk)
|
|
72
|
+
|
|
73
|
+
// Create the project directory
|
|
74
|
+
await mkdir(projectDir, { recursive: true })
|
|
75
|
+
|
|
76
|
+
const params = {
|
|
77
|
+
hostname: args.hostname,
|
|
78
|
+
port
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const env = await createComposer(params, logger, projectDir, version)
|
|
82
|
+
|
|
83
|
+
const fastifyVersion = await getDependencyVersion('fastify')
|
|
84
|
+
|
|
85
|
+
// Create the package.json, notes that we don't have the option for TS (yet) so we don't generate
|
|
86
|
+
// the package.json with the TS build
|
|
87
|
+
if (!opts.skipPackageJson) {
|
|
88
|
+
await createPackageJson('composer', version, fastifyVersion, logger, projectDir, false)
|
|
89
|
+
}
|
|
90
|
+
if (!opts.skipGitignore) {
|
|
91
|
+
await createGitignore(logger, projectDir)
|
|
92
|
+
}
|
|
93
|
+
await createReadme(logger, projectDir)
|
|
94
|
+
|
|
95
|
+
if (runPackageManagerInstall) {
|
|
96
|
+
const spinner = ora('Installing dependencies...').start()
|
|
97
|
+
await execa(pkgManager, ['install'], { cwd: projectDir })
|
|
98
|
+
spinner.succeed('...done!')
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (!opts.skipGitHubActions) {
|
|
102
|
+
await askDynamicWorkspaceCreateGHAction(logger, env, 'composer', false, projectDir)
|
|
103
|
+
await askStaticWorkspaceGHAction(logger, env, 'composer', false, projectDir)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export default createPlatformaticComposer
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { readFile, writeFile, appendFile } from 'fs/promises'
|
|
2
|
+
import { findComposerConfigFile, isFileAccessible } from '../utils.mjs'
|
|
3
|
+
import { join } from 'path'
|
|
4
|
+
import * as desm from 'desm'
|
|
5
|
+
|
|
6
|
+
function generateConfig (version) {
|
|
7
|
+
const config = {
|
|
8
|
+
$schema: `https://platformatic.dev/schemas/v${version}/composer`,
|
|
9
|
+
server: {
|
|
10
|
+
hostname: '{PLT_SERVER_HOSTNAME}',
|
|
11
|
+
port: '{PORT}',
|
|
12
|
+
logger: {
|
|
13
|
+
level: '{PLT_SERVER_LOGGER_LEVEL}'
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
composer: {
|
|
17
|
+
services: [{
|
|
18
|
+
id: 'example',
|
|
19
|
+
origin: '{PLT_EXAMPLE_ORIGIN}',
|
|
20
|
+
openapi: {
|
|
21
|
+
url: '/documentation/json'
|
|
22
|
+
}
|
|
23
|
+
}],
|
|
24
|
+
refreshTimeout: 1000
|
|
25
|
+
},
|
|
26
|
+
watch: true
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return config
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function generateEnv (hostname, port) {
|
|
33
|
+
const env = `\
|
|
34
|
+
PLT_SERVER_HOSTNAME=${hostname}
|
|
35
|
+
PORT=${port}
|
|
36
|
+
PLT_SERVER_LOGGER_LEVEL=info
|
|
37
|
+
PLT_EXAMPLE_ORIGIN=
|
|
38
|
+
`
|
|
39
|
+
|
|
40
|
+
return env
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function createComposer ({ hostname, port }, logger, currentDir = process.cwd(), version) {
|
|
44
|
+
if (!version) {
|
|
45
|
+
const pkg = await readFile(desm.join(import.meta.url, '..', '..', 'package.json'))
|
|
46
|
+
version = JSON.parse(pkg).version
|
|
47
|
+
}
|
|
48
|
+
const accessibleConfigFilename = await findComposerConfigFile(currentDir)
|
|
49
|
+
|
|
50
|
+
if (accessibleConfigFilename === undefined) {
|
|
51
|
+
const config = generateConfig(version)
|
|
52
|
+
await writeFile(join(currentDir, 'platformatic.composer.json'), JSON.stringify(config, null, 2))
|
|
53
|
+
logger.info('Configuration file platformatic.composer.json successfully created.')
|
|
54
|
+
|
|
55
|
+
const env = generateEnv(hostname, port)
|
|
56
|
+
const envFileExists = await isFileAccessible('.env', currentDir)
|
|
57
|
+
await appendFile(join(currentDir, '.env'), env)
|
|
58
|
+
await writeFile(join(currentDir, '.env.sample'), env)
|
|
59
|
+
/* c8 ignore next 5 */
|
|
60
|
+
if (envFileExists) {
|
|
61
|
+
logger.info('Environment file .env found, appending new environment variables to existing .env file.')
|
|
62
|
+
} else {
|
|
63
|
+
logger.info('Environment file .env successfully created.')
|
|
64
|
+
}
|
|
65
|
+
} else {
|
|
66
|
+
logger.info(`Configuration file ${accessibleConfigFilename} found, skipping creation of configuration file.`)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
PLT_SERVER_LOGGER_LEVEL: 'info',
|
|
71
|
+
PORT: port,
|
|
72
|
+
PLT_SERVER_HOSTNAME: hostname
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export default createComposer
|
package/src/db/create-db-cli.mjs
CHANGED
|
@@ -5,16 +5,16 @@ import { getPkgManager } from '../get-pkg-manager.mjs'
|
|
|
5
5
|
import parseArgs from 'minimist'
|
|
6
6
|
import { join } from 'path'
|
|
7
7
|
import inquirer from 'inquirer'
|
|
8
|
-
import
|
|
8
|
+
import which from 'which'
|
|
9
|
+
import { readFile, writeFile, mkdir } from 'fs/promises'
|
|
9
10
|
import pino from 'pino'
|
|
10
11
|
import pretty from 'pino-pretty'
|
|
11
12
|
import { execa } from 'execa'
|
|
12
13
|
import ora from 'ora'
|
|
13
14
|
import createDB from './create-db.mjs'
|
|
14
|
-
import
|
|
15
|
+
import askDir from '../ask-dir.mjs'
|
|
15
16
|
import { askDynamicWorkspaceCreateGHAction, askStaticWorkspaceGHAction } from '../ghaction.mjs'
|
|
16
|
-
import { getRunPackageManagerInstall, getUseTypescript } from '../cli-options.mjs'
|
|
17
|
-
import mkdirp from 'mkdirp'
|
|
17
|
+
import { getRunPackageManagerInstall, getUseTypescript, getPort } from '../cli-options.mjs'
|
|
18
18
|
|
|
19
19
|
export const createReadme = async (logger, dir = '.') => {
|
|
20
20
|
const readmeFileName = join(dir, 'README.md')
|
|
@@ -42,11 +42,10 @@ export const createReadme = async (logger, dir = '.') => {
|
|
|
42
42
|
logger.debug(`${readmeFileName} successfully created.`)
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
export
|
|
45
|
+
export function parseDBArgs (_args) {
|
|
46
46
|
return parseArgs(_args, {
|
|
47
47
|
default: {
|
|
48
48
|
hostname: '127.0.0.1',
|
|
49
|
-
port: 3042,
|
|
50
49
|
database: 'sqlite',
|
|
51
50
|
migrations: 'migrations',
|
|
52
51
|
plugin: true,
|
|
@@ -66,8 +65,8 @@ export const parseDBArgs = (_args) => {
|
|
|
66
65
|
})
|
|
67
66
|
}
|
|
68
67
|
|
|
69
|
-
const createPlatformaticDB = async (_args) => {
|
|
70
|
-
const logger = pino(pretty({
|
|
68
|
+
const createPlatformaticDB = async (_args, opts) => {
|
|
69
|
+
const logger = opts.logger || pino(pretty({
|
|
71
70
|
translateTime: 'SYS:HH:MM:ss',
|
|
72
71
|
ignore: 'hostname,pid'
|
|
73
72
|
}))
|
|
@@ -75,7 +74,7 @@ const createPlatformaticDB = async (_args) => {
|
|
|
75
74
|
const args = parseDBArgs(_args)
|
|
76
75
|
const version = await getVersion()
|
|
77
76
|
const pkgManager = getPkgManager()
|
|
78
|
-
const projectDir = await
|
|
77
|
+
const projectDir = opts.dir || await askDir(logger, '.')
|
|
79
78
|
|
|
80
79
|
const wizardOptions = await inquirer.prompt([{
|
|
81
80
|
type: 'list',
|
|
@@ -90,11 +89,12 @@ const createPlatformaticDB = async (_args) => {
|
|
|
90
89
|
default: args.plugin,
|
|
91
90
|
choices: [{ name: 'yes', value: true }, { name: 'no', value: false }]
|
|
92
91
|
},
|
|
93
|
-
getUseTypescript(args.typescript)
|
|
92
|
+
getUseTypescript(args.typescript),
|
|
93
|
+
getPort(args.port)
|
|
94
94
|
])
|
|
95
95
|
|
|
96
96
|
// Create the project directory
|
|
97
|
-
await
|
|
97
|
+
await mkdir(projectDir, { recursive: true })
|
|
98
98
|
|
|
99
99
|
const generatePlugin = args.plugin || wizardOptions.generatePlugin
|
|
100
100
|
const useTypescript = args.typescript || wizardOptions.useTypescript
|
|
@@ -102,7 +102,7 @@ const createPlatformaticDB = async (_args) => {
|
|
|
102
102
|
|
|
103
103
|
const params = {
|
|
104
104
|
hostname: args.hostname,
|
|
105
|
-
port:
|
|
105
|
+
port: wizardOptions.port,
|
|
106
106
|
database: args.database,
|
|
107
107
|
migrations: wizardOptions.defaultMigrations ? args.migrations : '',
|
|
108
108
|
plugin: generatePlugin,
|
|
@@ -119,17 +119,35 @@ const createPlatformaticDB = async (_args) => {
|
|
|
119
119
|
await createGitignore(logger, projectDir)
|
|
120
120
|
await createReadme(logger, projectDir)
|
|
121
121
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
122
|
+
let hasPlatformaticInstalled = false
|
|
123
|
+
if (!opts.skipPackageJson) {
|
|
124
|
+
const { runPackageManagerInstall } = await inquirer.prompt([
|
|
125
|
+
getRunPackageManagerInstall(pkgManager)
|
|
126
|
+
])
|
|
127
|
+
|
|
128
|
+
if (runPackageManagerInstall) {
|
|
129
|
+
const spinner = ora('Installing dependencies...').start()
|
|
130
|
+
await execa(pkgManager, ['install'], { cwd: projectDir })
|
|
131
|
+
spinner.succeed('...done!')
|
|
132
|
+
hasPlatformaticInstalled = true
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (!hasPlatformaticInstalled) {
|
|
137
|
+
try {
|
|
138
|
+
const npmLs = JSON.parse(await execa('npm', ['ls', '--json']))
|
|
139
|
+
hasPlatformaticInstalled = !!npmLs.dependencies.platformatic
|
|
140
|
+
} catch {
|
|
141
|
+
// Ignore all errors, this can fail
|
|
142
|
+
}
|
|
143
|
+
}
|
|
125
144
|
|
|
126
|
-
if (
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
spinner.succeed('...done!')
|
|
145
|
+
if (!hasPlatformaticInstalled) {
|
|
146
|
+
const exe = await which('platformatic', { noThrow: true })
|
|
147
|
+
hasPlatformaticInstalled = !!exe
|
|
130
148
|
}
|
|
131
149
|
|
|
132
|
-
if (
|
|
150
|
+
if (hasPlatformaticInstalled) {
|
|
133
151
|
// We applied package manager install, so we can:
|
|
134
152
|
// - run the migrations
|
|
135
153
|
// - generate types
|
|
@@ -166,8 +184,11 @@ const createPlatformaticDB = async (_args) => {
|
|
|
166
184
|
}
|
|
167
185
|
}
|
|
168
186
|
}
|
|
169
|
-
|
|
170
|
-
|
|
187
|
+
|
|
188
|
+
if (!opts.skipGitHubActions) {
|
|
189
|
+
await askDynamicWorkspaceCreateGHAction(logger, env, 'db', useTypescript, projectDir)
|
|
190
|
+
await askStaticWorkspaceGHAction(logger, env, 'db', useTypescript, projectDir)
|
|
191
|
+
}
|
|
171
192
|
}
|
|
172
193
|
|
|
173
194
|
export default createPlatformaticDB
|
package/src/ghaction.mjs
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import mkdirp from 'mkdirp'
|
|
2
1
|
import { join } from 'path'
|
|
3
2
|
import inquirer from 'inquirer'
|
|
4
3
|
import { isFileAccessible } from './utils.mjs'
|
|
5
|
-
import { writeFile } from 'fs/promises'
|
|
4
|
+
import { writeFile, mkdir } from 'fs/promises'
|
|
6
5
|
|
|
7
|
-
export const dynamicWorkspaceGHTemplate = (
|
|
6
|
+
export const dynamicWorkspaceGHTemplate = (env, config, buildTS = false) => {
|
|
8
7
|
const envAsStr = Object.keys(env).reduce((acc, key) => {
|
|
9
8
|
acc += ` ${key}: ${env[key]} \n`
|
|
10
9
|
return acc
|
|
@@ -36,7 +35,7 @@ jobs:
|
|
|
36
35
|
uses: platformatic/onestep@latest
|
|
37
36
|
with:
|
|
38
37
|
github_token: \${{ secrets.GITHUB_TOKEN }}
|
|
39
|
-
platformatic_workspace_id:
|
|
38
|
+
platformatic_workspace_id: \${{ secrets.PLATFORMATIC_DYNAMIC_WORKSPACE_ID }}
|
|
40
39
|
platformatic_workspace_key: \${{ secrets.PLATFORMATIC_DYNAMIC_WORKSPACE_API_KEY }}
|
|
41
40
|
platformatic_config_path: ${config}
|
|
42
41
|
env:
|
|
@@ -44,7 +43,7 @@ ${envAsStr}
|
|
|
44
43
|
`
|
|
45
44
|
}
|
|
46
45
|
|
|
47
|
-
export const staticWorkspaceGHTemplate = (
|
|
46
|
+
export const staticWorkspaceGHTemplate = (env, config, buildTS = false) => {
|
|
48
47
|
const envAsStr = Object.keys(env).reduce((acc, key) => {
|
|
49
48
|
acc += ` ${key}: ${env[key]} \n`
|
|
50
49
|
return acc
|
|
@@ -77,7 +76,7 @@ jobs:
|
|
|
77
76
|
uses: platformatic/onestep@latest
|
|
78
77
|
with:
|
|
79
78
|
github_token: \${{ secrets.GITHUB_TOKEN }}
|
|
80
|
-
platformatic_workspace_id:
|
|
79
|
+
platformatic_workspace_id: \${{ secrets.PLATFORMATIC_STATIC_WORKSPACE_ID }}
|
|
81
80
|
platformatic_workspace_key: \${{ secrets.PLATFORMATIC_STATIC_WORKSPACE_API_KEY }}
|
|
82
81
|
platformatic_config_path: ${config}
|
|
83
82
|
env:
|
|
@@ -85,19 +84,14 @@ ${envAsStr}
|
|
|
85
84
|
`
|
|
86
85
|
}
|
|
87
86
|
|
|
88
|
-
export const createDynamicWorkspaceGHAction = async (logger,
|
|
87
|
+
export const createDynamicWorkspaceGHAction = async (logger, env, config, projectDir, buildTS) => {
|
|
89
88
|
const ghActionFileName = 'platformatic-dynamic-workspace-deploy.yml'
|
|
90
89
|
const ghActionFilePath = join(projectDir, '.github', 'workflows', ghActionFileName)
|
|
91
90
|
const isGithubActionExists = await isFileAccessible(ghActionFilePath)
|
|
92
91
|
if (!isGithubActionExists) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
await mkdirp(join(projectDir, '.github', 'workflows'))
|
|
99
|
-
await writeFile(ghActionFilePath, dynamicWorkspaceGHTemplate(workspaceId, env, config, buildTS))
|
|
100
|
-
logger.info('Github action successfully created, please add PLATFORMATIC_DYNAMIC_WORKSPACE_API_KEY as repository secret.')
|
|
92
|
+
await mkdir(join(projectDir, '.github', 'workflows'), { recursive: true })
|
|
93
|
+
await writeFile(ghActionFilePath, dynamicWorkspaceGHTemplate(env, config, buildTS))
|
|
94
|
+
logger.info('Github action successfully created, please add PLATFORMATIC_DYNAMIC_WORKSPACE_ID and PLATFORMATIC_DYNAMIC_WORKSPACE_API_KEY as repository secrets.')
|
|
101
95
|
const isGitDir = await isFileAccessible('.git', projectDir)
|
|
102
96
|
if (!isGitDir) {
|
|
103
97
|
logger.warn('No git repository found. The Github action won\'t be triggered.')
|
|
@@ -119,32 +113,20 @@ export const askDynamicWorkspaceCreateGHAction = async (logger, env, type, build
|
|
|
119
113
|
}
|
|
120
114
|
])
|
|
121
115
|
if (githubAction) {
|
|
122
|
-
const { workspaceId } = await inquirer.prompt([
|
|
123
|
-
{
|
|
124
|
-
type: 'input',
|
|
125
|
-
name: 'workspaceId',
|
|
126
|
-
message: 'Please enter the workspace ID:'
|
|
127
|
-
}
|
|
128
|
-
])
|
|
129
116
|
const config = `./platformatic.${type}.json`
|
|
130
|
-
await createDynamicWorkspaceGHAction(logger,
|
|
117
|
+
await createDynamicWorkspaceGHAction(logger, env, config, projectDir, buildTS)
|
|
131
118
|
}
|
|
132
119
|
/* c8 ignore next */
|
|
133
120
|
}
|
|
134
121
|
|
|
135
|
-
export const createStaticWorkspaceGHAction = async (logger,
|
|
122
|
+
export const createStaticWorkspaceGHAction = async (logger, env, config, projectDir, buildTS) => {
|
|
136
123
|
const ghActionFileName = 'platformatic-static-workspace-deploy.yml'
|
|
137
124
|
const ghActionFilePath = join(projectDir, '.github', 'workflows', ghActionFileName)
|
|
138
125
|
const isGithubActionExists = await isFileAccessible(ghActionFilePath)
|
|
139
126
|
if (!isGithubActionExists) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
await mkdirp(join(projectDir, '.github', 'workflows'))
|
|
146
|
-
await writeFile(ghActionFilePath, staticWorkspaceGHTemplate(workspaceId, env, config, buildTS))
|
|
147
|
-
logger.info('Github action successfully created, please add PLATFORMATIC_STATIC_WORKSPACE_API_KEY as repository secret.')
|
|
127
|
+
await mkdir(join(projectDir, '.github', 'workflows'), { recursive: true })
|
|
128
|
+
await writeFile(ghActionFilePath, staticWorkspaceGHTemplate(env, config, buildTS))
|
|
129
|
+
logger.info('Github action successfully created, please add PLATFORMATIC_STATIC_WORKSPACE_ID and PLATFORMATIC_STATIC_WORKSPACE_API_KEY as repository secret.')
|
|
148
130
|
const isGitDir = await isFileAccessible('.git', projectDir)
|
|
149
131
|
if (!isGitDir) {
|
|
150
132
|
logger.warn('No git repository found. The Github action won\'t be triggered.')
|
|
@@ -166,15 +148,8 @@ export const askStaticWorkspaceGHAction = async (logger, env, type, buildTS, pro
|
|
|
166
148
|
}
|
|
167
149
|
])
|
|
168
150
|
if (githubAction) {
|
|
169
|
-
const { workspaceId } = await inquirer.prompt([
|
|
170
|
-
{
|
|
171
|
-
type: 'input',
|
|
172
|
-
name: 'workspaceId',
|
|
173
|
-
message: 'Please enter the workspace ID:'
|
|
174
|
-
}
|
|
175
|
-
])
|
|
176
151
|
const config = `./platformatic.${type}.json`
|
|
177
|
-
await createStaticWorkspaceGHAction(logger,
|
|
152
|
+
await createStaticWorkspaceGHAction(logger, env, config, projectDir, buildTS)
|
|
178
153
|
}
|
|
179
154
|
/* c8 ignore next */
|
|
180
155
|
}
|
package/src/index.mjs
CHANGED
|
@@ -2,10 +2,45 @@ import { say } from './say.mjs'
|
|
|
2
2
|
import helpMe from 'help-me'
|
|
3
3
|
import { join } from 'desm'
|
|
4
4
|
import inquirer from 'inquirer'
|
|
5
|
+
import { readdir, readFile } from 'fs/promises'
|
|
5
6
|
import createPlatformaticDB from './db/create-db-cli.mjs'
|
|
6
7
|
import createPlatformaticService from './service/create-service-cli.mjs'
|
|
8
|
+
import createPlatformaticComposer from './composer/create-composer-cli.mjs'
|
|
9
|
+
import { createPlatformaticRuntime, createRuntimeService } from './runtime/create-runtime-cli.mjs'
|
|
7
10
|
import commist from 'commist'
|
|
8
|
-
import { getUsername, getVersion, minimumSupportedNodeVersions, isCurrentVersionSupported } from './utils.mjs'
|
|
11
|
+
import { getUsername, getVersion, minimumSupportedNodeVersions, isCurrentVersionSupported, findRuntimeConfigFile } from './utils.mjs'
|
|
12
|
+
|
|
13
|
+
export async function chooseKind (argv, opts = {}) {
|
|
14
|
+
const skip = opts.skip
|
|
15
|
+
const choices = [
|
|
16
|
+
{ name: 'DB', value: 'db' },
|
|
17
|
+
{ name: 'Service', value: 'service' },
|
|
18
|
+
{ name: 'Composer', value: 'composer' },
|
|
19
|
+
{ name: 'Runtime', value: 'runtime' }
|
|
20
|
+
].filter((choice) => !skip || choice.value !== skip)
|
|
21
|
+
|
|
22
|
+
const options = await inquirer.prompt({
|
|
23
|
+
type: 'list',
|
|
24
|
+
name: 'type',
|
|
25
|
+
message: 'Which kind of project do you want to create?',
|
|
26
|
+
choices
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
switch (options.type) {
|
|
30
|
+
case 'db':
|
|
31
|
+
await createPlatformaticDB(argv, opts)
|
|
32
|
+
break
|
|
33
|
+
case 'service':
|
|
34
|
+
await createPlatformaticService(argv, opts)
|
|
35
|
+
break
|
|
36
|
+
case 'composer':
|
|
37
|
+
await createPlatformaticComposer(argv, opts)
|
|
38
|
+
break
|
|
39
|
+
case 'runtime':
|
|
40
|
+
await createPlatformaticRuntime(argv, opts)
|
|
41
|
+
break
|
|
42
|
+
}
|
|
43
|
+
}
|
|
9
44
|
|
|
10
45
|
const createPlatformatic = async (argv) => {
|
|
11
46
|
const help = helpMe({
|
|
@@ -20,6 +55,8 @@ const createPlatformatic = async (argv) => {
|
|
|
20
55
|
program.register('service help', help.toStdout.bind(null, ['service']))
|
|
21
56
|
program.register('db', createPlatformaticDB)
|
|
22
57
|
program.register('service', createPlatformaticService)
|
|
58
|
+
program.register('composer', createPlatformaticComposer)
|
|
59
|
+
program.register('runtime', createPlatformaticRuntime)
|
|
23
60
|
|
|
24
61
|
const result = program.parse(argv)
|
|
25
62
|
|
|
@@ -28,7 +65,6 @@ const createPlatformatic = async (argv) => {
|
|
|
28
65
|
const version = await getVersion()
|
|
29
66
|
const greeting = username ? `Hello, ${username}` : 'Hello,'
|
|
30
67
|
await say(`${greeting} welcome to ${version ? `Platformatic ${version}!` : 'Platformatic!'}`)
|
|
31
|
-
await say('Let\'s start by creating a new project.')
|
|
32
68
|
|
|
33
69
|
const currentVersion = process.versions.node
|
|
34
70
|
const supported = isCurrentVersionSupported(currentVersion)
|
|
@@ -38,18 +74,26 @@ const createPlatformatic = async (argv) => {
|
|
|
38
74
|
await say(`Please use one of the following Node.js versions >= ${supportedVersions}.`)
|
|
39
75
|
}
|
|
40
76
|
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
77
|
+
const runtimeConfig = await findRuntimeConfigFile(process.cwd())
|
|
78
|
+
if (runtimeConfig) {
|
|
79
|
+
await say(`Found a ${runtimeConfig} file in the current directory.`)
|
|
80
|
+
const config = JSON.parse(await readFile(runtimeConfig, 'utf8'))
|
|
81
|
+
if (config.autoload?.path) {
|
|
82
|
+
const servicesDir = config.autoload.path
|
|
83
|
+
const names = []
|
|
84
|
+
for (const entry of await readdir(servicesDir)) {
|
|
85
|
+
names.push(entry)
|
|
86
|
+
}
|
|
87
|
+
if (!await createRuntimeService({ servicesDir, names })) {
|
|
88
|
+
process.exit(1)
|
|
89
|
+
}
|
|
90
|
+
} else {
|
|
91
|
+
await say('The current project does not have a services directory.')
|
|
92
|
+
process.exit(1)
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
await say('Let\'s start by creating a new project.')
|
|
96
|
+
await chooseKind(argv)
|
|
53
97
|
}
|
|
54
98
|
|
|
55
99
|
await say('\nAll done! Please open the project directory and check the README.')
|