create-platformatic 0.46.1 → 0.47.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-platformatic",
3
- "version": "0.46.1",
3
+ "version": "0.47.0",
4
4
  "description": "Create platformatic-db interactive tool",
5
5
  "repository": {
6
6
  "type": "git",
@@ -34,7 +34,7 @@
34
34
  "semver": "^7.5.1",
35
35
  "undici": "^5.22.1",
36
36
  "which": "^3.0.1",
37
- "@platformatic/config": "0.46.1"
37
+ "@platformatic/config": "0.47.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "ajv": "^8.12.0",
@@ -47,8 +47,8 @@
47
47
  "tap": "^16.3.6",
48
48
  "typescript": "~5.2.0",
49
49
  "yaml": "^2.3.1",
50
- "@platformatic/db": "0.46.1",
51
- "@platformatic/service": "0.46.1"
50
+ "@platformatic/db": "0.47.0",
51
+ "@platformatic/service": "0.47.0"
52
52
  },
53
53
  "scripts": {
54
54
  "test": "standard | snazzy && cross-env NODE_OPTIONS=\"--loader=esmock --no-warnings\" c8 tap --no-coverage test/*test.mjs test/*/*test.mjs",
package/src/ask-dir.mjs CHANGED
@@ -1,4 +1,3 @@
1
- import { validatePath } from './utils.mjs'
2
1
  import inquirer from 'inquirer'
3
2
  import { resolve } from 'path'
4
3
 
@@ -7,8 +6,7 @@ const askProjectDir = async (logger, defaultName, message = 'Where would you lik
7
6
  type: 'input',
8
7
  name: 'dir',
9
8
  message,
10
- default: defaultName,
11
- validate: validatePath
9
+ default: defaultName
12
10
  })
13
11
 
14
12
  const projectDir = resolve(process.cwd(), options.dir)
@@ -35,6 +35,16 @@ export const createReadme = async (logger, dir = '.') => {
35
35
  logger.debug(`${readmeFileName} successfully created.`)
36
36
  }
37
37
 
