create-platformatic 0.28.1 → 0.30.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.
@@ -36,3 +36,6 @@ export {
36
36
  createStaticWorkspaceGHAction,
37
37
  createDynamicWorkspaceGHAction
38
38
  } from './src/ghaction.mjs'
39
+
40
+ export { createGitignore, 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": "0.28.1",
3
+ "version": "0.30.0",
4
4
  "description": "Create platformatic-db interactive tool",
5
5
  "repository": {
6
6
  "type": "git",
@@ -17,6 +17,7 @@
17
17
  "dependencies": {
18
18
  "boring-name-generator": "^1.0.3",
19
19
  "chalk": "^5.2.0",
20
+ "columnify": "^1.6.0",
20
21
  "commist": "^3.2.0",
21
22
  "desm": "^1.3.0",
22
23
  "es-main": "^1.2.0",
@@ -33,7 +34,7 @@
33
34
  "semver": "^7.5.1",
34
35
  "undici": "^5.22.1",
35
36
  "which": "^3.0.1",
36
- "@platformatic/config": "0.28.1"
37
+ "@platformatic/config": "0.30.0"
37
38
  },
38
39
  "devDependencies": {
39
40
  "ajv": "^8.12.0",
@@ -45,11 +46,11 @@
45
46
  "standard": "^17.1.0",
46
47
  "tap": "^16.3.6",
47
48
  "yaml": "^2.3.1",
48
- "@platformatic/db": "0.28.1",
49
- "@platformatic/service": "0.28.1"
49
+ "@platformatic/db": "0.30.0",
50
+ "@platformatic/service": "0.30.0"
50
51
  },
51
52
  "scripts": {
52
- "test": "standard | snazzy && cross-env NODE_OPTIONS=\"--loader=esmock --no-warnings\" c8 --100 tap --no-coverage test/*test.mjs test/*/*test.mjs",
53
+ "test": "standard | snazzy && cross-env NODE_OPTIONS=\"--loader=esmock --no-warnings\" c8 tap --no-coverage test/*test.mjs test/*/*test.mjs",
53
54
  "lint": "standard | snazzy"
54
55
  }
55
56
  }
@@ -31,7 +31,11 @@ tags
31
31
  # clinicjs
32
32
  .clinic/
33
33
  `
34
-
34
+ /**
35
+ * Creates a standard Platformatic app .gitignore file
36
+ * @param {import('pino').BaseLogger} logger Logger Interface
37
+ * @param {string} dir Target directory
38
+ */
35
39
  export const createGitignore = async (logger, dir = '.') => {
36
40
  const gitignoreFileName = join(dir, '.gitignore')
37
41
  const isGitignoreExists = await isFileAccessible(gitignoreFileName)
@@ -23,6 +23,15 @@ const packageJsonTemplate = (addTSBuild = false) => (`\
23
23
  }
