create-platformatic 1.17.0 → 1.19.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.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import createPlatformatic from './src/index.mjs'
2
+ import { createPlatformatic } from '@platformatic/create-platformatic-auto'
3
3
  import isMain from 'es-main'
4
4
  import parseArgs from 'minimist'
5
5
  import { readFile } from 'fs/promises'
@@ -30,12 +30,7 @@ if (isMain(import.meta)) {
30
30
  await createPlatformatic(_args)
31
31
  }
32
32
 
33
- export { default as createDB } from './src/db/create-db.mjs'
34
- export { parseDBArgs } from './src/db/create-db-cli.mjs'
35
33
  export {
36
34
  createStaticWorkspaceGHAction,
37
35
  createDynamicWorkspaceGHAction
38
36
  } from './src/ghaction.mjs'
39
-
40
- export { createGitignore, createGitRepository, createPackageJson, getDependencyVersion, getVersion } from './src/index.mjs'
41
- export { default as createService } from './src/service/create-service.mjs'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-platformatic",
3
- "version": "1.17.0",
3
+ "version": "1.19.0",
4
4
  "description": "Create platformatic-db interactive tool",
5
5
  "repository": {
6
6
  "type": "git",
@@ -36,8 +36,9 @@
36
36
  "strip-ansi": "^7.1.0",
37
37
  "undici": "^6.0.0",
38
38
  "which": "^3.0.1",
39
- "@platformatic/utils": "1.17.0",
40
- "@platformatic/config": "1.17.0"
39
+ "@platformatic/create-platformatic-auto": "1.19.0",
40
+ "@platformatic/utils": "1.19.0",
41
+ "@platformatic/config": "1.19.0"
41
42
  },
42
43
  "devDependencies": {
43
44
  "ajv": "^8.12.0",
@@ -49,8 +50,8 @@
49
50
  "standard": "^17.1.0",
50
51
  "typescript": "~5.3.0",
51
52
  "yaml": "^2.3.2",
52
- "@platformatic/db": "1.17.0",
53
- "@platformatic/service": "1.17.0"
53
+ "@platformatic/db": "1.19.0",
54
+ "@platformatic/service": "1.19.0"
54
55
  },
