Skip to content

Commit 153c45b

Browse files
committed
feat: suggest app name
refs: #17
1 parent f1ac661 commit 153c45b

File tree

5 files changed

+172
-12
lines changed

5 files changed

+172
-12
lines changed

src/Commands/InitCommand.php

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,21 +61,30 @@ class InitCommand extends Command implements Isolatable
6161
'php artisan telescope:install',
6262
];
6363

64+
protected string $appName;
65+
6466
public function handle(): void
6567
{
66-
$appName = $this->argument('application-name');
67-
$kebabName = Str::kebab($appName);
68+
$this->appName = $this->argument('application-name');
69+
70+
$pascalCaseAppName = $this->toPascalCase($this->appName);
71+
72+
if (!$this->isPascalCase($this->appName) && $this->confirm("The application name is not in PascalCase, would you like to use {$pascalCaseAppName}")) {
73+
$this->appName = $pascalCaseAppName;
74+
}
75+
76+
$kebabName = Str::kebab($this->appName);
6877

6978
$this->appUrl = $this->ask('Please enter an application URL', "https://api.dev.{$kebabName}.com");
7079

7180
$envFile = (file_exists('.env')) ? '.env' : '.env.example';
7281

7382
$this->updateConfigFile($envFile, '=', [
74-
'APP_NAME' => $appName,
83+
'APP_NAME' => $this->appName,
7584
]);
7685

7786
$this->updateConfigFile('.env.development', '=', [
78-
'APP_NAME' => $appName,
87+
'APP_NAME' => $this->appName,
7988
'APP_URL' => $this->appUrl,
8089
]);
8190

@@ -154,10 +163,9 @@ protected function createAdminUser(string $kebabName): void
154163

155164
protected function fillReadme(): void
156165
{
157-
$appName = $this->argument('application-name');
158166
$file = $this->loadReadmePart('README.md');
159167

160-
$this->setReadmeValue($file, 'project_name', $appName);
168+
$this->setReadmeValue($file, 'project_name', $this->appName);
161169

162170
$type = $this->choice(
163171
question: 'What type of application will your API serve?',
@@ -358,4 +366,21 @@ protected function saveReadme(): void
358366
{
359367
file_put_contents('README.md', $this->readmeContent);
360368
}
369+
370+
protected function toPascalCase(string $string): string
371+
{
372+
// Remove non-alphanumeric characters except underscores
373+
$string = preg_replace('/[^a-zA-Z0-9_]/', '', $string);
374+
375+
// Replace underscores with spaces, then uppercase the first letter of each word
376+
$string = ucwords(str_replace('_', ' ', $string));
377+
378+
// Remove spaces
379+
return str_replace(' ', '', $string);
380+
}
381+
382+
protected function isPascalCase(string $string): bool
383+
{
384+
return preg_match('/^[A-Z][a-zA-Z0-9]*$/', $string);
385+
}
361386
}

tests/InitCommandTest.php

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,45 @@ public function testRunWithoutAdminAndReadmeCreation()
3333

3434
$this
3535
->artisan('init "My App"')
36+
->expectsConfirmation('The application name is not in PascalCase, would you like to use MyApp')
37+
->expectsOutput('Project initialized successfully!')
38+
->expectsQuestion('Please enter an application URL', 'https://mysite.com')
39+
->expectsConfirmation('Do you want to generate an admin user?')
40+
->expectsConfirmation('Do you want to generate a README file?')
41+
->expectsConfirmation('Do you want to install media package?')
42+
->expectsConfirmation('Do you want to uninstall project-initializator package?')
43+
->assertExitCode(0);
44+
}
45+
46+
public function testRunWithoutAdminAndReadmeCreationConvertAppNameToPascalCase()
47+
{
48+
$this->mockFileGetContent(
49+
[
50+
'arguments' => ['.env.example'],
51+
'result' => $this->getFixture('env.example_app_name_pascal_case.yml'),
52+
],
53+
[
54+
'arguments' => ['.env.development'],
55+
'result' => $this->getFixture('env.development_app_name_pascal_case.yml'),
56+
],
57+
);
58+
59+
$this->mockFilePutContent(
60+
'env.example_app_name_pascal_case.yml',
61+
'env.development_app_name_pascal_case.yml',
62+
);
63+
64+
$this->mockShellExec(
65+
['arguments' => 'composer require ronasit/laravel-helpers --ansi'],
66+
['arguments' => 'composer require ronasit/laravel-swagger --ansi'],
67+
['arguments' => 'composer require --dev ronasit/laravel-entity-generator --ansi'],
68+
['arguments' => 'composer require laravel/telescope --ansi'],
69+
['arguments' => 'php artisan telescope:install --ansi'],
70+
);
71+
72+
$this
73+
->artisan('init "My App"')
74+
->expectsConfirmation('The application name is not in PascalCase, would you like to use MyApp', 'yes')
3675
->expectsOutput('Project initialized successfully!')
3776
->expectsQuestion('Please enter an application URL', 'https://mysite.com')
3877
->expectsConfirmation('Do you want to generate an admin user?')
@@ -56,12 +95,14 @@ public function testRunWithAdminAndWithoutReadmeCreation()
5695
);
5796

5897
$this->mockFilePutContent(
98+
'env.example.yml',
99+
'env.development.yml',
59100
[
60101
'database/migrations/2018_11_11_111111_add_default_user.php',
61102
$this->getFixture('migration.php'),
62103
'optionalParameter',
63104
'optionalParameter',
64-
]
105+
],
65106
);
66107