24
24
  }`)
25
25
 
26
+ /**
27
+ * Creates a Platformatic app package.json file
28
+ * @param {string} platVersion Platformatic Version
29
+ * @param {string} fastifyVersion Fastify Version
30
+ * @param {import('pino').BaseLogger} logger Logger Interface
31
+ * @param {string} dir Target directory where to create the file
32
+ * @param {boolean} addTSBuild Whether to add TS Build or not
33
+ * @param {object} scripts Package.json scripts list
34
+ */
26
35
  export const createPackageJson = async (platVersion, fastifyVersion, logger, dir, addTSBuild = false, scripts = {}) => {
27
36
  const packageJsonFileName = join(dir, 'package.json')
28
37
  const isPackageJsonExists = await isFileAccessible(packageJsonFileName)
@@ -11,11 +11,25 @@ import pino from 'pino'
11
11
  import pretty from 'pino-pretty'
12
12
  import { execa } from 'execa'
13
13
  import ora from 'ora'
14
- import createDB from './create-db.mjs'
14
+ import { getConnectionString, createDB } from './create-db.mjs'
15
15
  import askDir from '../ask-dir.mjs'
16
16
  import { askDynamicWorkspaceCreateGHAction, askStaticWorkspaceGHAction } from '../ghaction.mjs'
17
17
  import { getRunPackageManagerInstall, getUseTypescript, getPort, getOverwriteReadme } from '../cli-options.mjs'
18
18
 
19
+ const databases = [{
20
+ value: 'sqlite',
21
+ name: 'SQLite'
22
+ }, {
23
+ value: 'postgres',
24
+ name: 'PostgreSQL'
25
+ }, {
26
+ value: 'mysql',
27
+ name: 'MySQL'
28
+ }, {
29
+ value: 'mariadb',
30
+ name: 'MariaDB'
31
+ }]
32
+
19
33
  export const createReadme = async (logger, dir = '.') => {
20
34
  const readmeFileName = join(dir, 'README.md')
21
35
  let isReadmeExists = await isFileAccessible(readmeFileName)
@@ -70,6 +84,48 @@ const createPlatformaticDB = async (_args, opts) => {
70
84
  const pkgManager = getPkgManager()
71
85
  const projectDir = opts.dir || await askDir(logger, '.')
72
86
 
87
+ const { database } = await inquirer.prompt({
88
+ type: 'list',
89
+ name: 'database',
90
+ message: 'What database do you want to use?',
91
+ default: args.database,
92
+ choices: databases
93
+ })
94
+
95
+ let connectionString = getConnectionString(database)
96
+
97
+ while (true) {
98
+ const pickConnectionString = await inquirer.prompt({
99
+ type: 'expand',
100
+ name: 'edit',
101
+ message: `Do you want to use the connection string "${connectionString}"?`,
102
+ choices: [
103
+ {
104
+ key: 'y',
105
+ name: 'Confirm',
106
+ value: false
107
+ },
108
+ {
109
+ key: 'e',
110
+ name: 'Edit',
111
+ value: true
112
+ }
113
+ ]
114
+ })
115
+
116
+ if (pickConnectionString.edit) {
117
+ const answers = await inquirer.prompt({
118
+ type: 'editor',
119
+ name: 'connectionString',
120
+ message: 'Edit the connection string',
121
+ default: connectionString
122
+ })
123
+ connectionString = answers.connectionString.trim()
124
+ } else {
125
+ break
126
+ }
127
+ }
128
+
73
129
  const wizardOptions = await inquirer.prompt([{
74
130
  type: 'list',
75
131
  name: 'defaultMigrations',
@@ -97,7 +153,8 @@ const createPlatformaticDB = async (_args, opts) => {
97
153
  const params = {
98
154
  hostname: args.hostname,
99
155
  port: wizardOptions.port,
100
- database: args.database,
156
+ database,
157
+ connectionString,
101
158
  migrations: wizardOptions.defaultMigrations ? args.migrations : '',
102
159
  plugin: generatePlugin,
103
160
  types: useTypes,
@@ -162,8 +219,13 @@ const createPlatformaticDB = async (_args, opts) => {
162
219
  if (applyMigrations) {
163
220
  const spinner = ora('Applying migrations...').start()
164
221
  // We need to apply migrations using the platformatic installed in the project
165
- await execa(pkgManager, ['exec', 'platformatic', 'db', 'migrations', 'apply'], { cwd: projectDir })
166
- spinner.succeed('...done!')
222
+ try {
223
+ await execa(pkgManager, ['exec', 'platformatic', 'db', 'migrations', 'apply'], { cwd: projectDir })
224
+ spinner.succeed('...done!')
225
+ } catch (err) {
226
+ logger.trace({ err })
227
+ spinner.fail('...failed! Try again by running "platformatic db migrations apply"')
228
+ }
167
229
  }
168
230
  }
169
231
  if (generatePlugin) {
@@ -177,8 +239,13 @@ const createPlatformaticDB = async (_args, opts) => {
177
239
 
178
240
  if (generateTypes) {
179
241
  const spinner = ora('Generating types...').start()
180
- await execa(pkgManager, ['exec', 'platformatic', 'db', 'types'], { cwd: projectDir })
181
- spinner.succeed('...done!')
242
+ try {
243
+ await execa(pkgManager, ['exec', 'platformatic', 'db', 'types'], { cwd: projectDir })
244
+ spinner.succeed('...done!')
245
+ } catch (err) {
246
+ logger.trace({ err })
247
+ spinner.fail('...failed! Try again by running "platformatic db types"')
248
+ }
182
249
  }
183
250
  }
184
251
  }
@@ -1,49 +1,37 @@
1
1
  import { writeFile, mkdir, appendFile } from 'fs/promises'
2
2
  import { join, relative, resolve } from 'path'
3
3
  import { findDBConfigFile, isFileAccessible } from '../utils.mjs'
4
+ import { getTsConfig } from '../get-tsconfig.mjs'
4
5
 
5
6
  const connectionStrings = {
6
- postgres: 'postgres://postgres:postgres@localhost:5432/postgres',
7
+ postgres: 'postgres://postgres:postgres@127.0.0.1:5432/postgres',
7
8
  sqlite: 'sqlite://./db.sqlite',
8
- mysql: 'mysql://root@localhost:3306/graph',
9
- mysql8: 'mysql://root@localhost:3308/graph',
10
- mariadb: 'mysql://root@localhost:3307/graph'
9
+ mysql: 'mysql://root@127.0.0.1:3306/platformatic',
10
+ mariadb: 'mysql://root@127.0.0.1:3306/platformatic'
11
11
  }
12
12
 
13
- const moviesMigrationDo = `
13
+ const moviesMigrationDo = (database) => {
14
+ const key = {
15
+ postgres: 'SERIAL',
16
+ sqlite: 'INTEGER',
17
+ mysql: 'INTEGER UNSIGNED AUTO_INCREMENT',
18
+ mariadb: 'INTEGER UNSIGNED AUTO_INCREMENT'
19
+ }
20
+
21
+ return `
14
22
  -- Add SQL in this file to create the database tables for your API
15
23
  CREATE TABLE IF NOT EXISTS movies (
16
- id INTEGER PRIMARY KEY,
24
+ id ${key[database]} PRIMARY KEY,
17
25
  title TEXT NOT NULL
18
26
  );
19
27
  `
28
+ }
20
29
 