55
56
  "scripts": {
56
57
  "test:cli": "node --test ./test/cli",
package/src/ghaction.mjs CHANGED
@@ -2,6 +2,7 @@ import { join } from 'path'
2
2
  import { isFileAccessible, safeMkdir } from './utils.mjs'
3
3
  import { writeFile } from 'fs/promises'
4
4
  import columnify from 'columnify'
5
+
5
6
  function envAsString (env, indent) {
6
7
  const spaces = ' '.repeat(indent * 2)
7
8
  return Object.keys(env).reduce((acc, key) => {
package/src/utils.mjs CHANGED
@@ -1,16 +1,5 @@
1
- import { execa } from 'execa'
2
- import { access, constants, mkdir, readFile } from 'fs/promises'
3
- import { resolve, join, dirname } from 'path'
4
- import { createRequire } from 'module'
5
- import semver from 'semver'
6
- import * as desm from 'desm'
7
- import * as url from 'url'
8
-
9
- import ConfigManager from '@platformatic/config'
10
-
11
- export const sleep = ms => new Promise((resolve) => setTimeout(resolve, ms))
12
- export const randomBetween = (min, max) => Math.floor(Math.random() * (max - min + 1) + min)
13
- const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
1
+ import { access, mkdir } from 'fs/promises'
2
+ import { resolve } from 'path'
14
3
 
15
4
  export async function isFileAccessible (filename, directory) {
16
5
  try {
@@ -21,123 +10,6 @@ export async function isFileAccessible (filename, directory) {
21
10
  return false
22
11
  }
23
12
  }
24
- /**
25
- * Gets the username from git config or `whoami` command
26
- * @returns string | null
27
- */
28
- export const getUsername = async () => {
29
- try {
30
- const { stdout } = await execa('git', ['config', 'user.name'])
31
- if (stdout?.trim()) {
32
- return stdout.trim()
33
- }
34
- } catch (err) {
35
- // ignore: git failed
36
- }
37
- try {
38
- const { stdout } = await execa('whoami')
39
- if (stdout?.trim()) {
40
- return stdout.trim()
41
- }
42
- } catch (err) {
43
- // ignore: whoami failed
44
- }
45
-
46
- return null
47
- }
48
- /**
49
- * Get the platformatic package version from package.json
50
- * @returns string
51
- */
52
- /* c8 ignore next 4 */
53
- export const getVersion = async () => {
54
- const data = await readFile(desm.join(import.meta.url, '..', 'package.json'), 'utf8')
55
- return JSON.parse(data).version
56
- }
57
-
58
- export async function isDirectoryWriteable (directory) {
59
- try {
60
- await access(directory, constants.R_OK | constants.W_OK)
61
- return true
62
- } catch (err) {
63
- return false
64
- }
65
- }
66
-
67
- export const findConfigFile = async (directory) => (ConfigManager.findConfigFile(directory))
68
- export const findDBConfigFile = async (directory) => (ConfigManager.findConfigFile(directory, 'db'))
69
- export const findServiceConfigFile = async (directory) => (ConfigManager.findConfigFile(directory, 'service'))
70
- export const findComposerConfigFile = async (directory) => (ConfigManager.findConfigFile(directory, 'composer'))
71
- export const findRuntimeConfigFile = async (directory) => (ConfigManager.findConfigFile(directory, 'runtime'))
72
-
73
- /**
74
- * Gets the version of the specified dependency package from package.json
75
- * @param {string} dependencyName
76
- * @returns string
77
- */
78
- export const getDependencyVersion = async (dependencyName) => {
79
- const rootPackageJson = join(__dirname, '..', 'package.json')
80
- const packageJsonContents = JSON.parse(await readFile(rootPackageJson, 'utf8'))
81
- const dependencies = packageJsonContents.dependencies
82
- const devDependencies = packageJsonContents.devDependencies
83
- const regexp = /(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)/
84
- if (dependencies[dependencyName]) {
85
- const match = dependencies[dependencyName].match(regexp)
86
- if (!match) {
87
- return await resolveWorkspaceDependency(dependencyName)
88
- }
89
- return match[0]
90
- }
91
-
92
- if (devDependencies[dependencyName]) {
93
- const match = devDependencies[dependencyName].match(regexp)
94
- if (!match) {
95
- return await resolveWorkspaceDependency(dependencyName)
96
- }
97
- return match[0]
98
- }
99
-
100
- async function resolveWorkspaceDependency (dependencyName) {
101
- const require = createRequire(import.meta.url)
102
- let dependencyPath = dirname(require.resolve(dependencyName))
103
- // some deps are resolved not at their root level
104
- // for instance 'typescript' will be risolved in its own ./lib directory
105
- // next loop is to find the nearest parent directory that contains a package.json file
106
- while (!await isFileAccessible(join(dependencyPath, 'package.json'))) {
107
- dependencyPath = join(dependencyPath, '..')
108
- if (dependencyPath === '/') {
109
- throw new Error(`Cannot find package.json for ${dependencyName}`)
110
- }
111
- }
112
- const pathToPackageJson = join(dependencyPath, 'package.json')
113
- const packageJsonFile = await readFile(pathToPackageJson, 'utf-8')
114
- const packageJson = JSON.parse(packageJsonFile)
115
- return packageJson.version
116
- }
117
- }
118
-
119
- export const minimumSupportedNodeVersions = ['18.8.0', '20.6.0']
120
-
121
- export const isCurrentVersionSupported = (currentVersion) => {
122
- // TODO: add try/catch if some unsupported node version is passed
123
- for (const version of minimumSupportedNodeVersions) {
124
- if (semver.major(currentVersion) === semver.major(version) && semver.gte(currentVersion, version)) {
125
- return true
126
- }
127
- }
128
- return false
129
- }
130
-
131
- export function convertServiceNameToPrefix (serviceName) {
132
- return serviceName.replace(/-/g, '_').toUpperCase()
133
- }
134
- export function addPrefixToEnv (env, prefix) {
135
- const output = {}
136
- Object.entries(env).forEach(([key, value]) => {
137
- output[`${prefix}_${key}`] = value
138
- })
139
- return output
140
- }
141
13
 
142
14
  export async function safeMkdir (dir) {
143
15
  try {
package/src/ask-dir.mjs DELETED
@@ -1,37 +0,0 @@
1
- 'use strict'
2
-
3
- import { stat } from 'fs/promises'
4
- import inquirer from 'inquirer'
5
- import { resolve } from 'path'
6
-
7
- const askProjectDir = async (logger, defaultName, message = 'Where would you like to create your project?') => {
8
- const options = await inquirer.prompt({
9
- type: 'input',
10
- name: 'dir',
11
- message,
12
- default: defaultName
13
- })
14
-
15
- const projectDir = resolve(process.cwd(), options.dir)
16
-
17
- try {
18
- await stat(projectDir)
19
- logger.warn(`Directory ${projectDir} is not empty. Some files may be overwritten without confirmation.`)
20
- const confirmation = await inquirer.prompt({
21
- type: 'list',
22
- name: 'confirmExistingDirectory',
23
- message: `Confirm you want to use ${projectDir} directory?`,
24
- default: 'no',
25
- choices: [{ name: 'yes', value: true }, { name: 'no', value: false }]
26
- })
27
- if (!confirmation.confirmExistingDirectory) {
28
- logger.error('Please choose another directory.')
29
- process.exit(1)
30
- }
31
- } catch (err) {
32
- // directory is empty, we can proceed
33
- }
34
- return projectDir
35
- }
36
-
37
- export default askProjectDir
@@ -1,34 +0,0 @@
1
- export const getUseTypescript = typescript => {
2
- return {
3
- type: 'list',
4
- when: !typescript,
5
- name: 'useTypescript',
6
- message: 'Do you want to use TypeScript?',
7
- default: typescript,
8
- choices: [{ name: 'yes', value: true }, { name: 'no', value: false }]
9
- }
10
- }
11
-
12
- export const getInitGitRepository = () => {
13
- return {
14
- type: 'list',
15
- name: 'initGitRepository',
16
- message: 'Do you want to init the git repository?',
17
- default: false,
18
- choices: [{ name: 'yes', value: true }, { name: 'no', value: false }]
19
- }
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
- }
package/src/colors.mjs DELETED
@@ -1,4 +0,0 @@
1
- import chalk, { supportsColor } from 'chalk'
2
- const useColor = supportsColor && !process.env.NO_COLOR
3
- const noop = (str) => str
4
- export const pltGreen = useColor ? chalk.hex('#21FA90') : noop
@@ -1,30 +0,0 @@
1
- # Platformatic Composer API
2
-
3
- This is a generated [Platformatic Composer](https://docs.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 or >= v20.6.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
-
@@ -1,143 +0,0 @@
1
- import { getVersion, getDependencyVersion, safeMkdir } from '../utils.mjs'
2
- import { createPackageJson } from '../create-package-json.mjs'
3
- import { createGitignore } from '../create-gitignore.mjs'
4
- import { getPkgManager } from '@platformatic/utils'
5
- import parseArgs from 'minimist'
6
- import inquirer from 'inquirer'
7
- import pino from 'pino'
8
- import pretty from 'pino-pretty'
9
- import { execa } from 'execa'
10
- import ora from 'ora'
11
- import createComposer from './create-composer.mjs'
12
- import askDir from '../ask-dir.mjs'
13
- import { getPort, getUseTypescript, getInitGitRepository } from '../cli-options.mjs'
14
- import { createReadme } from '../create-readme.mjs'
15
- import { join } from 'path'
16
-
17
- export const getServicesToCompose = (servicesNames) => {
18
- return {
19
- type: 'checkbox',
20
- name: 'servicesToCompose',
21
- message: 'Which services do you want to expose via Platformatic Composer?',
22
- choices: servicesNames,
23
- default: []
24
- }
25
- }
26
-
27
- const createPlatformaticComposer = async (_args, opts) => {
28
- const logger = opts.logger || pino(pretty({
29
- translateTime: 'SYS:HH:MM:ss',
30
- ignore: 'hostname,pid'
31
- }))
32
-
33
- const args = parseArgs(_args, {
34
- default: {
35
- hostname: '127.0.0.1',
36
- install: true
37
- },
38
- alias: {
39
- h: 'hostname',
40
- p: 'port'
41
- },
42
- boolean: ['install']
43
- })
44
-
45
- const version = await getVersion()
46
- const pkgManager = getPkgManager()
47
-
48
- const projectDir = opts.dir || await askDir(logger, join('.', 'platformatic-composer'))
49
- const isRuntimeContext = opts.isRuntimeContext || false
50
-
51
- const toAsk = []
52
-
53
- // Ask for port if not in runtime context
54
- const portQuestion = getPort(args.port)
55
- portQuestion.when = !isRuntimeContext
56
- toAsk.push(portQuestion)
57
- toAsk.push(getUseTypescript(args.typescript))
58
-
59
- if (isRuntimeContext) {
60
- const servicesNames = opts.runtimeContext.servicesNames.filter(
61
- (serviceName) => serviceName !== opts.serviceName
62
- )
63
- if (servicesNames.length > 0) {
64
- toAsk.push(getServicesToCompose(servicesNames))
65
- }
66
- }
67
-
68
- if (!opts.skipGitHubActions) {
69
- toAsk.push({
70
- type: 'list',
71
- name: 'staticWorkspaceGitHubAction',
72
- message: 'Do you want to create the github action to deploy this application to Platformatic Cloud?',
73
- default: true,
74
- choices: [{ name: 'yes', value: true }, { name: 'no', value: false }]
75
- },
76
- {
77
- type: 'list',
78
- name: 'dynamicWorkspaceGitHubAction',
79
- message: 'Do you want to enable PR Previews in your application?',
80
- default: true,
81
- choices: [{ name: 'yes', value: true }, { name: 'no', value: false }]
82
- })
83
- }
84
-
85
- if (!opts.skipGitRepository) {
86
- toAsk.push(getInitGitRepository())
87
- }
88
- const {
89
- servicesToCompose,
90
- port,
91
- staticWorkspaceGitHubAction,
92
- dynamicWorkspaceGitHubAction,
93
- useTypescript,
94
- initGitRepository
95
- } = await inquirer.prompt(toAsk)
96
-
97
- // Create the project directory
98
- await safeMkdir(projectDir)
99
-
100
- const params = {
101
- isRuntimeContext,
102
- hostname: args.hostname,
103
- port,
104
- servicesToCompose,
105
- staticWorkspaceGitHubAction,
106
- dynamicWorkspaceGitHubAction,
107
- runtimeContext: opts.runtimeContext,
108
- typescript: useTypescript,
109
- initGitRepository
110
- }
111
-
112
- await createComposer(
113
- params,
114
- logger,
115
- projectDir,
116
- version
117
- )
118
-
119
- const fastifyVersion = await getDependencyVersion('fastify')
120
-
121
- // Create the package.json, notes that we don't have the option for TS (yet) so we don't generate
122
- // the package.json with the TS build
123
- if (!opts.skipPackageJson) {
124
- await createPackageJson(version, fastifyVersion, logger, projectDir, useTypescript)
125
- }
126
- if (!opts.skipGitignore) {
127
- await createGitignore(logger, projectDir)
128
- }
129
- await createReadme(logger, projectDir, 'composer')
130
-
131
- if (args.install && !opts.skipPackageJson) {
132
- const spinner = ora('Installing dependencies...').start()
133
- await execa(pkgManager, ['install'], { cwd: projectDir })
134
- spinner.succeed()
135
- }
136
-
137
- // returns metadata that can be used to make some further actions
138
- return {
139
- typescript: useTypescript
140
- }
141
- }
142
-
143
- export default createPlatformaticComposer
@@ -1,146 +0,0 @@
1
- import { readFile, writeFile, appendFile } from 'fs/promises'
2
- import { join } from 'path'
3
- import * as desm from 'desm'
4
- import { generatePlugins } from '../create-plugins.mjs'
5
- import { createDynamicWorkspaceGHAction, createStaticWorkspaceGHAction } from '../ghaction.mjs'
6
- import { getTsConfig } from '../get-tsconfig.mjs'
7
- import { createGitRepository } from '../create-git-repository.mjs'
8
-
9
- const TS_OUT_DIR = 'dist'
10
-
11
- function generateConfig (isRuntimeContext, version, servicesToCompose, typescript, envPrefix) {
12
- const config = {
13
- $schema: `https://platformatic.dev/schemas/v${version}/composer`,
14
- composer: {
15
- services: [{
16
- id: 'example',
17
- origin: `{PLT_${envPrefix}EXAMPLE_ORIGIN}`,
18
- openapi: {
19
- url: '/documentation/json'
20
- }
21
- }],
22
- refreshTimeout: 1000
23
- },
24
- watch: true,
25
- plugins: {
26
- paths: [
27
- { path: './plugins', encapsulate: false },
28
- './routes'
29
- ]
30
- }
31
- }
32
-
33
- if (!isRuntimeContext) {
34
- config.server = {
35
- hostname: '{PLT_SERVER_HOSTNAME}',
36
- port: '{PORT}',
37
- logger: {
38
- level: '{PLT_SERVER_LOGGER_LEVEL}'
39
- }
40
- }
41
- } else {
42
- config.composer.services = servicesToCompose.map((serviceName) => {
43
- return {
44
- id: serviceName,
45
- openapi: {
46
- url: '/documentation/json',
47
- prefix: `/${serviceName}`
48
- }
49
- }
50
- })
51
- }
52
-
53
- if (typescript === true && config.plugins) {
54
- config.plugins.typescript = `{PLT_${envPrefix}TYPESCRIPT}`
55
- }
56
-
57
- return config
58
- }
59
-
60
- function generateEnv (isRuntimeContext, hostname, port, typescript, envPrefix) {
61
- let env = ''
62
-
63
- if (!isRuntimeContext) {
64
- env += `\
65
- PLT_SERVER_HOSTNAME=${hostname}
66
- PORT=${port}
67
- PLT_SERVER_LOGGER_LEVEL=info`
68
- }
69
- env += `
70
- PLT_${envPrefix}EXAMPLE_ORIGIN=
71
- `
72
- if (typescript === true) {
73
- env += `\
74
- # Set to false to disable automatic typescript compilation.
75
- # Changing this setting is needed for production
76
- PLT_${envPrefix}TYPESCRIPT=true
77
- `
78
- }
79
- return env
80
- }
81
-
82
- async function createComposer (
83
- params,
84
- logger,
85
- currentDir = process.cwd(),
86
- version
87
- ) {
88
- const {
89
- isRuntimeContext,
90
- hostname,
91
- port,
92
- servicesToCompose = [],
93
- runtimeContext,
94
- typescript,
95
- staticWorkspaceGitHubAction,
96
- dynamicWorkspaceGitHubAction,
97
- initGitRepository
98
- } = params
99
-
100
- const composerEnv = {
101
- PLT_SERVER_LOGGER_LEVEL: 'info',
102
- PORT: port,
103
- PLT_SERVER_HOSTNAME: hostname
104
- }
105
- if (!version) {
106
- const pkg = await readFile(desm.join(import.meta.url, '..', '..', 'package.json'))
107
- version = JSON.parse(pkg).version
108
- }
109
- const envPrefix = runtimeContext !== undefined ? `${runtimeContext.envPrefix}_` : ''
110
-
111
- const config = generateConfig(isRuntimeContext, version, servicesToCompose, typescript, envPrefix)
112
- await writeFile(join(currentDir, 'platformatic.composer.json'), JSON.stringify(config, null, 2))
113
- logger.info('Configuration file platformatic.composer.json successfully created.')
114
-
115
- const env = generateEnv(isRuntimeContext, hostname, port, typescript, envPrefix)
116
- await appendFile(join(currentDir, '.env'), env)
117
- await writeFile(join(currentDir, '.env.sample'), env)
118
- /* c8 ignore next 5 */
119
- logger.info('Environment file .env successfully created.')
120
- await generatePlugins(logger, currentDir, typescript, 'composer')
121
-
122
- if (typescript === true) {
123
- const tsConfigFileName = join(currentDir, 'tsconfig.json')
124
- const tsConfig = getTsConfig(TS_OUT_DIR)
125
- await writeFile(tsConfigFileName, JSON.stringify(tsConfig, null, 2))
126
- logger.info(`Typescript configuration file ${tsConfigFileName} successfully created.`)
127
-
128
- // TODO: global.d.ts is needed to compile the project. Still need to populate it
129
- await writeFile(join(currentDir, 'global.d.ts'), '')
130
- }
131
-
132
- if (staticWorkspaceGitHubAction) {
133
- await createStaticWorkspaceGHAction(logger, composerEnv, './platformatic.service.json', currentDir, typescript)
134
- }
135
- if (dynamicWorkspaceGitHubAction) {
136
- await createDynamicWorkspaceGHAction(logger, composerEnv, './platformatic.service.json', currentDir, typescript)
137
- }
138
-
139
- if (initGitRepository) {
140
- await createGitRepository(logger, currentDir)
141
- }
142
-
143
- return composerEnv
144
- }
145
-
146
- export default createComposer