@friggframework/devtools 2.0.0--canary.424.a864ff6.0 → 2.0.0--canary.419.daed467.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/frigg-cli/index.js +6 -33
- package/frigg-cli/index.test.js +4 -4
- package/frigg-cli/init-command/backend-first-handler.js +3 -42
- package/frigg-cli/init-command/index.js +6 -52
- package/frigg-cli/test/init-command.test.js +4 -78
- package/frigg-cli/test/npm-registry.test.js +1 -1
- package/infrastructure/README.md +114 -104
- package/infrastructure/serverless-template.js +7 -0
- package/management-ui/server/api/cli.js +3 -6
- package/management-ui/server/utils/cliIntegration.js +4 -18
- package/package.json +6 -6
- package/frigg-cli/NON_INTERACTIVE_MODE.md +0 -290
- package/frigg-cli/__tests__/unit/commands/backend-first-handler.test.js +0 -207
- package/frigg-cli/init-command/frigg-config.example.json +0 -13
- package/frigg-cli/templates/backend/index.js +0 -42
- package/frigg-cli/templates/backend/infrastructure.js +0 -36
- package/frigg-cli/templates/backend/package.json +0 -18
- package/frigg-cli/templates/backend/serverless.yml +0 -25
- package/frigg-cli/test/init-cli.test.js +0 -48
package/frigg-cli/index.js
CHANGED
|
@@ -12,27 +12,11 @@ const { uiCommand } = require('./ui-command');
|
|
|
12
12
|
const program = new Command();
|
|
13
13
|
|
|
14
14
|
program
|
|
15
|
-
.command('init [
|
|
15
|
+
.command('init [templateName]')
|
|
16
16
|
.description('Initialize a new Frigg application')
|
|
17
|
-
.option('-
|
|
18
|
-
.option('--
|
|
19
|
-
.option('--
|
|
20
|
-
.option('--no-interactive', 'run without interactive prompts')
|
|
21
|
-
.option('--non-interactive', 'run without interactive prompts (alias for --no-interactive)')
|
|
22
|
-
.option('--yes', 'auto-accept all defaults (non-interactive mode)')
|
|
23
|
-
.option('--app-purpose <purpose>', 'application purpose (own-app|platform|exploring)')
|
|
24
|
-
.option('--include-integrations', 'include starter integrations')
|
|
25
|
-
.option('--no-include-integrations', 'skip starter integrations')
|
|
26
|
-
.option('--include-api-module', 'create custom API module')
|
|
27
|
-
.option('--no-include-api-module', 'skip custom API module')
|
|
28
|
-
.option('--serverless-provider <provider>', 'serverless provider (aws|local)')
|
|
29
|
-
.option('--install-deps', 'install dependencies')
|
|
30
|
-
.option('--no-install-deps', 'skip dependency installation')
|
|
31
|
-
.option('--init-git', 'initialize git repository')
|
|
32
|
-
.option('--no-init-git', 'skip git initialization')
|
|
33
|
-
.option('--config <path>', 'configuration file path')
|
|
34
|
-
.option('-f, --force', 'overwrite existing directory')
|
|
35
|
-
.option('-v, --verbose', 'enable verbose output')
|
|
17
|
+
.option('-t, --template <template>', 'template to use', 'backend-only')
|
|
18
|
+
.option('-n, --name <name>', 'project name')
|
|
19
|
+
.option('-d, --directory <directory>', 'target directory')
|
|
36
20
|
.action(initCommand);
|
|
37
21
|
|
|
38
22
|
program
|
|
@@ -77,17 +61,6 @@ program
|
|
|
77
61
|
.option('--no-open', 'do not open browser automatically')
|
|
78
62
|
.action(uiCommand);
|
|
79
63
|
|
|
80
|
-
|
|
81
|
-
program.parse(process.argv);
|
|
82
|
-
}
|
|
64
|
+
program.parse(process.argv);
|
|
83
65
|
|
|
84
|
-
module.exports = {
|
|
85
|
-
program,
|
|
86
|
-
initCommand,
|
|
87
|
-
installCommand,
|
|
88
|
-
startCommand,
|
|
89
|
-
buildCommand,
|
|
90
|
-
deployCommand,
|
|
91
|
-
generateIamCommand,
|
|
92
|
-
uiCommand
|
|
93
|
-
};
|
|
66
|
+
module.exports = { initCommand, installCommand, startCommand, buildCommand, deployCommand, generateIamCommand, uiCommand };
|
package/frigg-cli/index.test.js
CHANGED
|
@@ -8,7 +8,7 @@ const { updateBackendJsFile } = require('./install-command/backend-js');
|
|
|
8
8
|
const { commitChanges } = require('./install-command/commit-changes');
|
|
9
9
|
const { logInfo, logError } = require('./install-command/logger');
|
|
10
10
|
|
|
11
|
-
describe
|
|
11
|
+
describe('CLI Command Tests', () => {
|
|
12
12
|
it('should successfully install an API module when all steps complete without errors', async () => {
|
|
13
13
|
const mockApiModuleName = 'testModule';
|
|
14
14
|
const mockPackageName = `@friggframework/api-module-${mockApiModuleName}`;
|
|
@@ -46,7 +46,7 @@ describe.skip('CLI Command Tests', () => {
|
|
|
46
46
|
.description('Install an API module')
|
|
47
47
|
.action(installCommand);
|
|
48
48
|
|
|
49
|
-
await program.parseAsync(['node', '
|
|
49
|
+
await program.parseAsync(['node', 'install', mockApiModuleName]);
|
|
50
50
|
|
|
51
51
|
expect(validatePackageExists).toHaveBeenCalledWith(mockPackageName);
|
|
52
52
|
expect(findNearestBackendPackageJson).toHaveBeenCalled();
|
|
@@ -94,7 +94,7 @@ describe.skip('CLI Command Tests', () => {
|
|
|
94
94
|
.description('Install an API module')
|
|
95
95
|
.action(installCommand);
|
|
96
96
|
|
|
97
|
-
await program.parseAsync(['node', '
|
|
97
|
+
await program.parseAsync(['node', 'install', 'nonexistent-package']);
|
|
98
98
|
|
|
99
99
|
expect(mockValidatePackageExists).toHaveBeenCalledWith(
|
|
100
100
|
'@friggframework/api-module-nonexistent-package'
|
|
@@ -141,7 +141,7 @@ describe.skip('CLI Command Tests', () => {
|
|
|
141
141
|
.description('Install an API module')
|
|
142
142
|
.action(installCommand);
|
|
143
143
|
|
|
144
|
-
await program.parseAsync(['node', '
|
|
144
|
+
await program.parseAsync(['node', 'install', 'test-module']);
|
|
145
145
|
|
|
146
146
|
expect(mockLogError).toHaveBeenCalledWith(
|
|
147
147
|
'An error occurred:',
|
|
@@ -14,7 +14,7 @@ class BackendFirstHandler {
|
|
|
14
14
|
constructor(targetPath, options = {}) {
|
|
15
15
|
this.targetPath = targetPath;
|
|
16
16
|
this.appName = path.basename(targetPath);
|
|
17
|
-
this.options =
|
|
17
|
+
this.options = options;
|
|
18
18
|
this.templatesDir = path.join(__dirname, '..', 'templates');
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -36,8 +36,8 @@ class BackendFirstHandler {
|
|
|
36
36
|
|
|
37
37
|
console.log(chalk.green('\n✅ Frigg application created successfully!'));
|
|
38
38
|
|
|
39
|
-
// If user needs custom API module, prompt to create it
|
|
40
|
-
if (config.needsCustomApiModule
|
|
39
|
+
// If user needs custom API module, prompt to create it
|
|
40
|
+
if (config.needsCustomApiModule) {
|
|
41
41
|
console.log(chalk.cyan('\n🔧 Now let\'s create your custom API module...'));
|
|
42
42
|
const createModule = await confirm({
|
|
43
43
|
message: 'Would you like to create your custom API module now?',
|
|
@@ -49,11 +49,6 @@ class BackendFirstHandler {
|
|
|
49
49
|
console.log(chalk.cyan(` cd ${path.relative(process.cwd(), this.targetPath)}`));
|
|
50
50
|
console.log(chalk.cyan(' frigg generate:api-module\n'));
|
|
51
51
|
}
|
|
52
|
-
} else if (config.needsCustomApiModule && (this.options.nonInteractive || !this.options.interactive)) {
|
|
53
|
-
console.log(chalk.cyan('\n🔧 Custom API module needed'));
|
|
54
|
-
console.log(chalk.gray('\n Run this command after setup:'));
|
|
55
|
-
console.log(chalk.cyan(` cd ${path.relative(process.cwd(), this.targetPath)}`));
|
|
56
|
-
console.log(chalk.cyan(' frigg generate:api-module\n'));
|
|
57
52
|
}
|
|
58
53
|
|
|
59
54
|
this.displayNextSteps(deploymentMode, config);
|
|
@@ -67,10 +62,6 @@ class BackendFirstHandler {
|
|
|
67
62
|
return this.options.mode;
|
|
68
63
|
}
|
|
69
64
|
|
|
70
|
-
if (!this.options.interactive || this.options.nonInteractive) {
|
|
71
|
-
return 'standalone';
|
|
72
|
-
}
|
|
73
|
-
|
|
74
65
|
const mode = await select({
|
|
75
66
|
message: 'How will you deploy this Frigg application?',
|
|
76
67
|
choices: [
|
|
@@ -91,42 +82,12 @@ class BackendFirstHandler {
|
|
|
91
82
|
return mode;
|
|
92
83
|
}
|
|
93
84
|
|
|
94
|
-
/**
|
|
95
|
-
* Get default configuration for non-interactive mode
|
|
96
|
-
*/
|
|
97
|
-
getDefaultConfiguration(deploymentMode) {
|
|
98
|
-
const config = {
|
|
99
|
-
deploymentMode,
|
|
100
|
-
appPurpose: this.options.appPurpose || 'exploring',
|
|
101
|
-
needsCustomApiModule: this.options.includeApiModule || false,
|
|
102
|
-
includeIntegrations: this.options.includeIntegrations || false,
|
|
103
|
-
starterIntegrations: this.options.starterIntegrations || [],
|
|
104
|
-
includeDemoFrontend: this.options.frontend === true,
|
|
105
|
-
frontendFramework: this.options.frontendFramework || 'react',
|
|
106
|
-
demoAuthMode: this.options.demoAuthMode || 'mock',
|
|
107
|
-
serverlessProvider: this.options.serverlessProvider || (deploymentMode === 'standalone' ? 'aws' : undefined),
|
|
108
|
-
installDependencies: this.options.installDependencies !== false,
|
|
109
|
-
initializeGit: this.options.initializeGit !== false
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
// If app purpose is 'own-app' and no explicit API module setting, default to true
|
|
113
|
-
if (config.appPurpose === 'own-app' && this.options.includeApiModule === undefined) {
|
|
114
|
-
config.needsCustomApiModule = true;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return config;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
85
|
/**
|
|
121
86
|
* Get project configuration based on deployment mode
|
|
122
87
|
*/
|
|
123
88
|
async getProjectConfiguration(deploymentMode) {
|
|
124
89
|
const config = { deploymentMode };
|
|
125
90
|
|
|
126
|
-
if (!this.options.interactive || this.options.nonInteractive) {
|
|
127
|
-
return this.getDefaultConfiguration(deploymentMode);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
91
|
// Ask about the purpose of this Frigg application
|
|
131
92
|
config.appPurpose = await select({
|
|
132
93
|
message: 'What are you building with Frigg?',
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
|
|
10
10
|
const path = require('path');
|
|
11
11
|
const chalk = require('chalk');
|
|
12
|
-
const fs = require('fs-extra');
|
|
13
12
|
const validateProjectName = require('validate-npm-package-name');
|
|
14
13
|
const semver = require('semver');
|
|
15
14
|
const BackendFirstHandler = require('./backend-first-handler');
|
|
@@ -55,10 +54,6 @@ async function initCommand(projectName, options) {
|
|
|
55
54
|
const verbose = options.verbose || false;
|
|
56
55
|
const force = options.force || false;
|
|
57
56
|
|
|
58
|
-
// Handle non-interactive mode flags
|
|
59
|
-
const nonInteractive = options.nonInteractive || options['no-interactive'] || options.yes || false;
|
|
60
|
-
const interactive = !nonInteractive;
|
|
61
|
-
|
|
62
57
|
checkNodeVersion();
|
|
63
58
|
|
|
64
59
|
const root = path.resolve(projectName);
|
|
@@ -66,56 +61,15 @@ async function initCommand(projectName, options) {
|
|
|
66
61
|
|
|
67
62
|
checkAppName(appName);
|
|
68
63
|
|
|
69
|
-
// Load configuration from file if provided
|
|
70
|
-
let configFromFile = {};
|
|
71
|
-
if (options.config) {
|
|
72
|
-
try {
|
|
73
|
-
const configPath = path.resolve(options.config);
|
|
74
|
-
if (await fs.pathExists(configPath)) {
|
|
75
|
-
configFromFile = await fs.readJSON(configPath);
|
|
76
|
-
} else {
|
|
77
|
-
console.log(chalk.yellow(`Warning: Config file not found: ${configPath}`));
|
|
78
|
-
}
|
|
79
|
-
} catch (error) {
|
|
80
|
-
console.log(chalk.yellow(`Warning: Could not load config file: ${error.message}`));
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Merge options with environment variables and config file
|
|
85
|
-
const mergedOptions = {
|
|
86
|
-
force,
|
|
87
|
-
verbose,
|
|
88
|
-
mode: options.mode || process.env.FRIGG_DEPLOYMENT_MODE || configFromFile.deploymentMode,
|
|
89
|
-
frontend: options.frontend !== undefined ? options.frontend :
|
|
90
|
-
process.env.FRIGG_INCLUDE_FRONTEND !== undefined ? process.env.FRIGG_INCLUDE_FRONTEND === 'true' :
|
|
91
|
-
configFromFile.includeFrontend,
|
|
92
|
-
interactive,
|
|
93
|
-
nonInteractive,
|
|
94
|
-
appPurpose: options.appPurpose || process.env.FRIGG_APP_PURPOSE || configFromFile.appPurpose,
|
|
95
|
-
includeIntegrations: options.includeIntegrations !== undefined ? options.includeIntegrations :
|
|
96
|
-
process.env.FRIGG_INCLUDE_INTEGRATIONS !== undefined ? process.env.FRIGG_INCLUDE_INTEGRATIONS === 'true' :
|
|
97
|
-
configFromFile.includeIntegrations,
|
|
98
|
-
includeApiModule: options.includeApiModule !== undefined ? options.includeApiModule :
|
|
99
|
-
process.env.FRIGG_INCLUDE_API_MODULE !== undefined ? process.env.FRIGG_INCLUDE_API_MODULE === 'true' :
|
|
100
|
-
configFromFile.includeApiModule,
|
|
101
|
-
serverlessProvider: options.serverlessProvider || process.env.FRIGG_SERVERLESS_PROVIDER || configFromFile.serverlessProvider,
|
|
102
|
-
installDependencies: options.installDeps !== undefined ? options.installDeps :
|
|
103
|
-
process.env.FRIGG_INSTALL_DEPS !== undefined ? process.env.FRIGG_INSTALL_DEPS === 'true' :
|
|
104
|
-
configFromFile.installDependencies,
|
|
105
|
-
initializeGit: options.initGit !== undefined ? options.initGit :
|
|
106
|
-
process.env.FRIGG_INIT_GIT !== undefined ? process.env.FRIGG_INIT_GIT === 'true' :
|
|
107
|
-
configFromFile.initializeGit,
|
|
108
|
-
starterIntegrations: process.env.FRIGG_STARTER_INTEGRATIONS ?
|
|
109
|
-
process.env.FRIGG_STARTER_INTEGRATIONS.split(',').map(s => s.trim()) :
|
|
110
|
-
configFromFile.starterIntegrations,
|
|
111
|
-
frontendFramework: process.env.FRIGG_FRONTEND_FRAMEWORK || configFromFile.frontendFramework,
|
|
112
|
-
demoAuthMode: process.env.FRIGG_DEMO_AUTH_MODE || configFromFile.demoAuthMode
|
|
113
|
-
};
|
|
114
|
-
|
|
115
64
|
// Use backend-first handler by default
|
|
116
65
|
if (!options.template && !options.legacyFrontend) {
|
|
117
66
|
try {
|
|
118
|
-
const handler = new BackendFirstHandler(root,
|
|
67
|
+
const handler = new BackendFirstHandler(root, {
|
|
68
|
+
force,
|
|
69
|
+
verbose,
|
|
70
|
+
mode: options.mode,
|
|
71
|
+
frontend: options.frontend
|
|
72
|
+
});
|
|
119
73
|
|
|
120
74
|
await handler.initialize();
|
|
121
75
|
return;
|
|
@@ -128,89 +128,15 @@ describe('Init Command', () => {
|
|
|
128
128
|
force: true,
|
|
129
129
|
verbose: true,
|
|
130
130
|
mode: 'standalone',
|
|
131
|
-
frontend: false
|
|
132
|
-
interactive: false
|
|
131
|
+
frontend: false
|
|
133
132
|
};
|
|
134
|
-
|
|
135
|
-
await initCommand(mockProjectName, options);
|
|
136
|
-
|
|
137
|
-
expect(BackendFirstHandler).toHaveBeenCalledWith(
|
|
138
|
-
expect.any(String),
|
|
139
|
-
expect.objectContaining({
|
|
140
|
-
force: true,
|
|
141
|
-
verbose: true,
|
|
142
|
-
mode: 'standalone',
|
|
143
|
-
frontend: false,
|
|
144
|
-
interactive: true, // This gets set to true because interactive: false is not the same as nonInteractive: true
|
|
145
|
-
nonInteractive: false
|
|
146
|
-
})
|
|
147
|
-
);
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it('should handle non-interactive mode with --non-interactive flag', async () => {
|
|
151
|
-
const options = {
|
|
152
|
-
nonInteractive: true,
|
|
153
|
-
mode: 'standalone',
|
|
154
|
-
appPurpose: 'own-app'
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
await initCommand(mockProjectName, options);
|
|
158
|
-
|
|
159
|
-
expect(BackendFirstHandler).toHaveBeenCalledWith(
|
|
160
|
-
expect.any(String),
|
|
161
|
-
expect.objectContaining({
|
|
162
|
-
nonInteractive: true,
|
|
163
|
-
interactive: false,
|
|
164
|
-
mode: 'standalone',
|
|
165
|
-
appPurpose: 'own-app'
|
|
166
|
-
})
|
|
167
|
-
);
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
it('should handle non-interactive mode with --yes flag', async () => {
|
|
171
|
-
const options = {
|
|
172
|
-
yes: true,
|
|
173
|
-
mode: 'embedded'
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
await initCommand(mockProjectName, options);
|
|
177
|
-
|
|
178
|
-
expect(BackendFirstHandler).toHaveBeenCalledWith(
|
|
179
|
-
expect.any(String),
|
|
180
|
-
expect.objectContaining({
|
|
181
|
-
nonInteractive: true,
|
|
182
|
-
interactive: false,
|
|
183
|
-
mode: 'embedded'
|
|
184
|
-
})
|
|
185
|
-
);
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
it('should handle environment variables', async () => {
|
|
189
|
-
const originalEnv = process.env.FRIGG_DEPLOYMENT_MODE;
|
|
190
|
-
process.env.FRIGG_DEPLOYMENT_MODE = 'embedded';
|
|
191
|
-
process.env.FRIGG_APP_PURPOSE = 'platform';
|
|
192
|
-
|
|
193
|
-
const options = {
|
|
194
|
-
nonInteractive: true
|
|
195
|
-
};
|
|
196
|
-
|
|
133
|
+
|
|
197
134
|
await initCommand(mockProjectName, options);
|
|
198
|
-
|
|
135
|
+
|
|
199
136
|
expect(BackendFirstHandler).toHaveBeenCalledWith(
|
|
200
137
|
expect.any(String),
|
|
201
|
-
expect.objectContaining(
|
|
202
|
-
mode: 'embedded',
|
|
203
|
-
appPurpose: 'platform'
|
|
204
|
-
})
|
|
138
|
+
expect.objectContaining(options)
|
|
205
139
|
);
|
|
206
|
-
|
|
207
|
-
// Clean up
|
|
208
|
-
if (originalEnv !== undefined) {
|
|
209
|
-
process.env.FRIGG_DEPLOYMENT_MODE = originalEnv;
|
|
210
|
-
} else {
|
|
211
|
-
delete process.env.FRIGG_DEPLOYMENT_MODE;
|
|
212
|
-
}
|
|
213
|
-
delete process.env.FRIGG_APP_PURPOSE;
|
|
214
140
|
});
|
|
215
141
|
|
|
216
142
|
it('should handle initialization errors gracefully', async () => {
|