Skip to content

Commit b2f527a

Browse files
AlexJump24jbrooksuk
authored andcommitted
Initial work on the install command to save app settings
1 parent 3a983bb commit b2f527a

File tree

9 files changed

+152
-23
lines changed

9 files changed

+152
-23
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"illuminate/events": "^11.0",
3030
"illuminate/queue": "^11.0",
3131
"illuminate/support": "^11.0",
32+
"laravel/prompts": "^0.1",
3233
"nesbot/carbon": "^2.70",
3334
"spatie/laravel-query-builder": "^5.5",
3435
"spatie/laravel-settings": "^3.2",

database/migrations/2024_01_22_205110_create_default_settings.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,16 @@ public function up(): void
1212
{
1313
// Cachet settings...
1414
rescue(fn () => $this->migrator->add('app.install_id', Str::random(40)));
15-
rescue(fn () => $this->migrator->add('app.name', 'Cachet'));
16-
rescue(fn () => $this->migrator->add('app.domain'));
15+
rescue(fn () => $this->migrator->add('app.name', 'Cachet V3'));
16+
rescue(fn () => $this->migrator->add('app.domain', <<<'ABOUT'
17+
Cachet is a **beautiful** and **powerful** open-source status page system.
18+
19+
To access the [dashboard](/dashboard), use the following credentials:
20+
21+
- `test123`
22+
23+
Please [consider sponsoring](https://github.com/cachethq/cachet?sponsor=1) the continued development of Cachet.
24+
ABOUT));
1725
rescue(fn () => $this->migrator->add('app.about'));
1826
rescue(fn () => $this->migrator->add('app.timezone', 'UTC'));
1927
rescue(fn () => $this->migrator->add('app.locale', 'en'));

database/seeders/DatabaseSeeder.php

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -161,27 +161,6 @@ public function run(): void
161161
'engine' => IncidentTemplateEngineEnum::twig,
162162
]);
163163

