@platformatic/generators 1.28.1 → 1.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.
- package/index.js +3 -2
- package/lib/base-generator.d.ts +1 -0
- package/lib/base-generator.js +96 -31
- package/lib/file-generator.d.ts +1 -0
- package/lib/file-generator.js +8 -1
- package/lib/utils.d.ts +3 -0
- package/lib/utils.js +55 -2
- package/package.json +1 -1
- package/test/base-generator.test.js +117 -25
- package/test/file-generator.test.js +34 -0
- package/test/fixtures/sample-runtime/.env +9 -0
- package/test/fixtures/sample-runtime/platformatic.json +19 -0
- package/test/fixtures/sample-runtime/services/rival/platformatic.json +33 -0
- package/test/helpers.js +30 -9
- package/test/utils.test.js +63 -1
package/index.js
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
const { BaseGenerator } = require('./lib/base-generator')
|
|
4
4
|
const { StackableGenerator } = require('./lib/stackable-generator')
|
|
5
5
|
const { generateTests } = require('./lib/create-plugin')
|
|
6
|
-
|
|
6
|
+
const utils = require('./lib/utils')
|
|
7
7
|
module.exports = {
|
|
8
8
|
BaseGenerator,
|
|
9
9
|
StackableGenerator,
|
|
10
|
-
generateTests
|
|
10
|
+
generateTests,
|
|
11
|
+
...utils
|
|
11
12
|
}
|
package/lib/base-generator.d.ts
CHANGED
|
@@ -101,6 +101,7 @@ export namespace BaseGenerator {
|
|
|
101
101
|
|
|
102
102
|
addPackage(pkg: PackageDefinition): Promise<void>
|
|
103
103
|
|
|
104
|
+
loadFromDir(dir: string): Promise<void>
|
|
104
105
|
prepare(): Promise<GeneratorMetadata>
|
|
105
106
|
run(): Promise<GeneratorMetadata>
|
|
106
107
|
addQuestion(question: any, where?: WhereClause): Promise<void>
|
package/lib/base-generator.js
CHANGED
|
@@ -15,6 +15,9 @@ const { generateTests, generatePlugins } = require('./create-plugin')
|
|
|
15
15
|
const { PrepareError, MissingEnvVariable, ModuleNeeded } = require('./errors')
|
|
16
16
|
const { generateGitignore } = require('./create-gitignore')
|
|
17
17
|
const generateName = require('boring-name-generator')
|
|
18
|
+
const { getServiceTemplateFromSchemaUrl } = require('./utils')
|
|
19
|
+
const { flattenObject } = require('./utils')
|
|
20
|
+
const { envStringToObject } = require('./utils')
|
|
18
21
|
/* c8 ignore start */
|
|
19
22
|
const fakeLogger = {
|
|
20
23
|
info: () => {},
|
|
@@ -57,7 +60,8 @@ class BaseGenerator extends FileGenerator {
|
|
|
57
60
|
isRuntimeContext: false,
|
|
58
61
|
serviceName: '',
|
|
59
62
|
envPrefix: '',
|
|
60
|
-
env: {}
|
|
63
|
+
env: {},
|
|
64
|
+
isUpdating: false
|
|
61
65
|
}
|
|
62
66
|
}
|
|
63
67
|
|
|
@@ -179,47 +183,67 @@ class BaseGenerator extends FileGenerator {
|
|
|
179
183
|
async prepare () {
|
|
180
184
|
try {
|
|
181
185
|
this.reset()
|
|
182
|
-
await this.getFastifyVersion()
|
|
183
|
-
await this.getPlatformaticVersion()
|
|
184
186
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
187
|
+
if (this.config.isUpdating) {
|
|
188
|
+
// only the packages options may have changed, let's update those
|
|
189
|
+
await this.generateConfigFile()
|
|
190
|
+
const generatedConfigFile = JSON.parse(this.getFileObject('platformatic.json', '').contents)
|
|
191
|
+
const fileFromDisk = await this.loadFile({ file: 'platformatic.json', path: '' })
|
|
192
|
+
const currentConfigFile = JSON.parse(fileFromDisk.contents)
|
|
193
|
+
if (generatedConfigFile.plugins && generatedConfigFile.plugins.packages) {
|
|
194
|
+
currentConfigFile.plugins.packages = generatedConfigFile.plugins.packages
|
|
195
|
+
} else {
|
|
196
|
+
// remove packages because new configuration does not have them
|
|
197
|
+
currentConfigFile.plugins.packages = []
|
|
198
|
+
}
|
|
199
|
+
this.reset()
|
|
200
|
+
this.addFile({
|
|
201
|
+
path: '',
|
|
202
|
+
file: 'platformatic.json',
|
|
203
|
+
contents: JSON.stringify(currentConfigFile, null, 2)
|
|
204
|
+
})
|
|
205
|
+
} else {
|
|
206
|
+
await this.getFastifyVersion()
|
|
207
|
+
await this.getPlatformaticVersion()
|
|
196
208
|
|
|
197
|
-
|
|
209
|
+
await this._beforePrepare()
|
|
198
210
|
|
|
199
|
-
|
|
200
|
-
|
|
211
|
+
// generate package.json
|
|
212
|
+
const template = await this.generatePackageJson()
|
|
201
213
|
this.addFile({
|
|
202
214
|
path: '',
|
|
203
|
-
file: '
|
|
204
|
-
contents: JSON.stringify(
|
|
215
|
+
file: 'package.json',
|
|
216
|
+
contents: JSON.stringify(template, null, 2)
|
|
205
217
|
})
|
|
206
|
-
}
|
|
207
218
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
this.
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
219
|
+
await this.generateConfigFile()
|
|
220
|
+
|
|
221
|
+
await this.generateEnv()
|
|
222
|
+
|
|
223
|
+
if (this.config.typescript) {
|
|
224
|
+
// create tsconfig.json
|
|
225
|
+
this.addFile({
|
|
226
|
+
path: '',
|
|
227
|
+
file: 'tsconfig.json',
|
|
228
|
+
contents: JSON.stringify(this.getTsConfig(), null, 2)
|
|
229
|
+
})
|
|
214
230
|
}
|
|
215
|
-
}
|
|
216
231
|
|
|
217
|
-
|
|
232
|
+
if (this.config.plugin) {
|
|
233
|
+
// create plugin
|
|
234
|
+
this.files.push(...generatePlugins(this.config.typescript))
|
|
235
|
+
if (this.config.tests) {
|
|
236
|
+
// create tests
|
|
237
|
+
this.files.push(...generateTests(this.config.typescript, this.module))
|
|
238
|
+
}
|
|
239
|
+
}
|
|
218
240
|
|
|
219
|
-
|
|
241
|
+
this.files.push(generateGitignore())
|
|
220
242
|
|
|
221
|
-
|
|
243
|
+
await this._afterPrepare()
|
|
222
244
|
|
|
245
|
+
this.checkEnvVariablesInConfigFile()
|
|
246
|
+
}
|
|
223
247
|
return {
|
|
224
248
|
targetDirectory: this.targetDirectory,
|
|
225
249
|
env: this.config.env
|
|
@@ -310,7 +334,6 @@ class BaseGenerator extends FileGenerator {
|
|
|
310
334
|
async generateConfigFile () {
|
|
311
335
|
const configFileName = 'platformatic.json'
|
|
312
336
|
const contents = await this._getConfigFileContents()
|
|
313
|
-
|
|
314
337
|
// handle packages
|
|
315
338
|
if (this.packages.length > 0) {
|
|
316
339
|
if (!contents.plugins) {
|
|
@@ -431,6 +454,48 @@ class BaseGenerator extends FileGenerator {
|
|
|
431
454
|
this.packages.push(pkg)
|
|
432
455
|
}
|
|
433
456
|
|
|
457
|
+
async loadFromDir (serviceName, runtimeRootPath) {
|
|
458
|
+
const runtimePkgConfigFileData = JSON.parse(await readFile(join(runtimeRootPath, 'platformatic.json'), 'utf-8'))
|
|
459
|
+
const servicesPath = runtimePkgConfigFileData.autoload.path
|
|
460
|
+
const servicePkgJsonFileData = JSON.parse(await readFile(join(runtimeRootPath, servicesPath, serviceName, 'platformatic.json'), 'utf-8'))
|
|
461
|
+
const runtimeEnv = envStringToObject(await readFile(join(runtimeRootPath, '.env'), 'utf-8'))
|
|
462
|
+
const serviceNamePrefix = convertServiceNameToPrefix(serviceName)
|
|
463
|
+
const plugins = []
|
|
464
|
+
if (servicePkgJsonFileData.plugins && servicePkgJsonFileData.plugins.packages) {
|
|
465
|
+
for (const pkg of servicePkgJsonFileData.plugins.packages) {
|
|
466
|
+
const flattened = flattenObject(pkg)
|
|
467
|
+
const output = {
|
|
468
|
+
name: flattened.name,
|
|
469
|
+
options: []
|
|
470
|
+
}
|
|
471
|
+
if (pkg.options) {
|
|
472
|
+
Object.entries(flattened)
|
|
473
|
+
.filter(([key, value]) => key.indexOf('options.') === 0 && flattened[key].startsWith('{PLT_'))
|
|
474
|
+
.forEach(([key, value]) => {
|
|
475
|
+
const runtimeEnvVarKey = value.replace(/[{}]/g, '')
|
|
476
|
+
const serviceEnvVarKey = runtimeEnvVarKey.replace(`PLT_${serviceNamePrefix}_`, '')
|
|
477
|
+
const option = {
|
|
478
|
+
name: serviceEnvVarKey,
|
|
479
|
+
path: key.replace('options.', ''),
|
|
480
|
+
type: 'string',
|
|
481
|
+
value: runtimeEnv[runtimeEnvVarKey]
|
|
482
|
+
}
|
|
483
|
+
output.options.push(option)
|
|
484
|
+
})
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
plugins.push(output)
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
return {
|
|
492
|
+
name: serviceName,
|
|
493
|
+
template: getServiceTemplateFromSchemaUrl(servicePkgJsonFileData.$schema),
|
|
494
|
+
fields: [],
|
|
495
|
+
plugins
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
434
499
|
// implement in the subclass
|
|
435
500
|
/* c8 ignore next 1 */
|
|
436
501
|
async postInstallActions () {}
|
package/lib/file-generator.d.ts
CHANGED
package/lib/file-generator.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
const { safeMkdir } = require('./utils')
|
|
3
3
|
const { join } = require('node:path')
|
|
4
|
-
const { writeFile } = require('node:fs/promises')
|
|
4
|
+
const { writeFile, readFile } = require('node:fs/promises')
|
|
5
5
|
|
|
6
6
|
/* c8 ignore start */
|
|
7
7
|
const fakeLogger = {
|
|
@@ -24,6 +24,13 @@ class FileGenerator {
|
|
|
24
24
|
this.targetDirectory = dir
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
async loadFile ({ path, file }) {
|
|
28
|
+
const filePath = join(this.targetDirectory, path, file)
|
|
29
|
+
const contents = await readFile(filePath, 'utf-8')
|
|
30
|
+
this.addFile({ path, file, contents })
|
|
31
|
+
return this.getFileObject(file, path)
|
|
32
|
+
}
|
|
33
|
+
|
|
27
34
|
addFile ({ path, file, contents, options = {} }) {
|
|
28
35
|
const fileObject = this.getFileObject(file, path)
|
|
29
36
|
if (path.startsWith('/')) {
|
package/lib/utils.d.ts
CHANGED
|
@@ -13,7 +13,10 @@ export namespace GeneratorUtils {
|
|
|
13
13
|
export function stripVersion(version: string): string
|
|
14
14
|
export function convertServiceNameToPrefix(serviceName: string): string
|
|
15
15
|
export function envObjectToString(env: Env): string
|
|
16
|
+
export function envStringToObject(env: string): Env
|
|
16
17
|
export function extractEnvVariablesFromText(text: string): string[]
|
|
17
18
|
export function getPackageConfigurationObject(config: PackageConfiguration[]): object
|
|
19
|
+
export function flattenObject(obj: object): object
|
|
20
|
+
export function getServiceTemplateFromSchemaUrl(schemaUrl: string): string
|
|
18
21
|
export const PLT_ROOT: string
|
|
19
22
|
}
|
package/lib/utils.js
CHANGED
|
@@ -6,7 +6,7 @@ const { join } = require('node:path')
|
|
|
6
6
|
const { request } = require('undici')
|
|
7
7
|
const { setTimeout } = require('timers/promises')
|
|
8
8
|
const PLT_ROOT = 'PLT_ROOT'
|
|
9
|
-
|
|
9
|
+
const { EOL } = require('node:os')
|
|
10
10
|
async function safeMkdir (dir) {
|
|
11
11
|
try {
|
|
12
12
|
await mkdir(dir, { recursive: true })
|
|
@@ -52,9 +52,22 @@ function envObjectToString (env) {
|
|
|
52
52
|
Object.entries(env).forEach((kv) => {
|
|
53
53
|
output.push(`${kv[0]}=${kv[1]}`)
|
|
54
54
|
})
|
|
55
|
-
return output.join(
|
|
55
|
+
return output.join(EOL)
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
function envStringToObject (envString) {
|
|
59
|
+
const output = {}
|
|
60
|
+
const split = envString.split(EOL)
|
|
61
|
+
split
|
|
62
|
+
.filter((line) => {
|
|
63
|
+
return line.trim() !== '' && line.indexOf('#') !== 0
|
|
64
|
+
})
|
|
65
|
+
.forEach((line) => {
|
|
66
|
+
const kv = line.split('=')
|
|
67
|
+
output[kv[0]] = kv[1]
|
|
68
|
+
})
|
|
69
|
+
return output
|
|
70
|
+
}
|
|
58
71
|
function extractEnvVariablesFromText (text) {
|
|
59
72
|
const match = text.match(/\{[a-zA-Z0-9-_]*\}/g)
|
|
60
73
|
if (match) {
|
|
@@ -132,13 +145,53 @@ async function getLatestNpmVersion (pkg) {
|
|
|
132
145
|
}
|
|
133
146
|
return null
|
|
134
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* Flatten a deep-nested object to a single level depth one
|
|
150
|
+
* i.e from
|
|
151
|
+
* {
|
|
152
|
+
* name: 'test',
|
|
153
|
+
* a: {
|
|
154
|
+
* b: {
|
|
155
|
+
* c: 'foobar'
|
|
156
|
+
* }
|
|
157
|
+
* }
|
|
158
|
+
* }
|
|
159
|
+
* to:
|
|
160
|
+
* {
|
|
161
|
+
* name: 'test',
|
|
162
|
+
* 'a.b.c': 'foobar'
|
|
163
|
+
* }
|
|
164
|
+
* @param {Object} ob
|
|
165
|
+
* @returns Object
|
|
166
|
+
*/
|
|
167
|
+
function flattenObject (ob) {
|
|
168
|
+
const result = {}
|
|
169
|
+
for (const i in ob) {
|
|
170
|
+
if ((typeof ob[i]) === 'object' && !Array.isArray(ob[i])) {
|
|
171
|
+
const temp = flattenObject(ob[i])
|
|
172
|
+
for (const j in temp) {
|
|
173
|
+
result[i + '.' + j] = temp[j]
|
|
174
|
+
}
|
|
175
|
+
} else {
|
|
176
|
+
result[i] = ob[i]
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return result
|
|
180
|
+
}
|
|
135
181
|
|
|
182
|
+
function getServiceTemplateFromSchemaUrl (schemaUrl) {
|
|
183
|
+
const splitted = schemaUrl.split('/')
|
|
184
|
+
return `@platformatic/${splitted[splitted.length - 1]}`
|
|
185
|
+
}
|
|
136
186
|
module.exports = {
|
|
137
187
|
addPrefixToString,
|
|
138
188
|
convertServiceNameToPrefix,
|
|
139
189
|
getPackageConfigurationObject,
|
|
140
190
|
envObjectToString,
|
|
191
|
+
envStringToObject,
|
|
141
192
|
extractEnvVariablesFromText,
|
|
193
|
+
flattenObject,
|
|
194
|
+
getServiceTemplateFromSchemaUrl,
|
|
142
195
|
safeMkdir,
|
|
143
196
|
stripVersion,
|
|
144
197
|
PLT_ROOT,
|
package/package.json
CHANGED
|
@@ -1,18 +1,13 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { readFile, rm } = require('node:fs/promises')
|
|
4
|
-
const { test, afterEach, describe } = require('node:test')
|
|
3
|
+
const { readFile, rm, cp } = require('node:fs/promises')
|
|
4
|
+
const { test, after, afterEach, describe } = require('node:test')
|
|
5
5
|
const assert = require('node:assert')
|
|
6
6
|
const { join } = require('node:path')
|
|
7
7
|
|
|
8
|
-
const { fakeLogger, getTempDir } = require('./helpers')
|
|
8
|
+
const { fakeLogger, getTempDir, moveToTmpdir, mockNpmJsRequestForPkgs, mockAgent } = require('./helpers')
|
|
9
9
|
const { BaseGenerator } = require('../lib/base-generator')
|
|
10
10
|
const { convertServiceNameToPrefix } = require('../lib/utils')
|
|
11
|
-
const { MockAgent, setGlobalDispatcher } = require('undici')
|
|
12
|
-
|
|
13
|
-
const mockAgent = new MockAgent()
|
|
14
|
-
setGlobalDispatcher(mockAgent)
|
|
15
|
-
mockAgent.disableNetConnect()
|
|
16
11
|
|
|
17
12
|
afterEach(async () => {
|
|
18
13
|
try {
|
|
@@ -104,7 +99,8 @@ test('setConfig', async (t) => {
|
|
|
104
99
|
isRuntimeContext: false,
|
|
105
100
|
serviceName: '',
|
|
106
101
|
envPrefix: '',
|
|
107
|
-
tests: false
|
|
102
|
+
tests: false,
|
|
103
|
+
isUpdating: false
|
|
108
104
|
})
|
|
109
105
|
|
|
110
106
|
// should not have undefined properties
|
|
@@ -131,7 +127,8 @@ test('setConfig', async (t) => {
|
|
|
131
127
|
isRuntimeContext: false,
|
|
132
128
|
serviceName: '',
|
|
133
129
|
envPrefix: '',
|
|
134
|
-
tests: false
|
|
130
|
+
tests: false,
|
|
131
|
+
isUpdating: false
|
|
135
132
|
})
|
|
136
133
|
|
|
137
134
|
// reset config to defaults
|
|
@@ -150,7 +147,8 @@ test('setConfig', async (t) => {
|
|
|
150
147
|
isRuntimeContext: false,
|
|
151
148
|
serviceName: '',
|
|
152
149
|
envPrefix: '',
|
|
153
|
-
tests: false
|
|
150
|
+
tests: false,
|
|
151
|
+
isUpdating: false
|
|
154
152
|
})
|
|
155
153
|
|
|
156
154
|
// update only some fields
|
|
@@ -177,7 +175,8 @@ test('setConfig', async (t) => {
|
|
|
177
175
|
isRuntimeContext: false,
|
|
178
176
|
serviceName: '',
|
|
179
177
|
envPrefix: '',
|
|
180
|
-
tests: false
|
|
178
|
+
tests: false,
|
|
179
|
+
isUpdating: false
|
|
181
180
|
})
|
|
182
181
|
})
|
|
183
182
|
|
|
@@ -194,10 +193,10 @@ test('should append env values', async (t) => {
|
|
|
194
193
|
|
|
195
194
|
await bg.prepare()
|
|
196
195
|
const dotEnvFile = bg.getFileObject('.env')
|
|
197
|
-
assert.equal(dotEnvFile.contents, 'FOO=bar
|
|
196
|
+
assert.equal(dotEnvFile.contents.trim(), 'FOO=bar')
|
|
198
197
|
|
|
199
198
|
const dotEnvSampleFile = bg.getFileObject('.env.sample')
|
|
200
|
-
assert.equal(dotEnvSampleFile.contents, 'FOO=bar
|
|
199
|
+
assert.equal(dotEnvSampleFile.contents.trim(), 'FOO=bar')
|
|
201
200
|
})
|
|
202
201
|
|
|
203
202
|
test('should prepare the questions', async (t) => {
|
|
@@ -584,18 +583,19 @@ test('support packages', async (t) => {
|
|
|
584
583
|
}
|
|
585
584
|
|
|
586
585
|
{
|
|
586
|
+
mockNpmJsRequestForPkgs(['foobar'])
|
|
587
587
|
// should get the version from npm
|
|
588
|
-
mockAgent
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
588
|
+
// mockAgent
|
|
589
|
+
// .get('https://registry.npmjs.org')
|
|
590
|
+
// .intercept({
|
|
591
|
+
// method: 'GET',
|
|
592
|
+
// path: '/foobar'
|
|
593
|
+
// })
|
|
594
|
+
// .reply(200, {
|
|
595
|
+
// 'dist-tags': {
|
|
596
|
+
// latest: '1.42.0'
|
|
597
|
+
// }
|
|
598
|
+
// })
|
|
599
599
|
|
|
600
600
|
const svc = new BaseGenerator({
|
|
601
601
|
module: '@platformatic/service'
|
|
@@ -720,7 +720,99 @@ test('support packages', async (t) => {
|
|
|
720
720
|
assert.equal(packageJson.dependencies.foobar, 'latest')
|
|
721
721
|
}
|
|
722
722
|
})
|
|
723
|
+
test('should load data from directory', async (t) => {
|
|
724
|
+
const runtimeDirectory = join(__dirname, 'fixtures', 'sample-runtime')
|
|
725
|
+
const bg = new BaseGenerator({
|
|
726
|
+
module: '@platformatic/service'
|
|
727
|
+
})
|
|
728
|
+
const data = await bg.loadFromDir('rival', runtimeDirectory)
|
|
729
|
+
const expected = {
|
|
730
|
+
name: 'rival',
|
|
731
|
+
template: '@platformatic/service',
|
|
732
|
+
fields: [],
|
|
733
|
+
plugins: [
|
|
734
|
+
{
|
|
735
|
+
name: '@fastify/oauth2',
|
|
736
|
+
options: [
|
|
737
|
+
{
|
|
738
|
+
path: 'name',
|
|
739
|
+
type: 'string',
|
|
740
|
+
value: 'googleOAuth2',
|
|
741
|
+
name: 'FST_PLUGIN_OAUTH2_NAME'
|
|
742
|
+
},
|
|
743
|
+
{
|
|
744
|
+
path: 'credentials.client.id',
|
|
745
|
+
type: 'string',
|
|
746
|
+
value: 'sample_client_id',
|
|
747
|
+
name: 'FST_PLUGIN_OAUTH2_CREDENTIALS_CLIENT_ID'
|
|
748
|
+
},
|
|
749
|
+
{
|
|
750
|
+
path: 'credentials.client.secret',
|
|
751
|
+
type: 'string',
|
|
752
|
+
value: 'sample_client_secret',
|
|
753
|
+
name: 'FST_PLUGIN_OAUTH2_CREDENTIALS_CLIENT_SECRET'
|
|
754
|
+
},
|
|
755
|
+
{
|
|
756
|
+
path: 'startRedirectPath',
|
|
757
|
+
type: 'string',
|
|
758
|
+
value: '/login/google',
|
|
759
|
+
name: 'FST_PLUGIN_OAUTH2_REDIRECT_PATH'
|
|
760
|
+
},
|
|
761
|
+
{
|
|
762
|
+
path: 'callbackUri',
|
|
763
|
+
type: 'string',
|
|
764
|
+
value: 'http://localhost:3000/login/google/callback',
|
|
765
|
+
name: 'FST_PLUGIN_OAUTH2_CALLBACK_URI'
|
|
766
|
+
}
|
|
767
|
+
]
|
|
768
|
+
}]
|
|
769
|
+
}
|
|
770
|
+
assert.deepEqual(data, expected)
|
|
771
|
+
})
|
|
772
|
+
|
|
773
|
+
test.only('on update should just touch the packages configuration', async (t) => {
|
|
774
|
+
mockNpmJsRequestForPkgs(['@fastify/foo-plugin'])
|
|
775
|
+
const runtimeDirectory = join(__dirname, 'fixtures', 'sample-runtime', 'services', 'rival')
|
|
776
|
+
const dir = await moveToTmpdir(after)
|
|
777
|
+
await cp(runtimeDirectory, dir, { recursive: true })
|
|
778
|
+
|
|
779
|
+
const bg = new BaseGenerator({
|
|
780
|
+
module: '@platformatic/service',
|
|
781
|
+
targetDirectory: dir
|
|
782
|
+
})
|
|
783
|
+
bg.setConfig({
|
|
784
|
+
isUpdating: true
|
|
785
|
+
})
|
|
786
|
+
await bg.addPackage({
|
|
787
|
+
name: '@fastify/foo-plugin',
|
|
788
|
+
options: [
|
|
789
|
+
{
|
|
790
|
+
path: 'name',
|
|
791
|
+
type: 'string',
|
|
792
|
+
value: 'foobar',
|
|
793
|
+
name: 'FST_PLUGIN_FOO_FOOBAR'
|
|
794
|
+
}
|
|
795
|
+
]
|
|
796
|
+
})
|
|
797
|
+
await bg.prepare()
|
|
798
|
+
|
|
799
|
+
assert.equal(bg.files.length, 1)
|
|
800
|
+
assert.equal(bg.files[0].file, 'platformatic.json')
|
|
801
|
+
assert.equal(bg.files[0].path, '')
|
|
723
802
|
|
|
803
|
+
const configFileContents = JSON.parse(bg.files[0].contents)
|
|
804
|
+
assert.deepEqual(configFileContents.plugins.packages, [
|
|
805
|
+
{
|
|
806
|
+
name: '@fastify/foo-plugin',
|
|
807
|
+
options: {
|
|
808
|
+
name: '{FST_PLUGIN_FOO_FOOBAR}'
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
])
|
|
812
|
+
assert.deepEqual(bg.config.dependencies, {
|
|
813
|
+
'@fastify/foo-plugin': '1.42.0'
|
|
814
|
+
})
|
|
815
|
+
})
|
|
724
816
|
describe('runtime context', () => {
|
|
725
817
|
test('should set config.envPrefix correctly', async (t) => {
|
|
726
818
|
const bg = new BaseGenerator({
|
|
@@ -103,4 +103,38 @@ describe('FileGenerator', () => {
|
|
|
103
103
|
assert.equal(err.code, 'ENOENT')
|
|
104
104
|
}
|
|
105
105
|
})
|
|
106
|
+
|
|
107
|
+
test('should load file from filesystem', async (t) => {
|
|
108
|
+
const tempDir = join(tmpdir(), `plt-file-generator-test-${dirCount++}`)
|
|
109
|
+
t.after(async () => {
|
|
110
|
+
await rm(tempDir, { recursive: true })
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
await safeMkdir(tempDir)
|
|
114
|
+
const fg = new FileGenerator()
|
|
115
|
+
fg.setTargetDirectory(tempDir)
|
|
116
|
+
fg.addFile({ path: 'myDir', file: 'helloworld.txt', contents: 'hello world' })
|
|
117
|
+
await fg.writeFiles()
|
|
118
|
+
|
|
119
|
+
fg.reset()
|
|
120
|
+
const fileObject = await fg.loadFile({
|
|
121
|
+
path: 'myDir',
|
|
122
|
+
file: 'helloworld.txt'
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
assert.deepEqual(fileObject, {
|
|
126
|
+
path: 'myDir',
|
|
127
|
+
file: 'helloworld.txt',
|
|
128
|
+
contents: 'hello world',
|
|
129
|
+
options: {}
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
assert.equal(fg.files.length, 1)
|
|
133
|
+
assert.deepEqual(fg.files[0], {
|
|
134
|
+
path: 'myDir',
|
|
135
|
+
file: 'helloworld.txt',
|
|
136
|
+
contents: 'hello world',
|
|
137
|
+
options: {}
|
|
138
|
+
})
|
|
139
|
+
})
|
|
106
140
|
})
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
PLT_SERVER_HOSTNAME=0.0.0.0
|
|
2
|
+
PORT=3042
|
|
3
|
+
PLT_SERVER_LOGGER_LEVEL=info
|
|
4
|
+
PLT_RIVAL_TYPESCRIPT=true
|
|
5
|
+
PLT_RIVAL_FST_PLUGIN_OAUTH2_NAME=googleOAuth2
|
|
6
|
+
PLT_RIVAL_FST_PLUGIN_OAUTH2_CREDENTIALS_CLIENT_ID=sample_client_id
|
|
7
|
+
PLT_RIVAL_FST_PLUGIN_OAUTH2_CREDENTIALS_CLIENT_SECRET=sample_client_secret
|
|
8
|
+
PLT_RIVAL_FST_PLUGIN_OAUTH2_REDIRECT_PATH=/login/google
|
|
9
|
+
PLT_RIVAL_FST_PLUGIN_OAUTH2_CALLBACK_URI=http://localhost:3000/login/google/callback
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://platformatic.dev/schemas/v1.25.0/runtime",
|
|
3
|
+
"entrypoint": "rival",
|
|
4
|
+
"allowCycles": false,
|
|
5
|
+
"hotReload": true,
|
|
6
|
+
"autoload": {
|
|
7
|
+
"path": "services",
|
|
8
|
+
"exclude": [
|
|
9
|
+
"docs"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
"server": {
|
|
13
|
+
"hostname": "{PLT_SERVER_HOSTNAME}",
|
|
14
|
+
"port": "{PORT}",
|
|
15
|
+
"logger": {
|
|
16
|
+
"level": "{PLT_SERVER_LOGGER_LEVEL}"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://platformatic.dev/schemas/v1.25.0/service",
|
|
3
|
+
"service": {
|
|
4
|
+
"openapi": true
|
|
5
|
+
},
|
|
6
|
+
"watch": true,
|
|
7
|
+
"plugins": {
|
|
8
|
+
"paths": [
|
|
9
|
+
{
|
|
10
|
+
"path": "./plugins",
|
|
11
|
+
"encapsulate": false
|
|
12
|
+
},
|
|
13
|
+
"./routes"
|
|
14
|
+
],
|
|
15
|
+
"typescript": "{PLT_RIVAL_TYPESCRIPT}",
|
|
16
|
+
"packages": [
|
|
17
|
+
{
|
|
18
|
+
"name": "@fastify/oauth2",
|
|
19
|
+
"options": {
|
|
20
|
+
"name": "{PLT_RIVAL_FST_PLUGIN_OAUTH2_NAME}",
|
|
21
|
+
"credentials": {
|
|
22
|
+
"client": {
|
|
23
|
+
"id": "{PLT_RIVAL_FST_PLUGIN_OAUTH2_CREDENTIALS_CLIENT_ID}",
|
|
24
|
+
"secret": "{PLT_RIVAL_FST_PLUGIN_OAUTH2_CREDENTIALS_CLIENT_SECRET}"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"startRedirectPath": "{PLT_RIVAL_FST_PLUGIN_OAUTH2_REDIRECT_PATH}",
|
|
28
|
+
"callbackUri": "{PLT_RIVAL_FST_PLUGIN_OAUTH2_CALLBACK_URI}"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
}
|
package/test/helpers.js
CHANGED
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
const { join } = require('node:path')
|
|
4
4
|
const fs = require('node:fs/promises')
|
|
5
5
|
const { safeMkdir } = require('../lib/utils')
|
|
6
|
+
const { MockAgent, setGlobalDispatcher } = require('undici')
|
|
7
|
+
|
|
8
|
+
const mockAgent = new MockAgent()
|
|
9
|
+
setGlobalDispatcher(mockAgent)
|
|
10
|
+
mockAgent.disableNetConnect()
|
|
6
11
|
|
|
7
12
|
let counter = 0
|
|
8
13
|
|
|
@@ -16,21 +21,35 @@ async function getTempDir (baseDir) {
|
|
|
16
21
|
}
|
|
17
22
|
async function moveToTmpdir (teardown) {
|
|
18
23
|
const cwd = process.cwd()
|
|
19
|
-
const tmp = join(__dirname, 'tmp')
|
|
20
|
-
try {
|
|
21
|
-
|
|
22
|
-
} catch {
|
|
23
|
-
}
|
|
24
|
-
const dir = await getTempDir(
|
|
25
|
-
await fs.mkdir(dir)
|
|
24
|
+
// const tmp = join(__dirname, 'tmp')
|
|
25
|
+
// try {
|
|
26
|
+
// await fs.mkdir(tmp)
|
|
27
|
+
// } catch {
|
|
28
|
+
// }
|
|
29
|
+
const dir = await getTempDir()
|
|
26
30
|
process.chdir(dir)
|
|
27
31
|
teardown(() => process.chdir(cwd))
|
|
28
32
|
if (!process.env.SKIP_RM_TMP) {
|
|
29
|
-
teardown(() => fs.rm(
|
|
33
|
+
teardown(() => fs.rm(dir, { recursive: true }).catch(() => {}))
|
|
30
34
|
}
|
|
31
35
|
return dir
|
|
32
36
|
}
|
|
33
37
|
|
|
38
|
+
function mockNpmJsRequestForPkgs (pkgs) {
|
|
39
|
+
for (const pkg of pkgs) {
|
|
40
|
+
mockAgent
|
|
41
|
+
.get('https://registry.npmjs.org')
|
|
42
|
+
.intercept({
|
|
43
|
+
method: 'GET',
|
|
44
|
+
path: `/${pkg}`
|
|
45
|
+
})
|
|
46
|
+
.reply(200, {
|
|
47
|
+
'dist-tags': {
|
|
48
|
+
latest: '1.42.0'
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
}
|
|
34
53
|
module.exports = {
|
|
35
54
|
fakeLogger: {
|
|
36
55
|
info: () => {},
|
|
@@ -39,5 +58,7 @@ module.exports = {
|
|
|
39
58
|
error: () => {}
|
|
40
59
|
},
|
|
41
60
|
getTempDir,
|
|
42
|
-
moveToTmpdir
|
|
61
|
+
moveToTmpdir,
|
|
62
|
+
mockNpmJsRequestForPkgs,
|
|
63
|
+
mockAgent
|
|
43
64
|
}
|
package/test/utils.test.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { test, describe } = require('node:test')
|
|
4
|
+
const { EOL } = require('node:os')
|
|
4
5
|
const assert = require('node:assert')
|
|
5
6
|
const {
|
|
6
7
|
stripVersion,
|
|
@@ -10,6 +11,9 @@ const {
|
|
|
10
11
|
getPackageConfigurationObject,
|
|
11
12
|
addPrefixToString
|
|
12
13
|
} = require('../lib/utils')
|
|
14
|
+
const { flattenObject } = require('../lib/utils')
|
|
15
|
+
const { getServiceTemplateFromSchemaUrl } = require('../lib/utils')
|
|
16
|
+
const { envStringToObject } = require('../lib/utils')
|
|
13
17
|
|
|
14
18
|
describe('utils', () => {
|
|
15
19
|
describe('stripVersion', async () => {
|
|
@@ -47,7 +51,7 @@ describe('utils', () => {
|
|
|
47
51
|
DATABASE_URL: 'sqlite://./db.sqlite'
|
|
48
52
|
}
|
|
49
53
|
|
|
50
|
-
assert.equal(envObjectToString(env),
|
|
54
|
+
assert.equal(envObjectToString(env), `FOO=bar${EOL}DATABASE_URL=sqlite://./db.sqlite`)
|
|
51
55
|
})
|
|
52
56
|
})
|
|
53
57
|
|
|
@@ -158,4 +162,62 @@ describe('utils', () => {
|
|
|
158
162
|
assert.equal(addPrefixToString('FOO', ''), 'FOO')
|
|
159
163
|
})
|
|
160
164
|
})
|
|
165
|
+
|
|
166
|
+
describe('flattenObject', () => {
|
|
167
|
+
test('should return a single depth object', () => {
|
|
168
|
+
const packageObject = {
|
|
169
|
+
name: '@fastify/oauth2',
|
|
170
|
+
options: {
|
|
171
|
+
name: '{PLT_RIVAL_FST_PLUGIN_OAUTH2_NAME}',
|
|
172
|
+
credentials: {
|
|
173
|
+
client: {
|
|
174
|
+
id: '{PLT_RIVAL_FST_PLUGIN_OAUTH2_CREDENTIALS_CLIENT_ID}',
|
|
175
|
+
secret: '{PLT_RIVAL_FST_PLUGIN_OAUTH2_CREDENTIALS_CLIENT_SECRET}'
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
startRedirectPath: '{PLT_RIVAL_FST_PLUGIN_OAUTH2_REDIRECT_PATH}',
|
|
179
|
+
callbackUri: '{PLT_RIVAL_FST_PLUGIN_OAUTH2_CALLBACK_URI}'
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const expected = {
|
|
183
|
+
name: '@fastify/oauth2',
|
|
184
|
+
'options.name': '{PLT_RIVAL_FST_PLUGIN_OAUTH2_NAME}',
|
|
185
|
+
'options.credentials.client.id': '{PLT_RIVAL_FST_PLUGIN_OAUTH2_CREDENTIALS_CLIENT_ID}',
|
|
186
|
+
'options.credentials.client.secret': '{PLT_RIVAL_FST_PLUGIN_OAUTH2_CREDENTIALS_CLIENT_SECRET}',
|
|
187
|
+
'options.startRedirectPath': '{PLT_RIVAL_FST_PLUGIN_OAUTH2_REDIRECT_PATH}',
|
|
188
|
+
'options.callbackUri': '{PLT_RIVAL_FST_PLUGIN_OAUTH2_CALLBACK_URI}'
|
|
189
|
+
}
|
|
190
|
+
assert.deepEqual(flattenObject(packageObject), expected)
|
|
191
|
+
})
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
describe('getServiceTemplateFromSchemaUrl', () => {
|
|
195
|
+
test('should get the right template name from schema url', () => {
|
|
196
|
+
const composerSchema = 'https://platformatic.dev/schemas/v1.25.0/composer'
|
|
197
|
+
const serviceSchema = 'https://platformatic.dev/schemas/v1.25.0/service'
|
|
198
|
+
const dbSchema = 'https://platformatic.dev/schemas/v1.25.0/db'
|
|
199
|
+
|
|
200
|
+
assert.equal(getServiceTemplateFromSchemaUrl(composerSchema), '@platformatic/composer')
|
|
201
|
+
assert.equal(getServiceTemplateFromSchemaUrl(serviceSchema), '@platformatic/service')
|
|
202
|
+
assert.equal(getServiceTemplateFromSchemaUrl(dbSchema), '@platformatic/db')
|
|
203
|
+
})
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
describe('envStringToObject', () => {
|
|
207
|
+
test('should convert .env-like string to object', () => {
|
|
208
|
+
const template = [
|
|
209
|
+
'',
|
|
210
|
+
'# this is a comment that will be not parsed',
|
|
211
|
+
'MY_VAR=value',
|
|
212
|
+
'PLT_SERVICE_NAME_FOOBAR=foobar'
|
|
213
|
+
]
|
|
214
|
+
|
|
215
|
+
const expected = {
|
|
216
|
+
MY_VAR: 'value',
|
|
217
|
+
PLT_SERVICE_NAME_FOOBAR: 'foobar'
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
assert.deepEqual(envStringToObject(template.join(EOL)), expected)
|
|
221
|
+
})
|
|
222
|
+
})
|
|
161
223
|
})
|