21
30
  const moviesMigrationUndo = `
22
31
  -- Add SQL in this file to drop the database tables
23
32
  DROP TABLE movies;
24
33
  `
25
34
 
26
- function getTsConfig (outDir) {
27
- return {
28
- compilerOptions: {
29
- module: 'commonjs',
30
- esModuleInterop: true,
31
- target: 'es6',
32
- sourceMap: true,
33
- pretty: true,
34
- noEmitOnError: true,
35
- outDir
36
- },
37
- watchOptions: {
38
- watchFile: 'fixedPollingInterval',
39
- watchDirectory: 'fixedPollingInterval',
40
- fallbackPolling: 'dynamicPriority',
41
- synchronousWatchDirectory: true,
42
- excludeDirectories: ['**/node_modules', outDir]
43
- }
44
- }
45
- }
46
-
47
35
  const getPluginName = (isTypescript) => isTypescript === true ? 'plugin.ts' : 'plugin.js'
48
36
  const TS_OUT_DIR = 'dist'
49
37
 
@@ -86,20 +74,29 @@ function generateConfig (migrations, plugin, types, typescript, version) {
86
74
  }
87
75
 
88
76
  if (typescript === true) {
89
- config.plugins.typescript = true
77
+ config.plugins.typescript = '{PLT_TYPESCRIPT}'
90
78
  }
91
79
 
92
80
  return config
93
81
  }
94
82
 