164-
$appSettings = app(AppSettings::class);
165-
$appSettings->name = 'Cachet v3.x Demo';
166-
$appSettings->about = <<<'ABOUT'
167-
Cachet is a **beautiful** and **powerful** open-source status page system.
168-
169-
To access the [dashboard](/dashboard), use the following credentials:
170-
171-
- `test123`
172-
173-
Please [consider sponsoring](https://github.com/cachethq/cachet?sponsor=1) the continued development of Cachet.
174-
ABOUT;
175-
$appSettings->show_support = true;
176-
$appSettings->timezone = 'UTC';
177-
$appSettings->show_timezone = false;
178-
$appSettings->only_disrupted_days = false;
179-
$appSettings->incident_days = 7;
180-
$appSettings->refresh_rate = null;
181-
$appSettings->dashboard_login_link = true;
182-
$appSettings->major_outage_threshold = 25;
183-
$appSettings->save();
184-
185164
$customizationSettings = app(CustomizationSettings::class);
186165
$customizationSettings->header = <<<'HTML'
187166
<script src="https://cdn.usefathom.com/script.js" data-site="NQKCLYJJ" defer></script>

src/CachetCoreServiceProvider.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ private function registerCommands(): void
151151
{
152152
if ($this->app->runningInConsole()) {
153153
$this->commands([
154+
Commands\InstallCommand::class,
154155
Commands\SendBeaconCommand::class,
155156
Commands\VersionCommand::class,
156157
]);

src/Commands/InstallCommand.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
namespace Cachet\Commands;
4+
5+
use Cachet\Settings\AppSettings;
6+
use Cachet\Settings\Attributes\Description;
7+
use Illuminate\Console\Command;
8+
use Illuminate\Support\Sleep;
9+
use ReflectionClass;
10+
use ReflectionProperty;
11+
use function Laravel\Prompts\confirm;
12+
use function Laravel\Prompts\info;
13+
use function Laravel\Prompts\text;
14+
15+
16+
class InstallCommand extends Command
17+
{
18+
protected $name = 'cachet:install';
19+
20+
protected $description = 'Install Cachet';
21+
22+
public function handle(AppSettings $settings)
23+
{
24+
info('Welcome to the Cachet installer!');
25+
26+
Sleep::for(2)->seconds();
27+
28+
if (confirm('Do you want to configure Cachet before installing?', true)) {
29+
info('Configuring Cachet...');
30+
$this->configureDatabaseSettings($settings);
31+
}
32+
33+
info('Installing Cachet...');
34+
35+
info('Cachet has been installed successfully!');
36+
37+
return Command::SUCCESS;
38+
}
39+
40+
protected function configureDatabaseSettings(AppSettings $settings): void
41+
{
42+
collect(
43+
(new ReflectionClass($settings))->getProperties(ReflectionProperty::IS_PUBLIC)
44+
)
45+
->filter(fn (ReflectionProperty $property) => array_key_exists($property->getName(), $settings->installable()) )
46+
->each(function (ReflectionProperty $property) use ($settings) {
47+
$description = $property->getAttributes(Description::class)[0]->getArguments()[0];
48+
$value = match($property->getType()?->getName()) {
49+
'bool' => confirm($description ?? $property->getName()),
50+
default => text($description ?? $property->getName(), default: $property->getDefaultValue() ?? '', required: true),
51+
};
52+
53+
$settings->{$property->getName()} = $value;
54+
})
55+
->pluck('name');
56+
57+
$settings->save();
58+
}
59+
}

src/Settings/AppSettings.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,54 @@
22

33
namespace Cachet\Settings;
44

5+
use Cachet\Settings\Attributes\Description;
6+
use Illuminate\Support\Arr;
57
use Spatie\LaravelSettings\Settings;
68

79
class AppSettings extends Settings
810
{
11+
#[Description('The unique install ID of the application for telemetry.')]
912
public string $install_id;
1013

14+
#[Description('What is the name of your application?')]
1115
public ?string $name = 'Cachet';
1216

17+
#[Description('What is your application about?')]
1318
public ?string $about;
1419

20+
#[Description('Do you want to show support for Cachet?')]
1521
public bool $show_support = true;
1622

23+
#[Description('What timezone is is the application located in?')]
1724
public string $timezone = 'UTC';
1825

26+
#[Description('Would you like to show your timezone on the status page?')]
1927
public bool $show_timezone = false;
2028

29+
#[Description('Would you like to only show the days with disruption?')]
2130
public bool $only_disrupted_days = false;
2231

32+
#[Description('How many incident days should be shown in the timeline?')]
2333
public int $incident_days = 7;
2434

35+
#[Description('After how many seconds should the status page automatically refresh?')]
2536
public ?int $refresh_rate;
2637

38+
#[Description('Should the dashboard login link be shown?')]
2739
public bool $dashboard_login_link = true;
2840

41+
#[Description('Major outage threshold %')]
2942
public int $major_outage_threshold = 25;
3043

3144
public static function group(): string
3245
{
3346
return 'app';
3447
}
48+
49+
public function installable(): array
50+
{
51+
return Arr::except(get_class_vars(__CLASS__), [
52+
'install_id',
53+
]);
54+
}
3555
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Cachet\Settings\Attributes;
4+
5+
use Attribute;
6+
7+
#[Attribute(Attribute::TARGET_PROPERTY)]
8+
final class Description
9+
{
10+
public function __construct(private string $description) {}
11+
}

testbench.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ workbench:
2424
- migrate:refresh:
2525
--seed: true
2626
--seeder: Cachet\Database\Seeders\DatabaseSeeder
27+
- cachet:install
2728
assets:
2829
- query-builder-config
2930
- cachet-assets
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
namespace Tests\Unit\Commands;
4+
5+
use Cachet\Settings\AppSettings;
6+
use Illuminate\Foundation\Testing\RefreshDatabase;
7+
8+
uses(RefreshDatabase::class);
9+
10+
it('runs install command successfully without configuration', function () {
11+
$this->artisan('cachet:install')
12+
->expectsOutputToContain('Welcome to the Cachet installer!')
13+
->expectsConfirmation('Do you want to configure Cachet before installing?', 'no')
14+
->expectsOutputToContain('Installing Cachet...')
15+
->expectsOutputToContain('Cachet has been installed successfully!')
16+
->assertSuccessful();
17+
});
18+
19+
it('updates app settings when configuration is passed', function () {
20+
$this->artisan('cachet:install')
21+
->expectsOutputToContain('Welcome to the Cachet installer!')
22+
->expectsConfirmation('Do you want to configure Cachet before installing?', 'yes')
23+
->expectsOutputToContain('Configuring Cachet...')
24+
->expectsQuestion('What is the name of your application?', 'Laravel Envoyer')
25+
->expectsQuestion('What is your application about?', 'Zero downtime deployment tool.')
26+
->expectsConfirmation('Do you want to show support for Cachet?', 'yes')
27+
->expectsQuestion('What timezone is is the application located in?', 'America/New_York')
28+
->expectsConfirmation('Would you like to show your timezone on the status page?', 'yes')
29+
->expectsConfirmation('Would you like to only show the days with disruption?', 'yes')
30+
->expectsQuestion('How many incident days should be shown in the timeline?', 14)
31+
->expectsQuestion('After how many seconds should the status page automatically refresh?', 10)
32+
->expectsConfirmation('Should the dashboard login link be shown?', 'no')
33+
->expectsQuestion('Major outage threshold %', 50)
34+
->expectsOutputToContain('Installing Cachet...')
35+
->expectsOutputToContain('Cachet has been installed successfully!')
36+
->assertSuccessful();
37+
38+
$settings = app(AppSettings::class);
39+
expect($settings->name)->toBe('Laravel Envoyer')
40+
->and($settings->about)->toBe('Zero downtime deployment tool.')
41+
->and($settings->show_support)->toBeTrue()
42+
->and($settings->timezone)->toBe('America/New_York')
43+
->and($settings->show_timezone)->toBeTrue()
44+
->and($settings->only_disrupted_days)->toBeTrue()
45+
->and($settings->incident_days)->toBe(14)
46+
->and($settings->refresh_rate)->toBe(10)
47+
->and($settings->dashboard_login_link)->toBeFalse()
48+
->and($settings->major_outage_threshold)->toBe(50);
49+
});

0 commit comments

Comments
 (0)