38
+ export const getServicesToCompose = (servicesNames) => {
39
+ return {
40
+ type: 'checkbox',
41
+ name: 'servicesToCompose',
42
+ message: 'Which services do you want to expose via Platformatic Composer?',
43
+ choices: servicesNames,
44
+ default: []
45
+ }
46
+ }
47
+
38
48
  const createPlatformaticComposer = async (_args, opts) => {
39
49
  const logger = opts.logger || pino(pretty({
40
50
  translateTime: 'SYS:HH:MM:ss',
@@ -55,14 +65,26 @@ const createPlatformaticComposer = async (_args, opts) => {
55
65
  const pkgManager = getPkgManager()
56
66
 
57
67
  const projectDir = opts.dir || await askDir(logger, '.')
68
+ const isRuntimeContext = opts.isRuntimeContext || false
58
69
 
59
70
  const toAsk = [getPort(args.port)]
60
71
 
72
+ if (isRuntimeContext) {
73
+ const servicesNames = opts.runtimeContext.servicesNames.filter(
74
+ (serviceName) => serviceName !== opts.serviceName
75
+ )
76
+ toAsk.push(getServicesToCompose(servicesNames))
77
+ }
78
+
61
79
  if (!opts.skipPackageJson) {
62
80
  toAsk.push(getRunPackageManagerInstall(pkgManager))
63
81
  }
64
82
 
65
- const { runPackageManagerInstall, port } = await inquirer.prompt(toAsk)
83
+ const {
84
+ runPackageManagerInstall,
85
+ servicesToCompose,
86
+ port
87
+ } = await inquirer.prompt(toAsk)
66
88
 
67
89
  // Create the project directory
68
90
  await mkdir(projectDir, { recursive: true })
@@ -72,7 +94,14 @@ const createPlatformaticComposer = async (_args, opts) => {
72
94
  port
73
95
  }
74
96
 
75
- const env = await createComposer(params, logger, projectDir, version)
97
+ const env = await createComposer(
98
+ params,
99
+ logger,
100
+ projectDir,
101
+ version,
102
+ isRuntimeContext,
103
+ servicesToCompose
104
+ )
76
105
 
77
106
  const fastifyVersion = await getDependencyVersion('fastify')
78
107
 
@@ -3,7 +3,7 @@ import { findComposerConfigFile, isFileAccessible } from '../utils.mjs'
3
3
  import { join } from 'path'
4
4
  import * as desm from 'desm'
5
5
 
6
- function generateConfig (version) {
6
+ function generateConfig (version, isRuntimeContext, servicesToCompose) {
7
7
  const config = {
8
8
  $schema: `https://platformatic.dev/schemas/v${version}/composer`,
9
9
  server: {
@@ -26,21 +26,45 @@ function generateConfig (version) {
26
26
  watch: true
27
27
  }
28
28
 
29
+ if (isRuntimeContext) {
30
+ config.composer.services = servicesToCompose.map((serviceName) => {
31
+ return {
32
+ id: serviceName,
33
+ openapi: {
34
+ url: '/documentation/json',
35
+ prefix: `/${serviceName}`
36
+ }
37
+ }
38
+ })
39
+ }
40
+
29
41
  return config
30
42
  }
31
43
 
32
- function generateEnv (hostname, port) {
33
- const env = `\
44
+ function generateEnv (isRuntimeContext, hostname, port) {
45
+ let env = `\
34
46
  PLT_SERVER_HOSTNAME=${hostname}
35
47
  PORT=${port}
36
48
  PLT_SERVER_LOGGER_LEVEL=info
49
+ `
50
+
51
+ if (!isRuntimeContext) {
52
+ env += `\
37
53
  PLT_EXAMPLE_ORIGIN=
38
54
  `
55
+ }
39
56
 
40
57
  return env
41
58
  }
42
59
 
43
- async function createComposer ({ hostname, port }, logger, currentDir = process.cwd(), version) {
60
+ async function createComposer (
61
+ { hostname, port },
62
+ logger,
63
+ currentDir = process.cwd(),
64
+ version,
65
+ isRuntimeContext = false,
66
+ servicesToCompose = []
67
+ ) {
44
68
  if (!version) {
45
69
  const pkg = await readFile(desm.join(import.meta.url, '..', '..', 'package.json'))
46
70
  version = JSON.parse(pkg).version
@@ -48,11 +72,11 @@ async function createComposer ({ hostname, port }, logger, currentDir = process.
48
72
  const accessibleConfigFilename = await findComposerConfigFile(currentDir)
49
73
 
50
74
  if (accessibleConfigFilename === undefined) {
51
- const config = generateConfig(version)
75
+ const config = generateConfig(version, isRuntimeContext, servicesToCompose)
52
76
  await writeFile(join(currentDir, 'platformatic.composer.json'), JSON.stringify(config, null, 2))
53
77
  logger.info('Configuration file platformatic.composer.json successfully created.')
54
78
 
55
- const env = generateEnv(hostname, port)
79
+ const env = generateEnv(isRuntimeContext, hostname, port)
56
80
  const envFileExists = await isFileAccessible('.env', currentDir)
57
81
  await appendFile(join(currentDir, '.env'), env)
58
82
  await writeFile(join(currentDir, '.env.sample'), env)
@@ -351,7 +351,7 @@ export async function createDB ({ hostname, database = 'sqlite', port, migration
351
351
  if (createMigrations) {
352
352
  const isMigrationFolderExists = await isFileAccessible(migrationsFolderName, currentDir)
353
353
  if (!isMigrationFolderExists) {
354
- await mkdir(join(currentDir, migrationsFolderName))
354
+ await mkdir(join(currentDir, migrationsFolderName), { recursive: true })
355
355
  logger.info(`Migrations folder ${migrationsFolderName} successfully created.`)
356
356
  } else {
357
357
  logger.info(`Migrations folder ${migrationsFolderName} found, skipping creation of migrations folder.`)
package/src/ghaction.mjs CHANGED
@@ -59,12 +59,29 @@ ${envString}
59
59
  run: npm run build`
60
60
  : ''}
61
61
  - name: Deploy project
62
+ id: deploy-project
62
63
  uses: platformatic/onestep@latest
63
64
  with:
64
65
  github_token: \${{ secrets.GITHUB_TOKEN }}
65
66
  platformatic_workspace_id: \${{ secrets.PLATFORMATIC_DYNAMIC_WORKSPACE_ID }}
66
67
  platformatic_workspace_key: \${{ secrets.PLATFORMATIC_DYNAMIC_WORKSPACE_API_KEY }}
67
68
  platformatic_config_path: ${config}
69
+ outputs:
70
+ deployment_id: \${{ steps.deploy-project.outputs.deployment_id }}
71
+ calculate_risk:
72
+ permissions:
73
+ contents: read
74
+ pull-requests: write
75
+ needs: build_and_deploy
76
+ runs-on: ubuntu-latest
77
+ steps:
78
+ - name: Calculate risk
79
+ uses: platformatic/onestep/actions/calculate-risk@latest
80
+ with:
81
+ github_token: \${{ secrets.GITHUB_TOKEN }}
82
+ platformatic_workspace_id: \${{ secrets.PLATFORMATIC_DYNAMIC_WORKSPACE_ID }}
83
+ platformatic_workspace_key: \${{ secrets.PLATFORMATIC_DYNAMIC_WORKSPACE_API_KEY }}
84
+ platformatic_deployment_id: \${{ needs.build_and_deploy.outputs.deployment_id }}
68
85
  `
69
86
  }
70
87
 
@@ -50,7 +50,7 @@ export async function createPlatformaticRuntime (_args) {
50
50
  // Create the project directory
51
51
  await mkdir(projectDir, { recursive: true })
52
52
 
53
- const baseServicesDir = join(relative(process.cwd(), projectDir), 'library-app/services')
53
+ const baseServicesDir = join(relative(process.cwd(), projectDir), 'services')
54
54
  const servicesDir = await askDir(logger, baseServicesDir, 'Where would you like to load your services from?')
55
55
 
56
56
  const { runPackageManagerInstall } = await inquirer.prompt([
@@ -151,12 +151,17 @@ export async function createRuntimeService ({ servicesDir, names, logger }) {
151
151
 
152
152
  await chooseKind([], {
153
153
  skip: 'runtime',
154
+ serviceName: name,
154
155
  dir: serviceDir,
155
156
  logger,
156
157
  skipGitHubActions: true,
157
158
  skipPackageJson: true,
158
159
  skipGitignore: true,
159
- port: '0'
160
+ port: '0',
161
+ isRuntimeContext: true,
162
+ runtimeContext: {
163
+ servicesNames: names
164
+ }
160
165
  })
161
166
 
162
167
  return true
package/src/utils.mjs CHANGED
@@ -61,19 +61,6 @@ export async function isDirectoryWriteable (directory) {
61
61
  }
62
62
  }
63
63
 
64
- export const validatePath = async projectPath => {
65
- // if the folder exists, is OK:
66
- const projectDir = resolve(projectPath)
67
- const canAccess = await isDirectoryWriteable(projectDir)
68
- if (canAccess) {
69
- return true
70
- }
71
- // if the folder does not exist, check if the parent folder exists:
72
- const parentDir = dirname(projectDir)
73
- const canAccessParent = await isDirectoryWriteable(parentDir)
74
- return canAccessParent
75
- }
76
-
77
64
  export const findDBConfigFile = async (directory) => (ConfigManager.findConfigFile(directory, 'db'))
78
65
  export const findServiceConfigFile = async (directory) => (ConfigManager.findConfigFile(directory, 'service'))
79
66
  export const findComposerConfigFile = async (directory) => (ConfigManager.findConfigFile(directory, 'composer'))
@@ -1,84 +0,0 @@
1
- import { test } from 'tap'
2
- import { getRunPackageManagerInstall, getUseTypescript, getPort, getOverwriteReadme } from '../src/cli-options.mjs'
3
-
4
- test('getRunPackageManagerInstall', async ({ same }) => {
5
- same(
6
- getRunPackageManagerInstall('npm'),
7
- {
8
- type: 'list',
9
- name: 'runPackageManagerInstall',
10
- message: 'Do you want to run npm install?',
11
- default: true,
12
- choices: [{ name: 'yes', value: true }, { name: 'no', value: false }]
13
- }
14
- )
15
- })
16
-
17
- test('getUseTypescript', async ({ same }) => {
18
- same(
19
- getUseTypescript(true),
20
- {
21
- type: 'list',
22
- when: false,
23
- name: 'useTypescript',
24
- message: 'Do you want to use TypeScript?',
25
- default: true,
26
- choices: [{ name: 'yes', value: true }, { name: 'no', value: false }]
27
- }
28
- )
29
- })
30
-
31
- test('getOverwriteReadme', async ({ same }) => {
32
- same(
33
- getOverwriteReadme(),
34
- {
35
- type: 'list',
36
- name: 'shouldReplace',
37
- message: 'Do you want to overwrite the existing README.md?',
38
- default: true,
39
- choices: [{ name: 'yes', value: true }, { name: 'no', value: false }]
40
- }
41
- )
42
- })
43
-
44
- test('getPort', async ({ same }) => {
45
- same(
46
- getPort(undefined),
47
- {
48
- type: 'input',
49
- name: 'port',
50
- message: 'What port do you want to use?',
51
- default: 3042
52
- }
53
- )
54
-
55
- same(
56
- getPort(undefined),
57
- {
58
- type: 'input',
59
- name: 'port',
60
- message: 'What port do you want to use?',
61
- default: 3043
62
- }
63
- )
64
-
65
- same(
66
- getPort(1234),
67
- {
68
- type: 'input',
69
- name: 'port',
70
- message: 'What port do you want to use?',
71
- default: 1234
72
- }
73
- )
74
-
75
- same(
76
- getPort(undefined),
77
- {
78
- type: 'input',
79
- name: 'port',
80
- message: 'What port do you want to use?',
81
- default: 3044
82
- }
83
- )
84
- })
@@ -1,75 +0,0 @@
1
- import createComposer from '../../src/composer/create-composer.mjs'
2
- import { test, beforeEach, afterEach } from 'tap'
3
- import { tmpdir } from 'os'
4
- import { mkdtempSync, rmSync, readFileSync, writeFileSync } from 'fs'
5
- import { join } from 'path'
6
- import dotenv from 'dotenv'
7
-
8
- const base = tmpdir()
9
- let tmpDir
10
- let log = []
11
- beforeEach(() => {
12
- tmpDir = mkdtempSync(join(base, 'test-create-platformatic-'))
13
- })
14
-
15
- afterEach(() => {
16
- log = []
17
- rmSync(tmpDir, { recursive: true, force: true })
18
- process.env = {}
19
- })
20
-
21
- const fakeLogger = {
22
- debug: msg => log.push(msg),
23
- info: msg => log.push(msg)
24
- }
25
-
26
- test('creates composer', async ({ equal, same, ok }) => {
27
- const params = {
28
- hostname: 'myhost',
29
- port: 6666,
30
- typescript: false
31
- }
32
-
33
- await createComposer(params, fakeLogger, tmpDir)
34
-
35
- const pathToComposerConfigFile = join(tmpDir, 'platformatic.composer.json')
36
- const composerConfigFile = readFileSync(pathToComposerConfigFile, 'utf8')
37
- const composerConfig = JSON.parse(composerConfigFile)
38
- const { server, composer } = composerConfig
39
-
40
- equal(server.hostname, '{PLT_SERVER_HOSTNAME}')
41
- equal(server.port, '{PORT}')
42
-
43
- const pathToDbEnvFile = join(tmpDir, '.env')
44
- dotenv.config({ path: pathToDbEnvFile })
45
- equal(process.env.PLT_SERVER_HOSTNAME, 'myhost')
46
- equal(process.env.PORT, '6666')
47
- process.env = {}
48
-
49
- const pathToDbEnvSampleFile = join(tmpDir, '.env.sample')
50
- dotenv.config({ path: pathToDbEnvSampleFile })
51
- equal(process.env.PLT_SERVER_HOSTNAME, 'myhost')
52
- equal(process.env.PORT, '6666')
53
-
54
- same(composer, {
55
- services: [{
56
- id: 'example',
57
- origin: '{PLT_EXAMPLE_ORIGIN}',
58
- openapi: {
59
- url: '/documentation/json'
60
- }
61
- }],
62
- refreshTimeout: 1000
63
- })
64
- })
65
-
66
- test('creates project with configuration already present', async ({ ok }) => {
67
- const pathToComposerConfigFileOld = join(tmpDir, 'platformatic.composer.json')
68
- writeFileSync(pathToComposerConfigFileOld, JSON.stringify({ test: 'test' }))
69
- const params = {
70
- hostname: 'myhost',
71
- port: 6666
72
- }
73
- await createComposer(params, fakeLogger, tmpDir)
74
- ok(log.includes('Configuration file platformatic.composer.json found, skipping creation of configuration file.'))
75
- })
@@ -1,35 +0,0 @@
1
- import { test, beforeEach, afterEach } from 'tap'
2
- import { tmpdir } from 'os'
3
- import { isFileAccessible } from '../src/utils.mjs'
4
- import { createGitignore } from '../src/create-gitignore.mjs'
5
- import { mkdtempSync, rmSync, writeFileSync } from 'fs'
6
- import { join } from 'path'
7
-
8
- let log = ''
9
- const fakeLogger = {
10
- debug: msg => { log = msg }
11
- }
12
-
13
- let tmpDir
14
- beforeEach(() => {
15
- log = ''
16
- tmpDir = mkdtempSync(join(tmpdir(), 'test-create-platformatic-'))
17
- })
18
-
19
- afterEach(() => {
20
- rmSync(tmpDir, { recursive: true, force: true })
21
- })
22
-
23
- test('creates gitignore file', async ({ end, equal }) => {
24
- await createGitignore(fakeLogger, tmpDir)
25
- equal(log, `Gitignore file ${join(tmpDir, '.gitignore')} successfully created.`)
26
- const accessible = await isFileAccessible(join(tmpDir, '.gitignore'))
27
- equal(accessible, true)
28
- })
29
-
30
- test('do not create gitignore file because already present', async ({ end, equal }) => {
31
- const gitignore = join(tmpDir, '.gitignore')
32
- writeFileSync(gitignore, 'TEST')
33
- await createGitignore(fakeLogger, tmpDir)
34
- equal(log, `Gitignore file ${join(tmpDir, '.gitignore')} found, skipping creation of gitignore file.`)
35
- })
@@ -1,81 +0,0 @@
1
- import { test, beforeEach, afterEach } from 'tap'
2
- import { tmpdir } from 'os'
3
- import { isFileAccessible } from '../src/utils.mjs'
4
- import { createPackageJson } from '../src/create-package-json.mjs'
5
- import { mkdtempSync, rmSync, writeFileSync, readFileSync } from 'fs'
6
- import { join } from 'path'
7
-
8
- let log = ''
9
- const fakeLogger = {
10
- debug: msg => { log = msg }
11
- }
12
-
13
- let tmpDir
14
- beforeEach(() => {
15
- log = ''
16
- tmpDir = mkdtempSync(join(tmpdir(), 'test-create-platformatic-'))
17
- })
18
-
19
- afterEach(() => {
20
- rmSync(tmpDir, { recursive: true, force: true })
21
- })
22
-
23
- test('creates package.json file for db project', async ({ equal }) => {
24
- const version = '1.2.3'
25
- const fastifyVersion = '4.5.6'
26
- const addTSBuild = false
27
- const scripts = {}
28
- const dependencies = {
29
- '@platformatic/db': `^${version}`
30
- }
31
- await createPackageJson(version, fastifyVersion, fakeLogger, tmpDir, addTSBuild, scripts, dependencies)
32
- equal(log, `${join(tmpDir, 'package.json')} successfully created.`)
33
- const accessible = await isFileAccessible(join(tmpDir, 'package.json'))
34
- equal(accessible, true)
35
- const packageJson = JSON.parse(readFileSync(join(tmpDir, 'package.json')))
36
- equal(packageJson.scripts.start, 'platformatic start')
37
- equal(packageJson.scripts.build, undefined)
38
- equal(packageJson.dependencies.platformatic, `^${version}`)
39
- equal(packageJson.dependencies['@platformatic/db'], `^${version}`)
40
- equal(packageJson.devDependencies.fastify, `^${fastifyVersion}`)
41
- })
42
-
43
- test('creates package.json file for service project', async ({ equal }) => {
44
- const version = '1.2.3'
45
- const fastifyVersion = '4.5.6'
46
- const addTSBuild = false
47
- await createPackageJson(version, fastifyVersion, fakeLogger, tmpDir, addTSBuild)
48
- equal(log, `${join(tmpDir, 'package.json')} successfully created.`)
49
- const accessible = await isFileAccessible(join(tmpDir, 'package.json'))
50
- equal(accessible, true)
51
- const packageJson = JSON.parse(readFileSync(join(tmpDir, 'package.json')))
52
- equal(packageJson.scripts.start, 'platformatic start')
53
- equal(packageJson.dependencies.platformatic, `^${version}`)
54
- equal(packageJson.devDependencies.fastify, `^${fastifyVersion}`)
55
- })
56
-
57
- test('do not create package.json file because already present', async ({ equal }) => {
58
- const version = '1.2.3'
59
- const fastifyVersion = '4.5.6'
60
- const addTSBuild = false
61
- const packagejson = join(tmpDir, 'package.json')
62
- writeFileSync(packagejson, 'TEST')
63
- await createPackageJson(version, fastifyVersion, fakeLogger, tmpDir, addTSBuild)
64
- equal(log, `${join(tmpDir, 'package.json')} found, skipping creation of package.json file.`)
65
- })
66
-
67
- test('creates package.json file with TS build', async ({ equal }) => {
68
- const version = '1.2.3'
69
- const fastifyVersion = '4.5.6'
70
- const addTSBuild = true
71
- await createPackageJson(version, fastifyVersion, fakeLogger, tmpDir, addTSBuild)
72
- equal(log, `${join(tmpDir, 'package.json')} successfully created.`)
73
- const accessible = await isFileAccessible(join(tmpDir, 'package.json'))
74
- equal(accessible, true)
75
- const packageJson = JSON.parse(readFileSync(join(tmpDir, 'package.json')))
76
- equal(packageJson.scripts.start, 'platformatic start')
77
- equal(packageJson.scripts.clean, 'rm -fr ./dist')
78
- equal(packageJson.scripts.build, 'platformatic compile')
79
- equal(packageJson.dependencies.platformatic, `^${version}`)
80
- equal(packageJson.devDependencies.fastify, `^${fastifyVersion}`)
81
- })