Skip to content

Commit e78bc69

Browse files
committed
Merge branch 'develop' of https://github.com/wheels-dev/wheels into develop
2 parents cf35d3b + 6689568 commit e78bc69

File tree

25 files changed

+1512
-1109
lines changed

25 files changed

+1512
-1109
lines changed

cli/src/commands/wheels/base.cfc

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -657,8 +657,15 @@ component excludeFromHelp=true {
657657
if (left(local.paramValue, 1) == '"' && right(local.paramValue, 1) == '"') {
658658
local.paramValue = mid(local.paramValue, 2, len(local.paramValue) - 2);
659659
}
660-
661-
local.result[local.paramName] = local.paramValue;
660+
661+
// Convert string boolean values to actual booleans
662+
if (lCase(local.paramValue) == "true") {
663+
local.result[local.paramName] = true;
664+
} else if (lCase(local.paramValue) == "false") {
665+
local.result[local.paramName] = false;
666+
} else {
667+
local.result[local.paramName] = local.paramValue;
668+
}
662669
} else {
663670
local.result[local.key] = arguments.argStruct[local.key];
664671
}

cli/src/commands/wheels/generate/app-wizard.cfc

Lines changed: 128 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44
*
55
* This command will ask for:
66
*
7-
* - An Application Name (a new directoery will be created with this name)
7+
* - An Application Name (a new directory will be created with this name)
88
* - Template to use
99
* - A reload Password
1010
* - A datasource name
1111
* - What local cfengine you want to run
12-
* - If using Lucee, do you want to setup a local h2 dev database
13-
* - Do you want to initialize the app as a ForgBox opbject
12+
* - Database and dependencies configuration - only if skipInstall=false:
13+
* - If using Lucee, do you want to setup a local H2 dev database
14+
* - Bootstrap and other dependencies
15+
* - Do you want to initialize the app as a ForgeBox object
1416
*
1517
* {code:bash}
1618
* wheels new
@@ -48,6 +50,8 @@ component aliases="wheels g app-wizard, wheels new" extends="../base" {
4850
* @init "init" the directory as a package if it isn't already
4951
* @force Force installation into an none empty directory
5052
* @nonInteractive Run without prompts, using provided options or defaults
53+
* @expert Show advanced options and configurations
54+
* @skipInstall Skip dependency installation after app creation
5155
**/
5256
function run(
5357
string name = '',
@@ -60,7 +64,9 @@ component aliases="wheels g app-wizard, wheels new" extends="../base" {
6064
boolean setupH2 = true,
6165
boolean init = false,
6266
boolean force = false,
63-
boolean nonInteractive = false
67+
boolean nonInteractive = false,
68+
boolean expert = false,
69+
boolean skipInstall = false
6470
) {
6571
// Initialize detail service
6672
var details = application.wirebox.getInstance("DetailOutputService@wheels-cli");
@@ -89,20 +95,21 @@ component aliases="wheels g app-wizard, wheels new" extends="../base" {
8995
setupH2 = arguments.setupH2,
9096
init = arguments.init,
9197
force = arguments.force,
98+
skipInstall = arguments.skipInstall,
9299
initWizard = true
93100
).run();
94101
return;
95102
}
96103

97104
// ---------------- Welcome
98-
details.header("🧿", "Wheels Application Wizard");
105+
details.header("", "Wheels Application Wizard");
99106
print.line()
100107
.cyanLine( "Welcome to the Wheels app wizard!" )
101108
.cyanLine( "I'll help you create a new Wheels application." )
102109
.line();
103110

104111
// ---------------- Set an app Name
105-
print.yellowBoldLine( "📝 Step 1: Application Name" )
112+
print.yellowBoldLine( "Step 1: Application Name" )
106113
.line()
107114
.text( "Enter a name for your application. " )
108115
.line( "A new directory will be created with this name." )
@@ -138,7 +145,7 @@ component aliases="wheels g app-wizard, wheels new" extends="../base" {
138145
print.line().toConsole();
139146

140147
// ---------------- Template
141-
print.yellowBoldLine( "🎭 Step 2: Choose a Template" )
148+
print.yellowBoldLine( "Step 2: Choose a Template" )
142149
.line()
143150
.text( "Select a template to use as the starting point for your application." )
144151
.line();
@@ -161,7 +168,7 @@ component aliases="wheels g app-wizard, wheels new" extends="../base" {
161168
print.line().toConsole();
162169

163170
// ---------------- Set reload Password
164-
print.yellowBoldLine( "🔒 Step 3: Reload Password" )
171+
print.yellowBoldLine( "Step 3: Reload Password" )
165172
.line()
166173
.text( "Set a reload password to secure your app. " )
167174
.line( "This allows you to restart your app via URL." )
@@ -174,7 +181,7 @@ component aliases="wheels g app-wizard, wheels new" extends="../base" {
174181
print.line();
175182

176183
// ---------------- Set datasource Name
177-
print.yellowBoldLine( "🗝️ Step 4: Database Configuration" )
184+
print.yellowBoldLine( "Step 4: Database Configuration" )
178185
.line()
179186
.text( "Enter a datasource name for your database. " )
180187
.line( "You'll need to configure this in your CFML server admin." )
@@ -193,7 +200,7 @@ component aliases="wheels g app-wizard, wheels new" extends="../base" {
193200
print.line();
194201

195202
// ---------------- Set default server.json engine
196-
print.yellowBoldLine( "⚙️ Step 5: CFML Engine" )
203+
print.yellowBoldLine( "Step 5: CFML Engine" )
197204
.line()
198205
.text( "Select the CFML engine for your application." )
199206
.line();
@@ -221,28 +228,97 @@ component aliases="wheels g app-wizard, wheels new" extends="../base" {
221228
allowH2Creation = true;
222229
}
223230

224-
// ---------------- Test H2 Database?
225-
if ( allowH2Creation ) {
231+
// ---------------- Test H2 Database? (only ask if not skipping installations)
232+
var createH2Embedded = false;
233+
if ( allowH2Creation && !arguments.skipInstall ) {
226234
print.line();
227235
print.Line( 'As you are using Lucee, would you like to setup and use the' ).toConsole();
228-
var createH2Embedded = confirm( 'H2 Java embedded SQL database for development? [y,n]' );
229-
} else {
230-
createH2Embedded = false;
236+
createH2Embedded = confirm( 'H2 Java embedded SQL database for development? [y,n]' );
231237
}
232238

233-
//---------------- This is just an idea at the moment really.
234-
print.line();
235-
print.greenBoldLine( "========= Twitter Bootstrap ======================" ).toConsole();
236-
var useBootstrap=false;
239+
//---------------- Ask about dependencies only if we're not skipping installation
240+
var useBootstrap = false;
241+
if (!arguments.skipInstall) {
242+
print.line();
243+
print.greenBoldLine( "========= Dependencies ======================" ).toConsole();
244+
print.line( "Configure dependencies and plugins for your application." ).toConsole();
245+
237246
if(confirm("Would you like us to setup some default Bootstrap settings? [y/n]")){
238247
useBootstrap = true;
239248
}
249+
} else {
250+
print.line();
251+
print.cyanLine( "========= Dependencies Skipped ================" ).toConsole();
252+
print.line( "Dependency installation is disabled (skipInstall=true)." ).toConsole();
253+
print.line( "Dependencies like Bootstrap and H2 database will not be configured or installed." ).toConsole();
254+
}
240255

241256
// ---------------- Initialize as a package
242257
print.line();
243258
print.line( 'Finally, shall we initialize your application as a package' ).toConsole();
244259
var initPackage = confirm( 'by creating a box.json file? [y,n]' );
245260

261+
// ---------------- Expert Mode Options
262+
var serverPort = 8080;
263+
var jvmSettings = "";
264+
var customEnvConfigs = false;
265+
var advancedRouting = false;
266+
var customPluginRepos = "";
267+
var buildToolIntegration = "";
268+
269+
if (arguments.expert) {
270+
print.line();
271+
print.yellowBoldLine( "Expert Mode: Advanced Configuration" )
272+
.line()
273+
.text( "Configure advanced options for your application." )
274+
.line();
275+
276+
// Custom server port
277+
serverPort = ask(
278+
message = 'Custom server port (leave empty for default 8080): ',
279+
defaultResponse = '8080'
280+
);
281+
if (!isNumeric(serverPort)) {
282+
serverPort = 8080;
283+
}
284+
285+
// JVM Settings
286+
jvmSettings = ask(
287+
message = 'Custom JVM settings (e.g. -Xmx512m -Xms256m): ',
288+
defaultResponse = ''
289+
);
290+
291+
// Environment-specific configurations
292+
print.line();
293+
customEnvConfigs = confirm( 'Setup custom environment configurations (dev, staging, production)? [y,n]' );
294+
295+
// Advanced routing options
296+
print.line();
297+
advancedRouting = confirm( 'Enable advanced routing features (nested resources, constraints)? [y,n]' );
298+
299+
// Custom plugin repositories
300+
customPluginRepos = ask(
301+
message = 'Custom plugin repositories (comma-separated URLs): ',
302+
defaultResponse = ''
303+
);
304+
305+
// Build tool integration
306+
if (len(customPluginRepos)) {
307+
print.line();
308+
buildToolIntegration = multiselect( 'Build tool integration? ' )
309+
.options( [
310+
{value: 'none', display: 'None', selected: true},
311+
{value: 'ant', display: 'Apache Ant'},
312+
{value: 'gradle', display: 'Gradle'},
313+
{value: 'maven', display: 'Maven'},
314+
{value: 'npm', display: 'NPM Scripts'}
315+
] )
316+
.ask();
317+
}
318+
319+
print.line();
320+
}
321+
246322
print.line();
247323
print.line();
248324
print.greenBoldLine( "+-----------------------------------------------------------------------------------+" )
@@ -255,11 +331,40 @@ component aliases="wheels g app-wizard, wheels new" extends="../base" {
255331
.greenBoldLine( '| Reload Password | #ljustify(reloadPassword,57)# |' )
256332
.greenBoldLine( '| Datasource Name | #ljustify(datasourceName,57)# |' )
257333
.greenBoldLine( '| CF Engine | #ljustify(cfmlEngine,57)# |' )
258-
.greenBoldLine( '| Setup Bootstrap | #ljustify(useBootstrap,57)# |' )
259-
.greenBoldLine( '| Setup H2 Database | #ljustify(createH2Embedded,57)# |' )
260334
.greenBoldLine( '| Initialize as Package | #ljustify(initPackage,57)# |' )
261335
.greenBoldLine( '| Force Installation | #ljustify(force,57)# |' )
262-
.greenBoldLine( "+-----------------------+-----------------------------------------------------------+" )
336+
.greenBoldLine( '| Skip Dependency Install | #ljustify(arguments.skipInstall,57)# |' );
337+
338+
// Only show dependency settings if dependencies will be installed
339+
if (!arguments.skipInstall) {
340+
if (allowH2Creation) {
341+
print.greenBoldLine( '| Setup H2 Database | #ljustify(createH2Embedded,57)# |' );
342+
}
343+
print.greenBoldLine( '| Setup Bootstrap | #ljustify(useBootstrap,57)# |' );
344+
}
345+
346+
// Show expert mode options if enabled
347+
if (arguments.expert) {
348+
print.greenBoldLine( '| Expert Mode | #ljustify("Enabled",57)# |' )
349+
.greenBoldLine( '| Server Port | #ljustify(serverPort,57)# |' );
350+
351+
if (len(jvmSettings)) {
352+
print.greenBoldLine( '| JVM Settings | #ljustify(left(jvmSettings, 57),57)# |' );
353+
}
354+
355+
print.greenBoldLine( '| Custom Env Configs | #ljustify(customEnvConfigs,57)# |' )
356+
.greenBoldLine( '| Advanced Routing | #ljustify(advancedRouting,57)# |' );
357+
358+
if (len(customPluginRepos)) {
359+
print.greenBoldLine( '| Plugin Repositories | #ljustify(left(customPluginRepos, 57),57)# |' );
360+
}
361+
362+
if (len(buildToolIntegration) && buildToolIntegration != "none") {
363+
print.greenBoldLine( '| Build Tool | #ljustify(buildToolIntegration,57)# |' );
364+
}
365+
}
366+
367+
print.greenBoldLine( "+-----------------------+-----------------------------------------------------------+" )
263368
.toConsole();
264369

265370
print.line();
@@ -279,6 +384,7 @@ component aliases="wheels g app-wizard, wheels new" extends="../base" {
279384
setupH2 = #createH2Embedded#,
280385
init = #initPackage#,
281386
force = #force#,
387+
skipInstall = #arguments.skipInstall#,
282388
initWizard = true).run();
283389

284390
} else {

cli/src/commands/wheels/generate/app.cfc

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ component aliases="wheels g app" extends="../base" {
6262
* @setupH2 Setup the H2 database for development
6363
* @init "init" the directory as a package if it isn't already
6464
* @force Force installation into an none empty directory
65+
* @skipInstall Skip dependency installation after app creation
6566
**/
6667
function run(
6768
name = 'MyApp',
@@ -73,8 +74,13 @@ component aliases="wheels g app" extends="../base" {
7374
boolean useBootstrap = false,
7475
boolean setupH2 = true,
7576
boolean init = false,
76-
boolean force = false
77+
boolean force = false,
78+
boolean skipInstall = false
7779
) {
80+
81+
// Reconstruct arguments for handling --prefixed options
82+
arguments = reconstructArgs(arguments);
83+
7884
// Initialize detail service
7985
var details = application.wirebox.getInstance("DetailOutputService@wheels-cli");
8086

@@ -90,7 +96,7 @@ component aliases="wheels g app" extends="../base" {
9096
arguments.directory = resolvePath( arguments.directory );
9197

9298
// Output detail header
93-
details.header("🚀", "Creating new Wheels application: #arguments.name#");
99+
details.header("", "Creating new Wheels application: #arguments.name#");
94100

95101
// Validate directory, if it doesn't exist, create it.
96102
if ( !directoryExists( arguments.directory ) ) {
@@ -113,7 +119,7 @@ component aliases="wheels g app" extends="../base" {
113119

114120
// Install the template
115121
details.line();
116-
details.getPrint().yellowLine( "📦 Installing application template: #arguments.template#" );
122+
details.getPrint().yellowLine( "Installing application template: #arguments.template#" );
117123
packageService.installPackage(
118124
ID = arguments.template,
119125
directory = arguments.directory,
@@ -128,7 +134,7 @@ component aliases="wheels g app" extends="../base" {
128134

129135
// Setting Application Name
130136
details.line();
131-
details.getPrint().yellowLine( "🔧 Configuring application..." );
137+
details.getPrint().yellowLine( "Configuring application..." );
132138
command( 'tokenReplace' ).params( path = 'config/app.cfm', token = '|appName|', replacement = arguments.name ).run();
133139
details.update("config/app.cfm", true);
134140
command( 'tokenReplace' ).params( path = 'server.json', token = '|appName|', replacement = arguments.name ).run();
@@ -156,7 +162,7 @@ component aliases="wheels g app" extends="../base" {
156162
// Create h2 embedded db by adding an application.cfc level datasource
157163
if ( arguments.setupH2 ) {
158164
details.line();
159-
details.getPrint().yellowLine( "🗝️ Database Configuration" );
165+
details.getPrint().yellowLine( "Database Configuration" );
160166
var datadirectory = fileSystemUtil.resolvePath( 'db/h2/' );
161167

162168
if ( !directoryExists( datadirectory ) ) {
@@ -222,7 +228,7 @@ component aliases="wheels g app" extends="../base" {
222228
// Definitely refactor this into some sort of templating system?
223229
if(useBootstrap){
224230
details.line();
225-
details.getPrint().yellowLine( "🎨 Installing Bootstrap..." );
231+
details.getPrint().yellowLine( "Installing Bootstrap..." );
226232

227233
// Replace Default Template with something more sensible
228234
var bsLayout=fileRead( getTemplate('/bootstrap/layout.cfm' ) );
@@ -239,7 +245,12 @@ component aliases="wheels g app" extends="../base" {
239245
details.update("config/settings.cfm (Bootstrap settings)", true);
240246

241247
// New Flashwrapper Plugin needed - install it via Forgebox
242-
command( 'install cfwheels-flashmessages-bootstrap' ).run();
248+
if (!arguments.skipInstall) {
249+
command( 'install cfwheels-flashmessages-bootstrap' ).run();
250+
} else {
251+
details.getPrint().yellowLine( "Skipping Bootstrap plugin installation (--skipInstall flag)" );
252+
arrayAppend(nextSteps, "Install Bootstrap plugin: install cfwheels-flashmessages-bootstrap");
253+
}
243254

244255
}
245256

@@ -252,10 +263,16 @@ component aliases="wheels g app" extends="../base" {
252263
arrayAppend(nextSteps, "cd #arguments.name#");
253264

254265
if ( arguments.setupH2 ) {
255-
arrayAppend(nextSteps, "Start server and install H2 extension: start && install && restart");
256-
details.line();
257-
details.getPrint().yellowLine("🛠️ Installing H2 database extension...");
258-
command( 'start && install && restart' ).run();
266+
if (!arguments.skipInstall) {
267+
arrayAppend(nextSteps, "Start server and install H2 extension: start && install && restart");
268+
details.line();
269+
details.getPrint().yellowLine("Installing H2 database extension...");
270+
command( 'start && install && restart' ).run();
271+
} else {
272+
details.line();
273+
details.getPrint().yellowLine("Skipping H2 extension installation (--skipInstall flag)");
274+
arrayAppend(nextSteps, "Install H2 extension manually: start && install && restart");
275+
}
259276
} else {
260277
arrayAppend(nextSteps, "Configure your datasource in Lucee/ACF admin");
261278
arrayAppend(nextSteps, "Start the server: server start");

cli/src/commands/wheels/generate/controller.cfc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ component aliases="wheels g controller" extends="../base" {
2828
string description = "",
2929
boolean force = false
3030
) {
31+
32+
// Reconstruct arguments for handling --prefixed options
33+
arguments = reconstructArgs(arguments);
34+
3135
// Handle API flag implies REST
3236
if (arguments.api) {
3337
arguments.rest = true;
@@ -40,7 +44,7 @@ component aliases="wheels g controller" extends="../base" {
4044
return;
4145
}
4246

43-
detailOutput.header("🎮", "Generating controller: #arguments.name#");
47+
detailOutput.header("", "Generating controller: #arguments.name#");
4448

4549
// Parse actions
4650
var actionList = [];

0 commit comments

Comments
 (0)