Skip to content

Commit

Permalink
[5.x] Add default config for select starter kit modules (#11045)
Browse files Browse the repository at this point in the history
  • Loading branch information
jesseleite authored Nov 26, 2024
1 parent ab028aa commit a29ea36
Show file tree
Hide file tree
Showing 2 changed files with 203 additions and 17 deletions.
26 changes: 18 additions & 8 deletions src/StarterKits/Installer.php
Original file line number Diff line number Diff line change
Expand Up @@ -324,9 +324,11 @@ protected function instantiateModule(array $config, string $key): InstallableMod

$name = str_replace('_', ' ', $key);

if ($shouldPrompt && $this->isInteractive && ! confirm(Arr::get($config, 'prompt', "Would you like to install the [{$name}] module?"), false)) {
$default = Arr::get($config, 'default', false);

if ($shouldPrompt && $this->isInteractive && ! confirm(Arr::get($config, 'prompt', "Would you like to install the [{$name}] module?"), $default)) {
return false;
} elseif ($shouldPrompt && ! $this->isInteractive) {
} elseif ($shouldPrompt && ! $this->isInteractive && ! $default) {
return false;
}

Expand All @@ -338,19 +340,27 @@ protected function instantiateModule(array $config, string $key): InstallableMod
*/
protected function instantiateSelectModule(array $config, string $key): InstallableModule|array|bool
{
$skipOptionLabel = Arr::get($config, 'skip_option', 'No');
$skipModuleValue = 'skip_module';

$options = collect($config['options'])
->map(fn ($option, $optionKey) => Arr::get($option, 'label', ucfirst($optionKey)))
->prepend(Arr::get($config, 'skip_option', 'No'), $skipModule = 'skip_module')
->when($skipOptionLabel !== false, fn ($c) => $c->prepend($skipOptionLabel, $skipModuleValue))
->all();

$name = str_replace('_', ' ', $key);

$choice = select(
label: Arr::get($config, 'prompt', "Would you like to install one of the following [{$name}] modules?"),
options: $options,
);
if ($this->isInteractive) {
$choice = select(
label: Arr::get($config, 'prompt', "Would you like to install one of the following [{$name}] modules?"),
options: $options,
default: Arr::get($config, 'default'),
);
} elseif (! $this->isInteractive && ! $choice = Arr::get($config, 'default')) {
return false;
}

if ($choice === $skipModule) {
if ($choice === $skipModuleValue) {
return false;
}

Expand Down
194 changes: 185 additions & 9 deletions tests/StarterKits/InstallTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -772,22 +772,28 @@ public function it_installs_no_modules_by_default_when_running_non_interactively
}

#[Test]
public function it_installs_modules_with_prompt_false_config_by_default_when_running_non_interactively()
public function it_can_still_install_modules_with_prompt_false_or_default_config()
{
$this->setConfig([
'export_paths' => [
'copied.md',
],
'modules' => [
'seo' => [
'prompt' => false, // Setting prompt to false skips confirmation, so this module should still get installed non-interactively
'prompt' => false, // Setting `prompt: false` normally skips confirmation and ensures it always gets installed
'export_paths' => [
'resources/css/seo.css',
],
'dependencies' => [
'statamic/seo-pro' => '^0.2.0',
],
],
'hockey' => [
'default' => true, // Setting `default: true` will still ask user for confirmation, but should still get installed non-interactively
'export_paths' => [
'resources/css/hockey.css',
],
],
'bobsled' => [
'export_paths' => [
'resources/css/bobsled.css',
Expand All @@ -797,29 +803,64 @@ public function it_installs_modules_with_prompt_false_config_by_default_when_run
],
],
'jamaica' => [
'prompt' => false, // Setting prompt to false skips confirmation, so this module should still get installed non-interactively
'prompt' => false, // Setting `prompt: false` normally skips confirmation and ensures it always gets installed
'export_as' => [
'resources/css/theme.css' => 'resources/css/jamaica.css',
],
],
'js' => [
'default' => 'vue', // Setting a `default` option will still ask user for confirmation, but should still get installed non-interactively
'options' => [
'react' => [
'label' => 'React JS',
'export_paths' => [
'resources/js/react.js',
],
],
'vue' => [
'label' => 'Vue JS',
'export_paths' => [
'resources/js/vue.js',
],
],
],
],
'js_invalid' => [
'prompt' => false, // Setting `prompt: false` doesn't do anything for select modules, should use `default` like above
'options' => [
'svelte' => [
'export_paths' => [
'resources/js/svelte.js',
],
],
],
],
],
]);

$this->assertFileDoesNotExist(base_path('copied.md'));
$this->assertFileDoesNotExist(base_path('resources/css/seo.css'));
$this->assertFileDoesNotExist(base_path('resources/css/hockey.css'));
$this->assertFileDoesNotExist(base_path('resources/css/bobsled.css'));
$this->assertFileDoesNotExist(base_path('resources/css/theme.css'));
$this->assertComposerJsonDoesntHave('statamic/seo-pro');
$this->assertComposerJsonDoesntHave('bobsled/speed-calculator');
$this->assertFileDoesNotExist(base_path('resources/js/react.js'));
$this->assertFileDoesNotExist(base_path('resources/js/vue.js'));
$this->assertFileDoesNotExist(base_path('resources/js/svelte.js'));

$this->installCoolRunnings();

$this->assertFileExists(base_path('copied.md'));
$this->assertFileExists(base_path('resources/css/seo.css'));
$this->assertFileExists(base_path('resources/css/hockey.css'));
$this->assertFileDoesNotExist(base_path('resources/css/bobsled.css'));
$this->assertFileExists(base_path('resources/css/theme.css'));
$this->assertComposerJsonHasPackageVersion('require', 'statamic/seo-pro', '^0.2.0');
$this->assertComposerJsonDoesntHave('bobsled/speed-calculator');
$this->assertFileDoesNotExist(base_path('resources/js/react.js'));
$this->assertFileExists(base_path('resources/js/vue.js'));
$this->assertFileDoesNotExist(base_path('resources/js/svelte.js'));
}

#[Test]
Expand Down Expand Up @@ -926,7 +967,120 @@ public function it_installs_only_the_modules_confirmed_interactively_via_prompt(
}

#[Test]
public function it_display_custom_module_prompts()
public function it_allows_user_to_skip_in_select_module_prompts()
{
$this->setConfig([
'modules' => [
'js' => [
'prompt' => 'Want one of these fancy JS options?',
'options' => [
'react' => [
'label' => 'React JS',
'export_paths' => [
'resources/js/react.js',
],
],
'vue' => [
'label' => 'Vue JS',
'export_paths' => [
'resources/js/vue.js',
],
],
'svelte' => [
'export_paths' => [
'resources/js/svelte.js',
],
],
],
],
],
]);

$this->assertFileDoesNotExist(base_path('resources/js/react.js'));
$this->assertFileDoesNotExist(base_path('resources/js/vue.js'));
$this->assertFileDoesNotExist(base_path('resources/js/svelte.js'));

$command = $this->installCoolRunningsModules();

// Some fixes to `expectsChoice()` were merged for us, but are not available on 11.20.0 and below
// See: https://github.com/laravel/framework/pull/52408
if (version_compare(app()->version(), '11.20.0', '>')) {
$command->expectsChoice('Want one of these fancy JS options?', 'skip_module', [
'skip_module' => 'No',
'react' => 'React JS',
'vue' => 'Vue JS',
'svelte' => 'Svelte',
]);
} else {
$command->expectsQuestion('Want one of these fancy JS options?', 'skip_module');
}

$command->run();

$this->assertFileDoesNotExist(base_path('resources/js/react.js'));
$this->assertFileDoesNotExist(base_path('resources/js/vue.js'));
$this->assertFileDoesNotExist(base_path('resources/js/svelte.js'));
}

#[Test]
public function it_can_disable_skip_option_in_select_module_prompts()
{
$this->setConfig([
'modules' => [
'js' => [
'prompt' => 'Want one of these fancy JS options?',
'skip_option' => false,
'options' => [
'react' => [
'label' => 'React JS',
'export_paths' => [
'resources/js/react.js',
],
],
'vue' => [
'label' => 'Vue JS',
'export_paths' => [
'resources/js/vue.js',
],
],
'svelte' => [
'export_paths' => [
'resources/js/svelte.js',
],
],
],
],
],
]);

$this->assertFileDoesNotExist(base_path('resources/js/react.js'));
$this->assertFileDoesNotExist(base_path('resources/js/vue.js'));
$this->assertFileDoesNotExist(base_path('resources/js/svelte.js'));

$command = $this->installCoolRunningsModules();

// Some fixes to `expectsChoice()` were merged for us, but are not available on 11.20.0 and below
// See: https://github.com/laravel/framework/pull/52408
if (version_compare(app()->version(), '11.20.0', '>')) {
$command->expectsChoice('Want one of these fancy JS options?', 'svelte', [
// 'skip_module' => 'No', // This should not be here anymore, because of `skip_option: false`
'react' => 'React JS',
'vue' => 'Vue JS',
'svelte' => 'Svelte',
]);
} else {
$command->expectsQuestion('Want one of these fancy JS options?', 'svelte');
}

$command->run();

$this->assertFileDoesNotExist(base_path('resources/js/react.js'));
$this->assertFileDoesNotExist(base_path('resources/js/vue.js'));
$this->assertFileExists(base_path('resources/js/svelte.js'));
}

#[Test]
public function it_display_custom_module_prompts_and_option_labels()
{
$this->setConfig([
'modules' => [
Expand All @@ -938,6 +1092,7 @@ public function it_display_custom_module_prompts()
],
'js' => [
'prompt' => 'Want one of these fancy JS options?',
'skip_option' => 'No, thank you!',
'options' => [
'react' => [
'label' => 'React JS',
Expand Down Expand Up @@ -974,7 +1129,7 @@ public function it_display_custom_module_prompts()
// See: https://github.com/laravel/framework/pull/52408
if (version_compare(app()->version(), '11.20.0', '>')) {
$command->expectsChoice('Want one of these fancy JS options?', 'svelte', [
'skip_module' => 'No',
'skip_module' => 'No, thank you!',
'react' => 'React JS',
'vue' => 'Vue JS',
'svelte' => 'Svelte',
Expand Down Expand Up @@ -1146,21 +1301,21 @@ public static function validModuleConfigs()
}

#[Test]
public function it_installs_nested_modules_with_prompt_false_config_by_default_when_running_non_interactively()
public function it_can_still_install_nested_modules_with_prompt_false_or_default_config()
{
$this->setConfig([
'export_paths' => [
'copied.md',
],
'modules' => [
'canada' => [
'prompt' => false, // Setting prompt to false skips confirmation, so this module should still get installed non-interactively
'prompt' => false, // Setting `prompt: false` skips confirmation, so this module should still get installed
'export_paths' => [
'resources/css/hockey.css',
],
'modules' => [
'hockey_players' => [
'prompt' => false, // Setting prompt to false skips confirmation, so this module should still get installed non-interactively
'prompt' => false, // Setting `prompt: false` skips confirmation, so this module should still get installed
'export_paths' => [
'resources/dictionaries/players.yaml',
],
Expand All @@ -1174,11 +1329,28 @@ public function it_installs_nested_modules_with_prompt_false_config_by_default_w
],
],
'hockey_night_in_canada' => [
'prompt' => false, // Setting prompt to false skips confirmation, so this module should still get installed non-interactively
'prompt' => false, // Setting `prompt: false` skips confirmation, so this module should still get installed
'export_paths' => [
'resources/dictionaries/canadian_players.yaml',
],
],
'js' => [
'default' => 'vue', // Setting a `default` option, so this module should still get installed
'options' => [
'react' => [
'label' => 'React JS',
'export_paths' => [
'resources/js/react.js',
],
],
'vue' => [
'label' => 'Vue JS',
'export_paths' => [
'resources/js/vue.js',
],
],
],
],
],
],
],
Expand All @@ -1192,6 +1364,8 @@ public function it_installs_nested_modules_with_prompt_false_config_by_default_w
$this->assertFileDoesNotExist(base_path('resources/dictionaries/players.yaml'));
$this->assertFileDoesNotExist(base_path('resources/dictionaries/american_players.yaml'));
$this->assertFileDoesNotExist(base_path('resources/dictionaries/canadian_players.yaml'));
$this->assertFileDoesNotExist(base_path('resources/js/react.js'));
$this->assertFileDoesNotExist(base_path('resources/js/vue.js'));

$this->installCoolRunnings();

Expand All @@ -1201,6 +1375,8 @@ public function it_installs_nested_modules_with_prompt_false_config_by_default_w
$this->assertFileExists(base_path('resources/dictionaries/players.yaml'));
$this->assertFileDoesNotExist(base_path('resources/dictionaries/american_players.yaml'));
$this->assertFileExists(base_path('resources/dictionaries/canadian_players.yaml'));
$this->assertFileDoesNotExist(base_path('resources/js/react.js'));
$this->assertFileExists(base_path('resources/js/vue.js'));
}

#[Test]
Expand Down

0 comments on commit a29ea36

Please sign in to comment.