95
- function generateEnv (hostname, port, database) {
96
- const connectionString = connectionStrings[database]
97
- const env = `\
83
+ function generateEnv (hostname, port, connectionString, typescript) {
84
+ let env = `\
98
85
  PLT_SERVER_HOSTNAME=${hostname}
99
86
  PORT=${port}
100
87
  PLT_SERVER_LOGGER_LEVEL=info
101
88
  DATABASE_URL=${connectionString}
102
89
  `
90
+
91
+ if (typescript === true) {
92
+ env += `\
93
+
94
+ # Set to false to disable automatic typescript compilation.
95
+ # Changing this setting is needed for production
96
+ PLT_TYPESCRIPT=true
97
+ `
98
+ }
99
+
103
100
  return env
104
101
  }
105
102
 
@@ -135,7 +132,12 @@ async function generatePluginWithTypesSupport (logger, currentDir, isTypescript)
135
132
  logger.info(`Plugin file created at ${relative(currentDir, pluginPath)}`)
136
133
  }
137
134
 
138
- async function createDB ({ hostname, database = 'sqlite', port, migrations = 'migrations', plugin = true, types = true, typescript = false }, logger, currentDir, version) {
135
+ export function getConnectionString (database) {
136
+ return connectionStrings[database]
137
+ }
138
+
139
+ export async function createDB ({ hostname, database = 'sqlite', port, migrations = 'migrations', plugin = true, types = true, typescript = false, connectionString }, logger, currentDir, version) {
140
+ connectionString = connectionString || getConnectionString(database)
139
141
  const createMigrations = !!migrations // If we don't define a migrations folder, we don't create it
140
142
  const accessibleConfigFilename = await findDBConfigFile(currentDir)
141
143
  if (accessibleConfigFilename === undefined) {
@@ -143,7 +145,7 @@ async function createDB ({ hostname, database = 'sqlite', port, migrations = 'mi
143
145
  await writeFile(join(currentDir, 'platformatic.db.json'), JSON.stringify(config, null, 2))
144
146
  logger.info('Configuration file platformatic.db.json successfully created.')
145
147
 
146
- const env = generateEnv(hostname, port, database)
148
+ const env = generateEnv(hostname, port, connectionString, typescript)
147
149
  const envFileExists = await isFileAccessible('.env', currentDir)
148
150
  await appendFile(join(currentDir, '.env'), env)
149
151
  await writeFile(join(currentDir, '.env.sample'), env)
@@ -175,7 +177,7 @@ async function createDB ({ hostname, database = 'sqlite', port, migrations = 'mi
175
177
  const isMigrationFileDoExists = await isFileAccessible(migrationFilePathDo)
176
178
  const isMigrationFileUndoExists = await isFileAccessible(migrationFilePathUndo)
177
179
  if (!isMigrationFileDoExists && createMigrations) {
178
- await writeFile(migrationFilePathDo, moviesMigrationDo)
180
+ await writeFile(migrationFilePathDo, moviesMigrationDo(database))
179
181
  logger.info(`Migration file ${migrationFileNameDo} successfully created.`)
180
182
  if (!isMigrationFileUndoExists) {
181
183
  await writeFile(migrationFilePathUndo, moviesMigrationUndo)
@@ -202,7 +204,7 @@ async function createDB ({ hostname, database = 'sqlite', port, migrations = 'mi
202
204
  }
203
205
 
204
206
  return {
205
- DATABASE_URL: connectionStrings[database],
207
+ DATABASE_URL: connectionString,
206
208
  PLT_SERVER_LOGGER_LEVEL: 'info',
207
209
  PORT: port,
208
210
  PLT_SERVER_HOSTNAME: hostname
@@ -0,0 +1,21 @@
1
+ export function getTsConfig (outDir) {
2
+ return {
3
+ compilerOptions: {
4
+ module: 'commonjs',
5
+ esModuleInterop: true,
6
+ target: 'es2020',
7
+ sourceMap: true,
8
+ pretty: true,
9
+ noEmitOnError: true,
10
+ incremental: true,
11
+ outDir
12
+ },
13
+ watchOptions: {
14
+ watchFile: 'fixedPollingInterval',
15
+ watchDirectory: 'fixedPollingInterval',
16
+ fallbackPolling: 'dynamicPriority',
17
+ synchronousWatchDirectory: true,
18
+ excludeDirectories: ['**/node_modules', outDir]
19
+ }
20
+ }
21
+ }
package/src/ghaction.mjs CHANGED
@@ -2,12 +2,36 @@ import { join } from 'path'
2
2
  import inquirer from 'inquirer'
3
3
  import { isFileAccessible } from './utils.mjs'
4
4
  import { writeFile, mkdir } from 'fs/promises'
5
+ import columnify from 'columnify'
6
+ function envAsString (env) {
7
+ return Object.keys(env).reduce((acc, key) => {
8
+ if (key === 'DATABASE_URL') {
9
+ acc += ` ${key}: \${{ secrets.DATABASE_URL }}\n`
10
+ } else {
11
+ acc += ` ${key}: ${env[key]} \n`
12
+ }
5
13
 
6
- export const dynamicWorkspaceGHTemplate = (env, config, buildTS = false) => {
7
- const envAsStr = Object.keys(env).reduce((acc, key) => {
8
- acc += ` ${key}: ${env[key]} \n`
9
14
  return acc
10
15
  }, '')
16
+ }
17
+
18
+ function formatSecretsToAdd (secrets) {
19
+ const output = columnify(secrets, {
20
+ showHeaders: false,
21
+ columnSplitter: ': ',
22
+ config: {
23
+ key: {
24
+ align: 'right'
25
+ },
26
+ value: {
27
+ align: 'left'
28
+ }
29
+ }
30
+ })
31
+ return output
32
+ }
33
+ export const dynamicWorkspaceGHTemplate = (env, config, buildTS = false) => {
34
+ const envString = envAsString(env)
11
35
 
12
36
  return `name: Deploy Platformatic application to the cloud
13
37
  on:
@@ -39,15 +63,12 @@ jobs:
39
63
  platformatic_workspace_key: \${{ secrets.PLATFORMATIC_DYNAMIC_WORKSPACE_API_KEY }}
40
64
  platformatic_config_path: ${config}
41
65
  env:
42
- ${envAsStr}
66
+ ${envString}
43
67
  `
44
68
  }
45
69
 
46
70
  export const staticWorkspaceGHTemplate = (env, config, buildTS = false) => {
47
- const envAsStr = Object.keys(env).reduce((acc, key) => {
48
- acc += ` ${key}: ${env[key]} \n`
49
- return acc
50
- }, '')
71
+ const envString = envAsString(env)
51
72
 
52
73
  return `name: Deploy Platformatic application to the cloud
53
74
  on:
@@ -80,7 +101,7 @@ jobs:
80
101
  platformatic_workspace_key: \${{ secrets.PLATFORMATIC_STATIC_WORKSPACE_API_KEY }}
81
102
  platformatic_config_path: ${config}
82
103
  env:
83
- ${envAsStr}
104
+ ${envString}
84
105
  `
85
106
  }
86
107
 
@@ -91,7 +112,13 @@ export const createDynamicWorkspaceGHAction = async (logger, env, config, projec
91
112
  if (!isGithubActionExists) {
92
113
  await mkdir(join(projectDir, '.github', 'workflows'), { recursive: true })
93
114
  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.')
115
+ logger.info('Github action successfully created, please add the following secrets as repository secrets: ')
116
+ const secretsString = formatSecretsToAdd({
117
+ PLATFORMATIC_DYNAMIC_WORKSPACE_ID: 'your workspace id',
118
+ PLATFORMATIC_DYNAMIC_WORKSPACE_API_KEY: 'your workspace API key',
119
+ DATABASE_URL: env.DATABASE_URL
120
+ })
121
+ logger.info(`\n ${secretsString}`)
95
122
  const isGitDir = await isFileAccessible('.git', projectDir)
96
123
  if (!isGitDir) {
97
124
  logger.warn('No git repository found. The Github action won\'t be triggered.')
@@ -126,7 +153,13 @@ export const createStaticWorkspaceGHAction = async (logger, env, config, project
126
153
  if (!isGithubActionExists) {
127
154
  await mkdir(join(projectDir, '.github', 'workflows'), { recursive: true })
128
155
  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.')
156
+ logger.info('Github action successfully created, please add the following secrets as repository secrets: ')
157
+ const secretsString = formatSecretsToAdd({
158
+ PLATFORMATIC_STATIC_WORKSPACE_ID: 'your workspace id',
159
+ PLATFORMATIC_STATIC_WORKSPACE_API_KEY: 'your workspace API key',
160
+ DATABASE_URL: env.DATABASE_URL
161
+ })
162
+ logger.info(`\n ${secretsString}`)
130
163
  const isGitDir = await isFileAccessible('.git', projectDir)
131
164
  if (!isGitDir) {
132
165
  logger.warn('No git repository found. The Github action won\'t be triggered.')
package/src/index.mjs CHANGED
@@ -8,7 +8,9 @@ import createPlatformaticService from './service/create-service-cli.mjs'
8
8
  import createPlatformaticComposer from './composer/create-composer-cli.mjs'
9
9
  import { createPlatformaticRuntime, createRuntimeService } from './runtime/create-runtime-cli.mjs'
10
10
  import commist from 'commist'
11
- import { getUsername, getVersion, minimumSupportedNodeVersions, isCurrentVersionSupported, findRuntimeConfigFile } from './utils.mjs'
11
+ import { getUsername, getVersion, minimumSupportedNodeVersions, isCurrentVersionSupported, findRuntimeConfigFile, getDependencyVersion } from './utils.mjs'
12
+ import { createPackageJson } from './create-package-json.mjs'
13
+ import { createGitignore } from './create-gitignore.mjs'
12
14
 
13
15
  export async function chooseKind (argv, opts = {}) {
14
16
  const skip = opts.skip
@@ -101,3 +103,10 @@ const createPlatformatic = async (argv) => {
101
103
  }
102
104
 
103
105
  export default createPlatformatic
106
+
107
+ export {
108
+ createPackageJson,
109
+ createGitignore,
110
+ getVersion,
111
+ getDependencyVersion
112
+ }
@@ -2,6 +2,7 @@ import { writeFile, mkdir, readFile, appendFile } from 'fs/promises'
2
2
  import { join } from 'path'
3
3
  import * as desm from 'desm'
4
4
  import { findServiceConfigFile, isFileAccessible } from '../utils.mjs'
5
+ import { getTsConfig } from '../get-tsconfig.mjs'
5
6
 
6
7
  const TS_OUT_DIR = 'dist'
7
8
 
@@ -29,18 +30,28 @@ function generateConfig (version, typescript) {
29
30
  }
30
31
 
31
32
  if (typescript === true) {
32
- config.plugins.typescript = true
33
+ config.plugins.typescript = '{PLT_TYPESCRIPT}'
33
34
  }
34
35
 
35
36
  return config
36
37
  }
37
38
 
38
- function generateEnv (hostname, port) {
39
- const env = `\
39
+ function generateEnv (hostname, port, typescript) {
40
+ let env = `\
40
41
  PLT_SERVER_HOSTNAME=${hostname}
41
42
  PORT=${port}
42
43
  PLT_SERVER_LOGGER_LEVEL=info
43
44
  `
45
+
46
+ if (typescript === true) {
47
+ env += `\
48
+
49
+ # Set to false to disable automatic typescript compilation.
50
+ # Changing this setting is needed for production
51
+ PLT_TYPESCRIPT=true
52
+ `
53
+ }
54
+
44
55
  return env
45
56
  }
46
57
 
@@ -90,27 +101,6 @@ export default async function (fastify: FastifyInstance, opts: FastifyPluginOpti
90
101
  }
91
102
  `
92
103
 
93
- function getTsConfig (outDir) {
94
- return {
95
- compilerOptions: {
96
- module: 'commonjs',
97
- esModuleInterop: true,
98
- target: 'es6',
99
- sourceMap: true,
100
- pretty: true,
101
- noEmitOnError: true,
102
- outDir
103
- },
104
- watchOptions: {
105
- watchFile: 'fixedPollingInterval',
106
- watchDirectory: 'fixedPollingInterval',
107
- fallbackPolling: 'dynamicPriority',
108
- synchronousWatchDirectory: true,
109
- excludeDirectories: ['**/node_modules', outDir]
110
- }
111
- }
112
- }
113
-
114
104
  async function generatePluginWithTypesSupport (logger, currentDir, isTypescript) {
115
105
  await mkdir(join(currentDir, 'plugins'))
116
106
  const pluginTemplate = isTypescript
@@ -147,7 +137,7 @@ async function createService ({ hostname, port, typescript = false }, logger, cu
147
137
  await writeFile(join(currentDir, 'platformatic.service.json'), JSON.stringify(config, null, 2))
148
138
  logger.info('Configuration file platformatic.service.json successfully created.')
149
139
 
150
- const env = generateEnv(hostname, port)
140
+ const env = generateEnv(hostname, port, typescript)
151
141
  const envFileExists = await isFileAccessible('.env', currentDir)
152
142
  await appendFile(join(currentDir, '.env'), env)
153
143
  await writeFile(join(currentDir, '.env.sample'), env)
package/src/utils.mjs CHANGED
@@ -18,7 +18,10 @@ export async function isFileAccessible (filename, directory) {
18
18
  return false
19
19
  }
20
20
  }
21
-
21
+ /**
22
+ * Gets the username from git config or `whoami` command
23
+ * @returns string | null
24
+ */
22
25
  export const getUsername = async () => {
23
26
  try {
24
27
  const { stdout } = await execa('git', ['config', 'user.name'])
@@ -39,7 +42,10 @@ export const getUsername = async () => {
39
42
 
40
43
  return null
41
44
  }
42
-
45
+ /**
46
+ * Get the platformatic package version from package.json
47
+ * @returns string
48
+ */
43
49
  /* c8 ignore next 4 */
44
50
  export const getVersion = async () => {
45
51
  const data = await readFile(desm.join(import.meta.url, '..', 'package.json'), 'utf8')
@@ -73,6 +79,11 @@ export const findServiceConfigFile = async (directory) => (ConfigManager.findCon
73
79
  export const findComposerConfigFile = async (directory) => (ConfigManager.findConfigFile(directory, 'composer'))
74
80
  export const findRuntimeConfigFile = async (directory) => (ConfigManager.findConfigFile(directory, 'runtime'))
75
81
 
82
+ /**
83
+ * Gets the version of the specified dependency package from package.json
84
+ * @param {string} dependencyName
85
+ * @returns string
86
+ */
76
87
  export const getDependencyVersion = async (dependencyName) => {
77
88
  const require = createRequire(import.meta.url)
78
89
  const pathToPackageJson = join(dirname(require.resolve(dependencyName)), 'package.json')
@@ -188,6 +188,7 @@ test('creates project with typescript', async ({ equal, same }) => {
188
188
  equal(process.env.PLT_SERVER_HOSTNAME, 'myhost')
189
189
  equal(process.env.PORT, '6666')
190
190
  equal(process.env.DATABASE_URL, 'sqlite://./db.sqlite')
191
+ equal(process.env.PLT_TYPESCRIPT, 'true')
191
192
 
192
193
  equal(db.graphql, true)
193
194
  equal(db.openapi, true)
@@ -199,7 +200,7 @@ test('creates project with typescript', async ({ equal, same }) => {
199
200
  equal(migrationFileUndo, moviesMigrationUndo)
200
201
 
201
202
  same(plugins.paths, ['plugin.ts'])
202
- equal(plugins.typescript, true)
203
+ equal(plugins.typescript, '{PLT_TYPESCRIPT}')
203
204
  equal(await isFileAccessible(join(tmpDir, 'plugin.ts')), true)
204
205
  equal(await isFileAccessible(join(tmpDir, 'tsconfig.json')), true)
205
206
  })
@@ -0,0 +1,8 @@
1
+ import { test } from 'tap'
2
+ import * as funcs from '../create-platformatic.mjs'
3
+ test('Should export functions', async ({ ok }) => {
4
+ ok(funcs.createPackageJson)
5
+ ok(funcs.createGitignore)
6
+ ok(funcs.getDependencyVersion)
7
+ ok(funcs.getVersion)
8
+ })
@@ -29,9 +29,9 @@ const env = {
29
29
  PLT_SERVER_LOGGER_LEVEL: 'info'
30
30
  }
31
31
 
32
- test('creates gh action', async ({ end, equal }) => {
32
+ test('creates gh action', async ({ equal, match }) => {
33
33
  await createDynamicWorkspaceGHAction(fakeLogger, env, 'db', tmpDir, false)
34
- equal(log[0], 'Github action successfully created, please add PLATFORMATIC_DYNAMIC_WORKSPACE_ID and PLATFORMATIC_DYNAMIC_WORKSPACE_API_KEY as repository secrets.')
34
+ equal(log[0], 'Github action successfully created, please add the following secrets as repository secrets: ')
35
35
  const accessible = await isFileAccessible(join(tmpDir, '.github/workflows/platformatic-dynamic-workspace-deploy.yml'))
36
36
  equal(accessible, true)
37
37
  const ghFile = await readFile(join(tmpDir, '.github/workflows/platformatic-dynamic-workspace-deploy.yml'), 'utf8')
@@ -41,16 +41,16 @@ test('creates gh action', async ({ end, equal }) => {
41
41
  equal(steps[0].name, 'Checkout application project repository')
42
42
  equal(steps[1].name, 'npm install --omit=dev')
43
43
  equal(steps[2].name, 'Deploy project')
44
- equal(steps[2].env.DATABASE_URL, 'mydbconnectionstring')
44
+ match(steps[2].env.DATABASE_URL, /\$\{\{ secrets.DATABASE_URL \}\}/)
45
45
  equal(steps[2].env.PLT_SERVER_LOGGER_LEVEL, 'info')
46
46
 
47
47
  equal(permissions.contents, 'read')
48
48
  equal(permissions['pull-requests'], 'write')
49
49
  })
50
50
 
51
- test('creates gh action with TS build step', async ({ end, equal }) => {
51
+ test('creates gh action with TS build step', async ({ equal, match }) => {
52
52
  await createDynamicWorkspaceGHAction(fakeLogger, env, 'db', tmpDir, true)
53
- equal(log[0], 'Github action successfully created, please add PLATFORMATIC_DYNAMIC_WORKSPACE_ID and PLATFORMATIC_DYNAMIC_WORKSPACE_API_KEY as repository secrets.')
53
+ equal(log[0], 'Github action successfully created, please add the following secrets as repository secrets: ')
54
54
  const accessible = await isFileAccessible(join(tmpDir, '.github/workflows/platformatic-dynamic-workspace-deploy.yml'))
55
55
  equal(accessible, true)
56
56
  const ghFile = await readFile(join(tmpDir, '.github/workflows/platformatic-dynamic-workspace-deploy.yml'), 'utf8')
@@ -61,7 +61,7 @@ test('creates gh action with TS build step', async ({ end, equal }) => {
61
61
  equal(steps[1].name, 'npm install --omit=dev')
62
62
  equal(steps[2].name, 'Build project')
63
63
  equal(steps[3].name, 'Deploy project')
64
- equal(steps[3].env.DATABASE_URL, 'mydbconnectionstring')
64
+ match(steps[3].env.DATABASE_URL, /\$\{\{ secrets.DATABASE_URL \}\}/)
65
65
  equal(steps[3].env.PLT_SERVER_LOGGER_LEVEL, 'info')
66
66
 
67
67
  equal(permissions.contents, 'read')
@@ -78,17 +78,21 @@ test('do not create gitignore file because already present', async ({ end, equal
78
78
 
79
79
  test('creates gh action with a warn if a .git folder is not present', async ({ end, equal }) => {
80
80
  await createDynamicWorkspaceGHAction(fakeLogger, env, 'db', tmpDir)
81
- equal(log[0], 'Github action successfully created, please add PLATFORMATIC_DYNAMIC_WORKSPACE_ID and PLATFORMATIC_DYNAMIC_WORKSPACE_API_KEY as repository secrets.')
81
+ equal(log[0], 'Github action successfully created, please add the following secrets as repository secrets: ')
82
82
  const accessible = await isFileAccessible(join(tmpDir, '.github/workflows/platformatic-dynamic-workspace-deploy.yml'))
83
83
  equal(accessible, true)
84
- equal(log[1], 'No git repository found. The Github action won\'t be triggered.')
84
+ const secretsLogLine = log[1].split('\n')
85
+ equal(secretsLogLine[1].trim(), 'PLATFORMATIC_DYNAMIC_WORKSPACE_ID: your workspace id')
86
+ equal(secretsLogLine[2].trim(), 'PLATFORMATIC_DYNAMIC_WORKSPACE_API_KEY: your workspace API key')
87
+ equal(secretsLogLine[3].trim(), 'DATABASE_URL: mydbconnectionstring')
88
+ equal(log[2], 'No git repository found. The Github action won\'t be triggered.')
85
89
  })
86
90
 
87
91
  test('creates gh action without a warn if a .git folder is present', async ({ end, equal }) => {
88
92
  await mkdir(join(tmpDir, '.git'), { recursive: true })
89
93
  await createDynamicWorkspaceGHAction(fakeLogger, env, 'db', tmpDir)
90
- equal(log[0], 'Github action successfully created, please add PLATFORMATIC_DYNAMIC_WORKSPACE_ID and PLATFORMATIC_DYNAMIC_WORKSPACE_API_KEY as repository secrets.')
94
+ equal(log[0], 'Github action successfully created, please add the following secrets as repository secrets: ')
91
95
  const accessible = await isFileAccessible(join(tmpDir, '.github/workflows/platformatic-dynamic-workspace-deploy.yml'))
92
96
  equal(accessible, true)
93
- equal(log.length, 1)
97
+ equal(log.length, 2)
94
98
  })
@@ -29,9 +29,9 @@ const env = {
29
29
  PLT_SERVER_LOGGER_LEVEL: 'info'
30
30
  }
31
31
 
32
- test('creates gh action', async ({ end, equal }) => {
32
+ test('creates gh action', async ({ equal, match }) => {
33
33
  await createStaticWorkspaceGHAction(fakeLogger, env, 'db', tmpDir, false)
34
- equal(log[0], 'Github action successfully created, please add PLATFORMATIC_STATIC_WORKSPACE_ID and PLATFORMATIC_STATIC_WORKSPACE_API_KEY as repository secret.')
34
+ equal(log[0], 'Github action successfully created, please add the following secrets as repository secrets: ')
35
35
  const accessible = await isFileAccessible(join(tmpDir, '.github/workflows/platformatic-static-workspace-deploy.yml'))
36
36
  equal(accessible, true)
37
37
  const ghFile = await readFile(join(tmpDir, '.github/workflows/platformatic-static-workspace-deploy.yml'), 'utf8')
@@ -41,15 +41,15 @@ test('creates gh action', async ({ end, equal }) => {
41
41
  equal(steps[0].name, 'Checkout application project repository')
42
42
  equal(steps[1].name, 'npm install --omit=dev')
43
43
  equal(steps[2].name, 'Deploy project')
44
- equal(steps[2].env.DATABASE_URL, 'mydbconnectionstring')
44
+ match(steps[2].env.DATABASE_URL, /\$\{\{ secrets.DATABASE_URL \}\}/)
45
45
  equal(steps[2].env.PLT_SERVER_LOGGER_LEVEL, 'info')
46
46
 
47
47
  equal(permissions.contents, 'read')
48
48
  })
49
49
 
50
- test('creates gh action with TS build step', async ({ end, equal }) => {
50
+ test('creates gh action with TS build step', async ({ equal, match }) => {
51
51
  await createStaticWorkspaceGHAction(fakeLogger, env, 'db', tmpDir, true)
52
- equal(log[0], 'Github action successfully created, please add PLATFORMATIC_STATIC_WORKSPACE_ID and PLATFORMATIC_STATIC_WORKSPACE_API_KEY as repository secret.')
52
+ equal(log[0], 'Github action successfully created, please add the following secrets as repository secrets: ')
53
53
  const accessible = await isFileAccessible(join(tmpDir, '.github/workflows/platformatic-static-workspace-deploy.yml'))
54
54
  equal(accessible, true)
55
55
  const ghFile = await readFile(join(tmpDir, '.github/workflows/platformatic-static-workspace-deploy.yml'), 'utf8')
@@ -60,7 +60,7 @@ test('creates gh action with TS build step', async ({ end, equal }) => {
60
60
  equal(steps[1].name, 'npm install --omit=dev')
61
61
  equal(steps[2].name, 'Build project')
62
62
  equal(steps[3].name, 'Deploy project')
63
- equal(steps[3].env.DATABASE_URL, 'mydbconnectionstring')
63
+ match(steps[3].env.DATABASE_URL, /\$\{\{ secrets.DATABASE_URL \}\}/)
64
64
  equal(steps[3].env.PLT_SERVER_LOGGER_LEVEL, 'info')
65
65
 
66
66
  equal(permissions.contents, 'read')
@@ -76,17 +76,21 @@ test('do not create gitignore file because already present', async ({ end, equal
76
76
 
77
77
  test('creates gh action with a warn if a .git folder is not present', async ({ end, equal }) => {
78
78
  await createStaticWorkspaceGHAction(fakeLogger, env, 'db', tmpDir)
79
- equal(log[0], 'Github action successfully created, please add PLATFORMATIC_STATIC_WORKSPACE_ID and PLATFORMATIC_STATIC_WORKSPACE_API_KEY as repository secret.')
79
+ equal(log[0], 'Github action successfully created, please add the following secrets as repository secrets: ')
80
80
  const accessible = await isFileAccessible(join(tmpDir, '.github/workflows/platformatic-static-workspace-deploy.yml'))
81
81
  equal(accessible, true)
82
- equal(log[1], 'No git repository found. The Github action won\'t be triggered.')
82
+ const secretsLogLine = log[1].split('\n')
83
+ equal(secretsLogLine[1].trim(), 'PLATFORMATIC_STATIC_WORKSPACE_ID: your workspace id')
84
+ equal(secretsLogLine[2].trim(), 'PLATFORMATIC_STATIC_WORKSPACE_API_KEY: your workspace API key')
85
+ equal(secretsLogLine[3].trim(), 'DATABASE_URL: mydbconnectionstring')
86
+ equal(log[2], 'No git repository found. The Github action won\'t be triggered.')
83
87
  })
84
88
 
85
89
  test('creates gh action without a warn if a .git folder is present', async ({ end, equal }) => {
86
90
  await mkdir(join(tmpDir, '.git'), { recursive: true })
87
91
  await createStaticWorkspaceGHAction(fakeLogger, env, 'db', tmpDir)
88
- equal(log[0], 'Github action successfully created, please add PLATFORMATIC_STATIC_WORKSPACE_ID and PLATFORMATIC_STATIC_WORKSPACE_API_KEY as repository secret.')
92
+ equal(log[0], 'Github action successfully created, please add the following secrets as repository secrets: ')
89
93
  const accessible = await isFileAccessible(join(tmpDir, '.github/workflows/platformatic-static-workspace-deploy.yml'))
90
94
  equal(accessible, true)
91
- equal(log.length, 1)
95
+ equal(log.length, 2)
92
96
  })
@@ -60,7 +60,7 @@ test('creates service with typescript', async ({ equal, same, ok }) => {
60
60
  equal(process.env.PORT, '6666')
61
61
 
62
62
  same(plugins.paths, [{ path: './plugins', encapsulate: false }, './routes'])
63
- equal(plugins.typescript, true)
63
+ equal(plugins.typescript, '{PLT_TYPESCRIPT}')
64
64
 
65
65
  ok(await isFileAccessible(join(tmpDir, 'tsconfig.json')))
66
66
  ok(await isFileAccessible(join(tmpDir, 'plugins', 'example.ts')))