67108
$this->mockShellExec(
@@ -74,6 +115,7 @@ public function testRunWithAdminAndWithoutReadmeCreation()
74115

75116
$this
76117
->artisan('init "My App"')
118+
->expectsConfirmation('The application name is not in PascalCase, would you like to use MyApp')
77119
->expectsOutput('Project initialized successfully!')
78120
->expectsQuestion('Please enter an application URL', 'https://mysite.com')
79121
->expectsConfirmation('Do you want to generate an admin user?', 'yes')
@@ -133,6 +175,8 @@ public function testRunWithAdminAndDefaultReadmeCreation()
133175
);
134176

135177
$this->mockFilePutContent(
178+
'env.example.yml',
179+
'env.development.yml',
136180
[
137181
'database/migrations/2018_11_11_111111_add_default_user.php',
138182
$this->getFixture('migration.php'),
@@ -158,6 +202,7 @@ public function testRunWithAdminAndDefaultReadmeCreation()
158202

159203
$this
160204
->artisan('init "My App"')
205+
->expectsConfirmation('The application name is not in PascalCase, would you like to use MyApp')
161206
->expectsOutput('Project initialized successfully!')
162207
->expectsQuestion('Please enter an application URL', 'https://mysite.com')
163208
->expectsConfirmation('Do you want to generate an admin user?', 'yes')
@@ -263,6 +308,8 @@ public function testRunWithAdminAndPartialReadmeCreation()
263308
);
264309

265310
$this->mockFilePutContent(
311+
'env.example.yml',
312+
'env.development.yml',
266313
[
267314
'README.md',
268315
$this->getFixture('partial_readme.md'),
@@ -281,6 +328,7 @@ public function testRunWithAdminAndPartialReadmeCreation()
281328

282329
$this
283330
->artisan('init "My App"')
331+
->expectsConfirmation('The application name is not in PascalCase, would you like to use MyApp')
284332
->expectsOutput('Project initialized successfully!')
285333
->expectsQuestion('Please enter an application URL', 'https://mysite.com')
286334
->expectsConfirmation('Do you want to generate an admin user?')
@@ -383,6 +431,8 @@ public function testRunWithAdminAndFullReadmeCreationAndRemovingInitializatorIns
383431
);
384432

385433
$this->mockFilePutContent(
434+
'env.example.yml',
435+
'env.development.yml',
386436
[
387437
'database/migrations/2018_11_11_111111_add_default_user.php',
388438
$this->getFixture('migration.php'),
@@ -410,6 +460,7 @@ public function testRunWithAdminAndFullReadmeCreationAndRemovingInitializatorIns
410460

411461
$this
412462
->artisan('init "My App"')
463+
->expectsConfirmation('The application name is not in PascalCase, would you like to use MyApp')
413464
->expectsOutput('Project initialized successfully!')
414465
->expectsQuestion('Please enter an application URL', 'https://mysite.com')
415466
->expectsConfirmation('Do you want to generate an admin user?', 'yes')

tests/Support/Traits/InitCommandMockTrait.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@ trait InitCommandMockTrait
99
{
1010
use MockTrait;
1111

12-
public function mockFilePutContent(...$arguments): void
13-
{
12+
public function mockFilePutContent(
13+
string $exampleEnvFixtureName = 'env.example.yml',
14+
string $developmentEnvFixtureName = 'env.development.yml',
15+
...$arguments
16+
): void {
1417
$callChain = [
15-
['.env.example', $this->getFixture('env.example.yml'), 'optionalParameter', 'optionalParameter'],
16-
['.env.development', $this->getFixture('env.development.yml'), 'optionalParameter', 'optionalParameter'],
18+
['.env.example', $this->getFixture($exampleEnvFixtureName), 'optionalParameter', 'optionalParameter'],
19+
['.env.development', $this->getFixture($developmentEnvFixtureName), 'optionalParameter', 'optionalParameter'],
1720
...$arguments,
1821
];
1922

@@ -22,7 +25,7 @@ public function mockFilePutContent(...$arguments): void
2225
callChain: array_map(
2326
fn ($call) => $this->functionCall('file_put_contents', $call),
2427
$callChain,
25-
)
28+
),
2629
);
2730
}
2831

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
APP_NAME=MyApp
2+
APP_ENV=development
3+
APP_KEY=
4+
APP_DEBUG=true
5+
APP_LOG_LEVEL=debug
6+
APP_URL=https://mysite.com
7+
8+
DB_CONNECTION=pgsql
9+
DB_HOST=
10+
DB_PORT=
11+
DB_DATABASE=
12+
DB_USERNAME=
13+
DB_PASSWORD=
14+
15+
BROADCAST_DRIVER=log
16+
CACHE_DRIVER=file
17+
SESSION_DRIVER=redis
18+
QUEUE_CONNECTION=redis
19+
20+
REDIS_HOST=redis
21+
REDIS_PASSWORD=
22+
REDIS_PORT=
23+
24+
MAIL_DRIVER=smtp
25+
MAIL_HOST=
26+
MAIL_PORT=
27+
MAIL_USERNAME=
28+
MAIL_PASSWORD=
29+
MAIL_ENCRYPTION=
30+
31+
FILESYSTEM_DISK=gcs
32+
33+
PUSHER_APP_ID=
34+
PUSHER_APP_KEY=
35+
PUSHER_APP_SECRET=
36+
37+
FRONTEND_URL=
38+
39+
JWT_SHOW_BLACKLIST_EXCEPTION=true
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
APP_NAME=MyApp
2+
APP_ENV=local
3+
APP_KEY=
4+
APP_DEBUG=true
5+
APP_LOG_LEVEL=debug
6+
APP_URL=http://localhost
7+
8+
DB_CONNECTION=pgsql
9+
DB_HOST=pgsql
10+
DB_PORT=5432
11+
DB_DATABASE=postgres
12+
DB_USERNAME=postgres
13+
DB_PASSWORD=""
14+
15+
BROADCAST_DRIVER=log
16+
CACHE_DRIVER=redis
17+
SESSION_DRIVER=redis
18+
QUEUE_CONNECTION=sync
19+
20+
REDIS_HOST=redis
21+
REDIS_PASSWORD=null
22+
REDIS_PORT=6379
23+
24+
MAIL_DRIVER=smtp
25+
MAIL_HOST=smtp.mailtrap.io
26+
MAIL_PORT=2525
27+
MAIL_USERNAME=null
28+
MAIL_PASSWORD=null
29+
MAIL_ENCRYPTION=null
30+
31+
FILESYSTEM_DISK=local
32+
GOOGLE_CLOUD_STORAGE_BUCKET=ronasit-development
33+
GOOGLE_CLOUD_PROJECT_ID=ronas-it-development
34+
35+
PUSHER_APP_ID=
36+
PUSHER_APP_KEY=
37+
PUSHER_APP_SECRET=
38+
39+
FRONTEND_URL=http://localhost
40+
41+
JWT_SECRET=
42+
JWT_SHOW_BLACKLIST_EXCEPTION=true

0 commit comments

Comments
 (0)