diff --git a/composer.json b/composer.json
index 9bc42d31c3..ca6e324fb6 100644
--- a/composer.json
+++ b/composer.json
@@ -14,8 +14,9 @@
"composer/composer": "^2.2.22",
"guzzlehttp/guzzle": "^6.3 || ^7.0",
"james-heinrich/getid3": "^1.9.21",
- "laravel/framework": "^10.0 || ^11.0",
+ "laravel/framework": "^10.25.0 || ^11.0",
"laravel/helpers": "^1.1",
+ "laravel/prompts": "^0.1.16",
"league/commonmark": "^2.2",
"league/csv": "^9.0",
"league/glide": "^2.0",
diff --git a/src/Console/Commands/AddonsDiscover.php b/src/Console/Commands/AddonsDiscover.php
index 7741714cf8..27bed61166 100644
--- a/src/Console/Commands/AddonsDiscover.php
+++ b/src/Console/Commands/AddonsDiscover.php
@@ -31,12 +31,13 @@ class AddonsDiscover extends Command
*/
public function handle(Manifest $manifest)
{
+ $this->newLine();
$manifest->build();
foreach (array_keys($manifest->manifest) as $package) {
- $this->line("Discovered Addon: {$package}");
+ $this->components->task("Discovered Addon: {$package}");
}
- $this->info('Addon manifest generated successfully.');
+ $this->components->info('Addon manifest generated successfully.');
}
}
diff --git a/src/Console/Commands/AssetsGeneratePresets.php b/src/Console/Commands/AssetsGeneratePresets.php
index edbc112a0a..aba0a593f9 100644
--- a/src/Console/Commands/AssetsGeneratePresets.php
+++ b/src/Console/Commands/AssetsGeneratePresets.php
@@ -10,6 +10,11 @@
use Statamic\Jobs\GeneratePresetImageManipulation;
use Statamic\Support\Arr;
+use function Laravel\Prompts\error;
+use function Laravel\Prompts\info;
+use function Laravel\Prompts\note;
+use function Laravel\Prompts\progress;
+
class AssetsGeneratePresets extends Command
{
use RunsInPlease;
@@ -46,12 +51,12 @@ public function handle()
$this->shouldQueue = $this->option('queue');
if ($this->shouldQueue && config('queue.default') === 'sync') {
- $this->error('The queue connection is set to "sync". Queueing will be disabled.');
+ error('The queue connection is set to "sync". Queueing will be disabled.');
$this->shouldQueue = false;
}
AssetContainer::all()->sortBy('title')->each(function ($container) {
- $this->line('Generating presets for '.$container->title().'...');
+ note('Generating presets for '.$container->title().'...');
$this->generatePresets($container);
$this->newLine();
});
@@ -73,37 +78,40 @@ private function generatePresets($container)
$cpPresets = config('statamic.cp.enabled') ? 1 : 0;
$steps = (count($container->warmPresets()) + $cpPresets) * count($assets);
- $bar = $this->output->createProgressBar($steps);
-
- foreach ($assets as $asset) {
- $verb = $this->shouldQueue ? 'Queueing' : 'Generating';
- $bar->setFormat("[%current%/%max%] $verb %filename% %preset%... ");
-
- foreach ($asset->warmPresets() as $preset) {
- $counts[$preset] = ($counts[$preset] ?? 0) + 1;
- $bar->setMessage($preset, 'preset');
- $bar->setMessage($asset->basename(), 'filename');
- $bar->display();
-
- $dispatchMethod = $this->shouldQueue
- ? 'dispatch'
- : (method_exists(Dispatcher::class, 'dispatchSync') ? 'dispatchSync' : 'dispatchNow');
-
- try {
- GeneratePresetImageManipulation::$dispatchMethod($asset, $preset);
- } catch (\Exception $e) {
- Log::debug($e);
- $counts['errors'] = ($counts['errors'] ?? 0) + 1;
- }
- $bar->advance();
+ if ($steps > 0) {
+ $progress = progress(
+ label: $this->shouldQueue ? 'Queueing...' : 'Generating...',
+ steps: $steps
+ );
+
+ $progress->start();
+
+ foreach ($assets as $asset) {
+ foreach ($asset->warmPresets() as $preset) {
+ $counts[$preset] = ($counts[$preset] ?? 0) + 1;
+ $progress->label("Generating $preset for {$asset->basename()}...");
+
+ $dispatchMethod = $this->shouldQueue
+ ? 'dispatch'
+ : (method_exists(Dispatcher::class, 'dispatchSync') ? 'dispatchSync' : 'dispatchNow');
+
+ try {
+ GeneratePresetImageManipulation::$dispatchMethod($asset, $preset);
+ } catch (\Exception $e) {
+ Log::debug($e);
+ $counts['errors'] = ($counts['errors'] ?? 0) + 1;
+ }
+
+ $progress->advance();
+ }
}
+
+ $progress->finish();
}
$verb = $this->shouldQueue ? 'queued' : 'generated';
- $bar->setFormat(sprintf("[✔] %s images $verb for %s assets.", $steps, count($assets)));
- $bar->finish();
- $this->newLine(2);
+ info(sprintf("[✔] %s images $verb for %s assets.", $steps, count($assets)));
if (property_exists($this, 'components')) {
$errors = Arr::pull($counts, 'errors');
diff --git a/src/Console/Commands/AssetsMeta.php b/src/Console/Commands/AssetsMeta.php
index 69d6acbd16..8e990ed5c6 100644
--- a/src/Console/Commands/AssetsMeta.php
+++ b/src/Console/Commands/AssetsMeta.php
@@ -7,6 +7,8 @@
use Statamic\Facades\Asset;
use Statamic\Facades\AssetContainer;
+use function Laravel\Prompts\progress;
+
class AssetsMeta extends Command
{
use RunsInPlease;
@@ -19,18 +21,22 @@ public function handle()
{
$assets = $this->getAssets();
- $bar = $this->output->createProgressBar($assets->count());
-
- $assets->each(function ($asset) use ($bar) {
- $asset->hydrate();
- $asset->save();
- $bar->advance();
- });
-
- $bar->finish();
+ if ($assets->isEmpty()) {
+ return $this->components->warn("There's no metadata to generate. You don't have any assets.");
+ }
- $this->line('');
- $this->info('Asset metadata generated');
+ progress(
+ label: 'Generating asset metadata...',
+ steps: $assets,
+ callback: function ($asset, $progress) {
+ $asset->hydrate();
+ $asset->save();
+ $progress->advance();
+ },
+ hint: 'This may take a while if you have a lot of assets.'
+ );
+
+ $this->components->info("Generated metadata for {$assets->count()} ".str_plural('asset', $assets->count()).'.');
}
/**
diff --git a/src/Console/Commands/AuthMigration.php b/src/Console/Commands/AuthMigration.php
index 75981821ea..aaf148fd85 100644
--- a/src/Console/Commands/AuthMigration.php
+++ b/src/Console/Commands/AuthMigration.php
@@ -43,7 +43,7 @@ public function handle()
File::put($to, $contents);
- $this->line("Created Auth Migration: {$file}");
+ $this->components->info("Migration [$file] created successfully.");
$this->createGroupsTable();
$this->createRolesTable();
@@ -67,7 +67,7 @@ private function createGroupsTable()
File::put($to, $contents);
- $this->line("Created Groups Migration: {$file}");
+ $this->components->info("Migration [$file] created successfully.");
}
private function createRolesTable()
@@ -86,6 +86,6 @@ private function createRolesTable()
File::put($to, $contents);
- $this->line("Created Roles Migration: {$file}");
+ $this->components->info("Migration [$file] created successfully.");
}
}
diff --git a/src/Console/Commands/GeneratorCommand.php b/src/Console/Commands/GeneratorCommand.php
index 9de87901c9..c497d6ed8f 100644
--- a/src/Console/Commands/GeneratorCommand.php
+++ b/src/Console/Commands/GeneratorCommand.php
@@ -28,15 +28,7 @@ public function handle()
: $addon;
}
- if (parent::handle() === false) {
- return false;
- }
-
- $relativePath = $this->getRelativePath($this->getPath($this->qualifyClass($this->getNameInput())));
-
- if (! $addon) {
- $this->line("Your {$this->typeLower} class awaits: {$relativePath}");
- }
+ return parent::handle();
}
/**
diff --git a/src/Console/Commands/ImportGroups.php b/src/Console/Commands/ImportGroups.php
index 0d8a522f84..a03243a890 100644
--- a/src/Console/Commands/ImportGroups.php
+++ b/src/Console/Commands/ImportGroups.php
@@ -13,6 +13,9 @@
use Statamic\Contracts\Auth\UserGroupRepository as GroupRepositoryContract;
use Statamic\Facades\UserGroup;
+use function Laravel\Prompts\error;
+use function Laravel\Prompts\progress;
+
class ImportGroups extends Command
{
use RunsInPlease;
@@ -39,7 +42,7 @@ class ImportGroups extends Command
public function handle()
{
if (! config('statamic.users.tables.groups', false)) {
- $this->error('You do not have eloquent driven groups enabled');
+ error('You do not have eloquent driven groups enabled');
return;
}
@@ -65,17 +68,20 @@ private function importGroups()
Facade::clearResolvedInstance(GroupContract::class);
Facade::clearResolvedInstance(GroupRepositoryContract::class);
- $this->withProgressBar($groups, function ($group) {
- $eloquentGroup = UserGroup::make()
- ->handle($group->handle())
- ->title($group->title())
- ->roles($group->roles())
- ->data($group->data()->except(['title', 'roles']));
+ progress(
+ label: 'Importing groups...',
+ steps: $groups,
+ callback: function ($group, $progress) {
+ $eloquentGroup = UserGroup::make()
+ ->handle($group->handle())
+ ->title($group->title())
+ ->roles($group->roles())
+ ->data($group->data()->except(['title', 'roles']));
- $eloquentGroup->save();
- });
+ $eloquentGroup->save();
+ }
+ );
- $this->newLine();
$this->info('Groups imported');
}
}
diff --git a/src/Console/Commands/ImportRoles.php b/src/Console/Commands/ImportRoles.php
index 49abf026fc..5e726b98d6 100644
--- a/src/Console/Commands/ImportRoles.php
+++ b/src/Console/Commands/ImportRoles.php
@@ -13,6 +13,9 @@
use Statamic\Contracts\Auth\RoleRepository as RoleRepositoryContract;
use Statamic\Facades\Role;
+use function Laravel\Prompts\error;
+use function Laravel\Prompts\progress;
+
class ImportRoles extends Command
{
use RunsInPlease;
@@ -39,7 +42,7 @@ class ImportRoles extends Command
public function handle()
{
if (! config('statamic.users.tables.roles', false)) {
- $this->error('You do not have eloquent driven roles enabled');
+ error('You do not have eloquent driven roles enabled');
return;
}
@@ -65,16 +68,19 @@ private function importRoles()
Facade::clearResolvedInstance(RoleContract::class);
Facade::clearResolvedInstance(RoleRepositoryContract::class);
- $this->withProgressBar($roles, function ($role) {
- $eloquentRole = Role::make($role->handle())
- ->title($role->title())
- ->permissions($role->permissions())
- ->preferences($role->preferences());
+ progress(
+ label: 'Importing roles...',
+ steps: $roles,
+ callback: function ($role) {
+ $eloquentRole = Role::make($role->handle())
+ ->title($role->title())
+ ->permissions($role->permissions())
+ ->preferences($role->preferences());
- $eloquentRole->save();
- });
+ $eloquentRole->save();
+ }
+ );
- $this->newLine();
$this->info('Roles imported');
}
}
diff --git a/src/Console/Commands/ImportUsers.php b/src/Console/Commands/ImportUsers.php
index de0acacea7..854ab786f4 100644
--- a/src/Console/Commands/ImportUsers.php
+++ b/src/Console/Commands/ImportUsers.php
@@ -15,6 +15,10 @@
use Statamic\Stache\Repositories\UserRepository as FileRepository;
use Statamic\Stache\Stores\UsersStore;
+use function Laravel\Prompts\error;
+use function Laravel\Prompts\info;
+use function Laravel\Prompts\progress;
+
class ImportUsers extends Command
{
use RunsInPlease;
@@ -41,7 +45,7 @@ class ImportUsers extends Command
public function handle()
{
if (config('statamic.users.repository') !== 'eloquent') {
- $this->error('Your site is not using the eloquent user repository.');
+ error('Your site is not using the eloquent user repository.');
return 0;
}
@@ -58,7 +62,7 @@ private function importUsers()
$model = config("auth.providers.$provider.model");
if (! in_array(HasUuids::class, class_uses_recursive($model))) {
- $this->error('Your user model must use the HasUuids trait for this migration to run');
+ error('Please add the HasUuids trait to your '.$model.' model in order to run this importer.');
return;
}
@@ -75,34 +79,37 @@ private function importUsers()
$eloquentRepository = app(UserRepositoryManager::class)->createEloquentDriver([]);
- $this->withProgressBar($users, function ($user) use ($eloquentRepository) {
- $data = $user->data();
+ progress(
+ label: 'Importing users...',
+ steps: $users,
+ callback: function ($user, $progress) use ($eloquentRepository) {
+ $data = $user->data();
- $eloquentUser = $eloquentRepository->make()
- ->email($user->email())
- ->preferences($user->preferences())
- ->data($data->except(['groups', 'roles'])->merge(['name' => $user->name()]))
- ->id($user->id());
+ $eloquentUser = $eloquentRepository->make()
+ ->email($user->email())
+ ->preferences($user->preferences())
+ ->data($data->except(['groups', 'roles'])->merge(['name' => $user->name()]))
+ ->id($user->id());
- if ($user->isSuper()) {
- $eloquentUser->makeSuper();
- }
+ if ($user->isSuper()) {
+ $eloquentUser->makeSuper();
+ }
- if (count($data->get('groups', [])) > 0) {
- $eloquentUser->groups($data->get('groups'));
- }
+ if (count($data->get('groups', [])) > 0) {
+ $eloquentUser->groups($data->get('groups'));
+ }
- if (count($data->get('roles', [])) > 0) {
- $eloquentUser->roles($data->get('roles'));
- }
+ if (count($data->get('roles', [])) > 0) {
+ $eloquentUser->roles($data->get('roles'));
+ }
- $eloquentUser->saveToDatabase();
+ $eloquentUser->saveToDatabase();
- $eloquentUser->model()->forceFill(['password' => $user->password()]);
- $eloquentUser->model()->saveQuietly();
- });
+ $eloquentUser->model()->forceFill(['password' => $user->password()]);
+ $eloquentUser->model()->saveQuietly();
+ }
+ );
- $this->newLine();
- $this->info('Users imported');
+ info('Users imported');
}
}
diff --git a/src/Console/Commands/InstallSsg.php b/src/Console/Commands/InstallSsg.php
index 57478851f4..0f8455dafa 100644
--- a/src/Console/Commands/InstallSsg.php
+++ b/src/Console/Commands/InstallSsg.php
@@ -9,6 +9,10 @@
use Statamic\Console\RunsInPlease;
use Symfony\Component\Process\PhpExecutableFinder;
+use function Laravel\Prompts\confirm;
+use function Laravel\Prompts\error;
+use function Laravel\Prompts\spin;
+
class InstallSsg extends Command
{
use EnhancesCommands, RunsInPlease;
@@ -35,30 +39,42 @@ class InstallSsg extends Command
public function handle()
{
if (Composer::isInstalled('statamic/ssg')) {
- return $this->error('The Static Site Generator package is already installed.');
+ return error('The Static Site Generator package is already installed.');
}
- $this->info('Installing the statamic/ssg package...');
- Composer::withoutQueue()->throwOnFailure()->require('statamic/ssg');
+ spin(
+ fn () => Composer::withoutQueue()->throwOnFailure()->require('statamic/ssg'),
+ 'Installing the statamic/ssg package...'
+ );
+
$this->checkLine('Installed statamic/ssg package');
- if ($this->confirm('Would you like to publish the config file?')) {
- Process::run([
- (new PhpExecutableFinder())->find(false) ?: 'php',
- defined('ARTISAN_BINARY') ? ARTISAN_BINARY : 'artisan',
- 'vendor:publish',
- '--provider',
- 'Statamic\\StaticSite\\ServiceProvider',
- ]);
+ if (confirm('Would you like to publish the config file?')) {
+ spin(
+ function () {
+ Process::run([
+ (new PhpExecutableFinder())->find(false) ?: 'php',
+ defined('ARTISAN_BINARY') ? ARTISAN_BINARY : 'artisan',
+ 'vendor:publish',
+ '--provider',
+ 'Statamic\\StaticSite\\ServiceProvider',
+ ]);
+ },
+ message: 'Publishing the config file...'
+ );
$this->checkLine('Config file published. You can find it at config/statamic/ssg.php');
}
if (
! Composer::isInstalled('spatie/fork')
- && $this->confirm('Would you like to install spatie/fork? It allows for running multiple workers at once.')
+ && confirm('Would you like to install spatie/fork? It allows for running multiple workers at once.')
) {
- Composer::withoutQueue()->throwOnFailure()->require('spatie/fork');
+ spin(
+ fn () => Composer::withoutQueue()->throwOnFailure()->require('spatie/fork'),
+ 'Installing the spatie/fork package...'
+ );
+
$this->checkLine('Installed spatie/fork package');
}
}
diff --git a/src/Console/Commands/MakeAddon.php b/src/Console/Commands/MakeAddon.php
index bada10e715..71ca01628a 100644
--- a/src/Console/Commands/MakeAddon.php
+++ b/src/Console/Commands/MakeAddon.php
@@ -11,6 +11,8 @@
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
+use function Laravel\Prompts\spin;
+
class MakeAddon extends GeneratorCommand
{
use EnhancesCommands, RunsInPlease, ValidatesInput;
@@ -83,16 +85,22 @@ public function handle()
->generateOptional()
->installComposerDependencies();
} catch (\Exception $e) {
- $this->error($e->getMessage());
+ $this->components->error($e->getMessage());
return 1;
}
$relativePath = $this->getRelativePath($this->addonPath());
- $this->output->newLine();
- $this->info("🎉 Your addon package is ready: {$relativePath}");
- $this->line('Learn how to build addons in our docs: https://statamic.dev/extending/addons');
+ $this->components->info('Your addon is ready! 🎉');
+
+ $this->components->bulletList([
+ "You find your addon in {$relativePath}",
+ 'Learn how to build addons in our docs: https://statamic.dev/extending/addons',
+ "When you're ready, setup as a seller to publish your addon on the Marketplace: https://statamic.com/sell",
+ ]);
+
+ $this->newLine();
}
/**
@@ -132,30 +140,31 @@ protected function generateComposerJson()
*/
protected function generateAddonFiles()
{
- $this->line('Creating addon...');
-
- $this->generateComposerJson();
-
- $files = [
- 'addon/provider.php.stub' => 'src/ServiceProvider.php',
- 'addon/TestCase.php.stub' => 'tests/TestCase.php',
- 'addon/ExampleTest.php.stub' => 'tests/ExampleTest.php',
- 'addon/.gitignore.stub' => '.gitignore',
- 'addon/README.md.stub' => 'README.md',
- 'addon/phpunit.xml.stub' => 'phpunit.xml',
- ];
-
- $data = [
- 'name' => $this->addonTitle(),
- 'package' => $this->package,
- 'namespace' => $this->addonNamespace(),
- ];
-
- foreach ($files as $stub => $file) {
- $this->createFromStub($stub, $this->addonPath($file), $data);
- }
-
- $this->checkInfo('Addon boilerplate created successfully.');
+ spin(
+ function () {
+ $this->generateComposerJson();
+
+ $files = [
+ 'addon/provider.php.stub' => 'src/ServiceProvider.php',
+ 'addon/TestCase.php.stub' => 'tests/TestCase.php',
+ 'addon/ExampleTest.php.stub' => 'tests/ExampleTest.php',
+ 'addon/.gitignore.stub' => '.gitignore',
+ 'addon/README.md.stub' => 'README.md',
+ 'addon/phpunit.xml.stub' => 'phpunit.xml',
+ ];
+
+ $data = [
+ 'name' => $this->addonTitle(),
+ 'package' => $this->package,
+ 'namespace' => $this->addonNamespace(),
+ ];
+
+ foreach ($files as $stub => $file) {
+ $this->createFromStub($stub, $this->addonPath($file), $data);
+ }
+ },
+ 'Creating addon...'
+ );
return $this;
}
@@ -195,19 +204,17 @@ protected function generateOptional()
*/
protected function installComposerDependencies()
{
- $this->output->newLine();
-
- $this->line("Installing your addon's Composer dependencies. This may take a moment...");
-
- try {
- Composer::withoutQueue()->throwOnFailure()->install($this->addonPath());
- } catch (ProcessException $exception) {
- $this->line($exception->getMessage());
- $this->output->newLine();
- throw new \Exception("An error was encountered while installing your addon's Composer dependencies!");
- }
-
- $this->checkInfo('Composer dependencies installed successfully.');
+ spin(
+ function () {
+ try {
+ Composer::withoutQueue()->throwOnFailure()->install($this->addonPath());
+ } catch (ProcessException $exception) {
+ $this->line($exception->getMessage());
+ throw new \Exception("An error was encountered while installing your addon's Composer dependencies.");
+ }
+ },
+ "Installing your addon's Composer dependencies..."
+ );
return $this;
}
@@ -242,19 +249,20 @@ protected function addRepositoryPath()
*/
protected function installAddon()
{
- $this->output->newLine();
- $this->line('Installing your addon with Composer. This may take a moment...');
- $this->addRepositoryPath();
-
- try {
- Composer::withoutQueue()->throwOnFailure()->require($this->package);
- } catch (ProcessException $exception) {
- $this->line($exception->getMessage());
- $this->output->newLine();
- throw new \Exception('An error was encountered while installing your addon!');
- }
-
- $this->checkInfo('Addon installed successfully.');
+ spin(
+ function () {
+ $this->addRepositoryPath();
+
+ try {
+ Composer::withoutQueue()->throwOnFailure()->require($this->package);
+ } catch (ProcessException $exception) {
+ $this->newLine();
+ $this->line($exception->getMessage());
+ throw new \Exception('An error was encountered while installing your addon.');
+ }
+ },
+ 'Installing your addon with Composer...'
+ );
return $this;
}
diff --git a/src/Console/Commands/MakeFieldtype.php b/src/Console/Commands/MakeFieldtype.php
index 64dd08c02e..c3af3944cc 100644
--- a/src/Console/Commands/MakeFieldtype.php
+++ b/src/Console/Commands/MakeFieldtype.php
@@ -75,8 +75,14 @@ protected function generateVueComponent()
if ($addon = $this->argument('addon')) {
$this->wireUpAddonJs($addon);
} else {
- $this->line("Your {$this->typeLower} Vue component awaits: {$relativePath}");
- $this->comment("Don't forget to import and register your Fieldtype component in resources/js/addon.js");
+ $this->components->info("Fieldtype Vue component [{$relativePath}] created successfully.");
+
+ $this->components->bulletList([
+ "Don't forget to import and register your fieldtype's Vue component in resources/js/addon.js",
+ 'For more information, see the documentation: https://statamic.dev/fieldtypes#vue-components',
+ ]);
+
+ $this->newLine();
}
}
diff --git a/src/Console/Commands/MakeUser.php b/src/Console/Commands/MakeUser.php
index 59d84f20ac..87adde9466 100644
--- a/src/Console/Commands/MakeUser.php
+++ b/src/Console/Commands/MakeUser.php
@@ -12,6 +12,11 @@
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
+use function Laravel\Prompts\confirm;
+use function Laravel\Prompts\error;
+use function Laravel\Prompts\password;
+use function Laravel\Prompts\text;
+
class MakeUser extends Command
{
use RunsInPlease, ValidatesInput;
@@ -59,7 +64,7 @@ class MakeUser extends Command
public function handle()
{
if (! Statamic::pro() && User::query()->count() > 0) {
- return $this->error(__('Statamic Pro is required.'));
+ return error(__('Statamic Pro is required.'));
}
// If email argument exists, non-interactively create user.
@@ -83,7 +88,7 @@ public function handle()
*/
protected function promptEmail()
{
- $this->email = $this->ask('Email');
+ $this->email = text(label: 'Email', required: true);
if ($this->emailValidationFails()) {
return $this->promptEmail();
@@ -103,7 +108,7 @@ protected function promptName()
return $this->promptSeparateNameFields();
}
- $this->data['name'] = $this->ask('Name', false);
+ $this->data['name'] = text(label: 'Name');
return $this;
}
@@ -115,8 +120,8 @@ protected function promptName()
*/
protected function promptSeparateNameFields()
{
- $this->data['first_name'] = $this->ask('First Name', false);
- $this->data['last_name'] = $this->ask('Last Name', false);
+ $this->data['first_name'] = text(label: 'First Name');
+ $this->data['last_name'] = text(label: 'Last Name');
return $this;
}
@@ -128,7 +133,7 @@ protected function promptSeparateNameFields()
*/
protected function promptPassword()
{
- $this->data['password'] = $this->secret('Password (Your input will be hidden)');
+ $this->data['password'] = password(label: 'Password', required: true);
if ($this->passwordValidationFails()) {
return $this->promptPassword();
@@ -148,7 +153,7 @@ protected function promptSuper()
return $this;
}
- if ($this->confirm('Super user', false)) {
+ if (confirm('Super user?', false)) {
$this->super = true;
}
@@ -175,7 +180,7 @@ protected function createUser()
$user->save();
- $this->info('User created successfully.');
+ $this->components->info('User created successfully.');
}
/**
diff --git a/src/Console/Commands/Multisite.php b/src/Console/Commands/Multisite.php
index 69b1414c42..a54e351bec 100644
--- a/src/Console/Commands/Multisite.php
+++ b/src/Console/Commands/Multisite.php
@@ -17,6 +17,10 @@
use Statamic\Statamic;
use Symfony\Component\VarExporter\VarExporter;
+use function Laravel\Prompts\confirm;
+use function Laravel\Prompts\info;
+use function Laravel\Prompts\text;
+
class Multisite extends Command
{
use EnhancesCommands, RunsInPlease;
@@ -39,23 +43,24 @@ public function handle()
$this->validateRunningOfCommand();
- $confirmed = $this->confirm("The current site handle is [{$this->siteOne()}], content will be moved into folders with this name. Is this okay?");
+ $confirmed = confirm("The current site handle is [{$this->siteOne()}], content will be moved into folders with this name. Is this okay?");
if (! $confirmed) {
- $this->crossLine('Change the site handle in config/statamic/sites.php then try this command again.');
+ $this->components->error('Change the site handle in config/statamic/sites.php then try this command again.');
return;
}
- $this->info("Please enter the handles of the additional sites. Just press enter when you're done.");
+ info("Please enter the handles of the additional sites. Just press enter when you're done.");
+
do {
- if ($site = $this->ask('Handle of site #'.($this->sites->count() + 1))) {
+ if ($site = text('Handle of site #'.($this->sites->count() + 1))) {
$this->sites->add($site);
}
- } while ($site !== null);
+ } while ($site !== '');
if ($this->sites->count() < 2) {
- return $this->crossLine('Multisite has not been enabled.');
+ return $this->components->error('Multisite has not been enabled.');
}
$this->clearStache();
diff --git a/src/Console/Commands/SiteClear.php b/src/Console/Commands/SiteClear.php
index 6ef57827d4..a4156378f4 100644
--- a/src/Console/Commands/SiteClear.php
+++ b/src/Console/Commands/SiteClear.php
@@ -7,6 +7,8 @@
use Statamic\Console\RunsInPlease;
use Statamic\Facades\YAML;
+use function Laravel\Prompts\confirm;
+
class SiteClear extends Command
{
use RunsInPlease;
@@ -74,7 +76,7 @@ protected function shouldAbort()
return false;
}
- return ! $this->confirm('Are you sure you want to remove all the site content and resources?', false);
+ return ! confirm(label: 'Are you sure you want to remove all the site content and resources?', default: false);
}
/**
diff --git a/src/Console/Commands/StacheClear.php b/src/Console/Commands/StacheClear.php
index 25e7d4505e..038ba23bee 100644
--- a/src/Console/Commands/StacheClear.php
+++ b/src/Console/Commands/StacheClear.php
@@ -33,6 +33,6 @@ public function handle()
{
Stache::clear();
- $this->info('You have trimmed the Stache. It looks dashing.');
+ $this->components->info('You have trimmed the Stache. It looks dashing.');
}
}
diff --git a/src/Console/Commands/StacheRefresh.php b/src/Console/Commands/StacheRefresh.php
index e103b8c2e8..aaa98bebd7 100644
--- a/src/Console/Commands/StacheRefresh.php
+++ b/src/Console/Commands/StacheRefresh.php
@@ -5,7 +5,8 @@
use Illuminate\Console\Command;
use Statamic\Console\RunsInPlease;
use Statamic\Facades\Stache;
-use Wilderborn\Partyline\Facade as Partyline;
+
+use function Laravel\Prompts\spin;
class StacheRefresh extends Command
{
@@ -16,12 +17,9 @@ class StacheRefresh extends Command
public function handle()
{
- Partyline::bind($this);
-
- $this->line('Please wait. This may take a while if you have a lot of content.');
-
- Stache::refresh();
+ spin(callback: fn () => Stache::clear(), message: 'Clearing the Stache...');
+ spin(callback: fn () => Stache::warm(), message: 'Warming the Stache...');
- $this->info('You have trimmed and polished the Stache. It is handsome, warm, and ready.');
+ $this->components->info('You have trimmed and polished the Stache. It is handsome, warm, and ready.');
}
}
diff --git a/src/Console/Commands/StacheWarm.php b/src/Console/Commands/StacheWarm.php
index 7df4777b2d..0a6965c744 100644
--- a/src/Console/Commands/StacheWarm.php
+++ b/src/Console/Commands/StacheWarm.php
@@ -5,7 +5,8 @@
use Illuminate\Console\Command;
use Statamic\Console\RunsInPlease;
use Statamic\Facades\Stache;
-use Wilderborn\Partyline\Facade as Partyline;
+
+use function Laravel\Prompts\spin;
class StacheWarm extends Command
{
@@ -16,12 +17,8 @@ class StacheWarm extends Command
public function handle()
{
- Partyline::bind($this);
-
- $this->line('Please wait. This may take a while if you have a lot of content.');
-
- Stache::warm();
+ spin(callback: fn () => Stache::warm(), message: 'Warming the Stache...');
- $this->info('You have poured oil over the Stache and polished it until it shines. It is warm and ready');
+ $this->components->info('You have poured oil over the Stache and polished it until it shines. It is warm and ready');
}
}
diff --git a/src/Console/Commands/StarterKitExport.php b/src/Console/Commands/StarterKitExport.php
index a31321f93e..3760878701 100644
--- a/src/Console/Commands/StarterKitExport.php
+++ b/src/Console/Commands/StarterKitExport.php
@@ -9,6 +9,8 @@
use Statamic\Facades\Path;
use Statamic\StarterKits\Exceptions\StarterKitException;
+use function Laravel\Prompts\confirm;
+
class StarterKitExport extends Command
{
use RunsInPlease;
@@ -43,12 +45,12 @@ public function handle()
try {
StarterKitExporter::export($path);
} catch (StarterKitException $exception) {
- $this->error($exception->getMessage());
+ $this->components->error($exception->getMessage());
return 1;
}
- $this->info("Starter kit was successfully exported to [$path].");
+ $this->components->info("Starter kit was successfully exported to [$path].");
}
/**
@@ -60,7 +62,7 @@ protected function askToStubStarterKitConfig()
$newPath = base_path($config = 'starter-kit.yaml');
if ($this->input->isInteractive()) {
- if (! $this->confirm("Config [{$config}] does not exist. Would you like to create it now?", true)) {
+ if (! confirm("Config [{$config}] does not exist. Would you like to create it now?", true)) {
return;
}
}
@@ -93,13 +95,13 @@ protected function getAbsolutePath()
protected function askToCreateExportPath($path)
{
if ($this->input->isInteractive()) {
- if (! $this->confirm("Path [{$path}] does not exist. Would you like to create it now?", true)) {
+ if (! confirm("Path [{$path}] does not exist. Would you like to create it now?", true)) {
return;
}
}
File::makeDirectory($path, 0755, true);
- $this->comment("A new directory has been created at [{$path}].");
+ $this->components->info("A new directory has been created at [{$path}].");
}
}
diff --git a/src/Console/Commands/StarterKitInstall.php b/src/Console/Commands/StarterKitInstall.php
index 119235b852..75d492e6c0 100644
--- a/src/Console/Commands/StarterKitInstall.php
+++ b/src/Console/Commands/StarterKitInstall.php
@@ -10,6 +10,9 @@
use Statamic\StarterKits\Installer as StarterKitInstaller;
use Statamic\StarterKits\LicenseManager as StarterKitLicenseManager;
+use function Laravel\Prompts\confirm;
+use function Laravel\Prompts\text;
+
class StarterKitInstall extends Command
{
use RunsInPlease, ValidatesInput;
@@ -59,7 +62,8 @@ public function handle()
->fromLocalRepo($this->option('local'))
->withConfig($this->option('with-config'))
->withoutDependencies($this->option('without-dependencies'))
- ->withUser($cleared && $this->input->isInteractive() && ! $this->option('cli-install'))
+ ->isInteractive($isInteractive = $this->input->isInteractive())
+ ->withUser($cleared && $isInteractive && ! $this->option('cli-install'))
->usingSubProcess($this->option('cli-install'))
->force($this->option('force'));
@@ -81,7 +85,7 @@ public function handle()
$this->comment('composer global update statamic/cli'.PHP_EOL);
}
- $this->info("Starter kit [$package] was successfully installed.");
+ $this->components->info("Starter kit [$package] was successfully installed.");
}
/**
@@ -91,7 +95,7 @@ public function handle()
*/
protected function getPackage()
{
- return $this->argument('package') ?: $this->ask('Package');
+ return $this->argument('package') ?: text('Package');
}
/**
@@ -104,7 +108,7 @@ protected function shouldClear()
if ($this->option('clear-site')) {
return true;
} elseif ($this->input->isInteractive()) {
- return $this->confirm('Clear site first?', false);
+ return confirm('Clear site first?', false);
}
return false;
diff --git a/src/Console/Commands/StarterKitRunPostInstall.php b/src/Console/Commands/StarterKitRunPostInstall.php
index 3eee3dea8d..0db823cb58 100644
--- a/src/Console/Commands/StarterKitRunPostInstall.php
+++ b/src/Console/Commands/StarterKitRunPostInstall.php
@@ -37,7 +37,7 @@ public function handle()
}
if (! app('files')->exists(base_path("vendor/{$package}"))) {
- $this->error("Cannot find starter kit [{$package}] in vendor.");
+ $this->components->error("Cannot find starter kit [{$package}] in vendor.");
return 1;
}
@@ -47,11 +47,11 @@ public function handle()
try {
$installer->runPostInstallHook(true)->removeStarterKit();
} catch (StarterKitException $exception) {
- $this->error($exception->getMessage());
+ $this->components->error($exception->getMessage());
return 1;
}
- $this->info("Starter kit [$package] was successfully installed.");
+ $this->components->info("Starter kit [$package] was successfully installed.");
}
}
diff --git a/src/Console/Commands/StaticClear.php b/src/Console/Commands/StaticClear.php
index a6bc6bf7fb..98732f7812 100644
--- a/src/Console/Commands/StaticClear.php
+++ b/src/Console/Commands/StaticClear.php
@@ -6,6 +6,8 @@
use Statamic\Console\RunsInPlease;
use Statamic\Facades\StaticCache;
+use function Laravel\Prompts\spin;
+
class StaticClear extends Command
{
use RunsInPlease;
@@ -31,8 +33,8 @@ class StaticClear extends Command
*/
public function handle()
{
- StaticCache::flush();
+ spin(callback: fn () => StaticCache::flush(), message: 'Clearing the static page cache...');
- $this->info('Your static page cache is now so very, very empty.');
+ $this->components->info('Your static page cache is now so very, very empty.');
}
}
diff --git a/src/Console/Commands/StaticWarm.php b/src/Console/Commands/StaticWarm.php
index ad9a8b1975..c1010af209 100644
--- a/src/Console/Commands/StaticWarm.php
+++ b/src/Console/Commands/StaticWarm.php
@@ -44,7 +44,7 @@ class StaticWarm extends Command
public function handle()
{
if (! config('statamic.static_caching.strategy')) {
- $this->error('Static caching is not enabled.');
+ $this->components->error('Static caching is not enabled.');
return 1;
}
@@ -52,7 +52,7 @@ public function handle()
$this->shouldQueue = $this->option('queue');
if ($this->shouldQueue && config('queue.default') === 'sync') {
- $this->error('The queue connection is set to "sync". Queueing will be disabled.');
+ $this->components->error('The queue connection is set to "sync". Queueing will be disabled.');
$this->shouldQueue = false;
}
@@ -60,10 +60,10 @@ public function handle()
$this->warm();
- $this->output->newLine();
- $this->info($this->shouldQueue
- ? 'All requests to warm the static cache have been added to the queue.'
- : 'The static cache has been warmed.'
+ $this->components->info(
+ $this->shouldQueue
+ ? 'All requests to warm the static cache have been added to the queue.'
+ : 'The static cache has been warmed.'
);
return 0;
@@ -116,7 +116,7 @@ private function concurrency(): int
public function outputSuccessLine(Response $response, $index): void
{
- $this->checkLine($this->getRelativeUri($index));
+ $this->components->twoColumnDetail($this->getRelativeUri($index), '✓ Cached');
}
public function outputFailureLine($exception, $index): void
@@ -135,7 +135,7 @@ public function outputFailureLine($exception, $index): void
$message = $exception->getMessage();
}
- $this->crossLine("$uri → $message");
+ $this->components->twoColumnDetail($uri, "$message");
}
private function getRelativeUri(int $index): string
diff --git a/src/Console/Commands/SupportZipBlueprint.php b/src/Console/Commands/SupportZipBlueprint.php
index bf402ae381..9d0608a74c 100644
--- a/src/Console/Commands/SupportZipBlueprint.php
+++ b/src/Console/Commands/SupportZipBlueprint.php
@@ -26,8 +26,7 @@ public function handle()
return 1;
}
- $this->info('Zip created successfully.');
- $this->comment("Your zip file awaits: {$filename}");
+ $this->components->info("Zip [{$filename}] created successfully.");
}
protected function createZip($blueprint)
@@ -37,7 +36,7 @@ protected function createZip($blueprint)
$zip = new ZipArchive();
if ($zip->open($filename, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
- $this->error("Unable to create zip file \"$filename\"");
+ $this->components->error("Unable to create zip file: [$filename]");
return false;
}
@@ -58,7 +57,7 @@ protected function getBlueprint()
$handle = $this->argument('blueprint');
if (! $blueprint = Blueprint::find($handle)) {
- $this->error("Blueprint \"$handle\" not found");
+ $this->components->error("Blueprint [$handle] not found.");
return null;
}
diff --git a/src/Console/Commands/UpdatesRun.php b/src/Console/Commands/UpdatesRun.php
index ba29f611ea..20d39742f5 100644
--- a/src/Console/Commands/UpdatesRun.php
+++ b/src/Console/Commands/UpdatesRun.php
@@ -39,7 +39,7 @@ public function handle()
$success = UpdateScriptManager::runUpdatesForSpecificPackageVersion($package, $this->argument('version'), $this);
$success
- ? $this->info('Update scripts were run successfully!')
- : $this->comment('There were no update scripts for this version.');
+ ? $this->components->info('Update scripts were run successfully!')
+ : $this->components->warn('There were no update scripts for this version.');
}
}
diff --git a/src/Console/ValidatesInput.php b/src/Console/ValidatesInput.php
index f219643f4a..92b250f285 100644
--- a/src/Console/ValidatesInput.php
+++ b/src/Console/ValidatesInput.php
@@ -21,7 +21,7 @@ private function validationFails($input, $rules)
return false;
}
- $this->error($validator->errors()->first());
+ $this->components->error($validator->errors()->first());
return true;
}
diff --git a/src/Stache/Stache.php b/src/Stache/Stache.php
index 1bfab301e9..29e164c817 100644
--- a/src/Stache/Stache.php
+++ b/src/Stache/Stache.php
@@ -10,7 +10,6 @@
use Statamic\Support\Str;
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Lock\LockInterface;
-use Wilderborn\Partyline\Facade as Partyline;
class Stache
{
@@ -82,8 +81,6 @@ public function generateId()
public function clear()
{
- Partyline::comment('Clearing Stache...');
-
$this->stores()->reverse()->each->clear();
$this->duplicates()->clear();
@@ -100,8 +97,6 @@ public function refresh()
public function warm()
{
- Partyline::comment('Warming Stache...');
-
$lock = tap($this->lock('stache-warming'))->acquire(true);
$this->startTimer();
diff --git a/src/StarterKits/Installer.php b/src/StarterKits/Installer.php
index eaa856f7b0..17996a83e5 100644
--- a/src/StarterKits/Installer.php
+++ b/src/StarterKits/Installer.php
@@ -5,8 +5,11 @@
use Facades\Statamic\Console\Processes\Composer;
use Facades\Statamic\Console\Processes\TtyDetector;
use Facades\Statamic\StarterKits\Hook;
+use Illuminate\Console\Command;
+use Illuminate\Console\View\Components\Line;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Facades\Http;
+use Laravel\Prompts\Prompt;
use Statamic\Console\NullConsole;
use Statamic\Console\Please\Application as PleaseApplication;
use Statamic\Console\Processes\Exceptions\ProcessException;
@@ -16,6 +19,9 @@
use Statamic\StarterKits\Exceptions\StarterKitException;
use Statamic\Support\Str;
+use function Laravel\Prompts\confirm;
+use function Laravel\Prompts\spin;
+
final class Installer
{
protected $package;
@@ -51,7 +57,7 @@ public function __construct(string $package, $console = null, ?LicenseManager $l
* @param mixed $console
* @return static
*/
- public static function package(string $package, $console = null, ?LicenseManager $licenseManager = null)
+ public static function package(string $package, ?Command $console = null, ?LicenseManager $licenseManager = null)
{
return new self($package, $console, $licenseManager);
}
@@ -95,6 +101,13 @@ public function withoutDependencies($withoutDependencies = false)
return $this;
}
+ public function isInteractive($isInteractive = false)
+ {
+ Prompt::interactive($isInteractive);
+
+ return $this;
+ }
+
/**
* Install with super user.
*
@@ -248,13 +261,16 @@ protected function prepareRepository()
*/
protected function requireStarterKit()
{
- $this->console->info("Preparing starter kit [{$this->package}]...");
-
- try {
- Composer::withoutQueue()->throwOnFailure()->requireDev($this->package);
- } catch (ProcessException $exception) {
- $this->rollbackWithError("Error installing starter kit [{$this->package}].", $exception->getMessage());
- }
+ spin(
+ function () {
+ try {
+ Composer::withoutQueue()->throwOnFailure()->requireDev($this->package);
+ } catch (ProcessException $exception) {
+ $this->rollbackWithError("Error installing starter kit [{$this->package}].", $exception->getMessage());
+ }
+ },
+ "Preparing starter kit [{$this->package}]..."
+ );
return $this;
}
@@ -481,7 +497,7 @@ public function makeSuperUser()
return $this;
}
- if ($this->console->confirm('Create a super user?', false)) {
+ if (confirm('Create a super user?', false)) {
$this->console->call('make:user', ['--super' => true]);
}
@@ -569,11 +585,14 @@ protected function registerInstalledCommand($commandClass)
*/
protected function reticulateSplines()
{
- $this->console->info('Reticulating splines...');
-
- if (config('app.env') !== 'testing') {
- usleep(500000);
- }
+ spin(
+ function () {
+ if (config('app.env') !== 'testing') {
+ usleep(500000);
+ }
+ },
+ 'Reticulating splines...'
+ );
return $this;
}
@@ -589,11 +608,14 @@ public function removeStarterKit()
return $this;
}
- $this->console->info('Cleaning up temporary files...');
-
- if (Composer::isInstalled($this->package)) {
- Composer::withoutQueue()->throwOnFailure(false)->removeDev($this->package);
- }
+ spin(
+ function () {
+ if (Composer::isInstalled($this->package)) {
+ Composer::withoutQueue()->throwOnFailure(false)->removeDev($this->package);
+ }
+ },
+ 'Cleaning up temporary files...'
+ );
return $this;
}
diff --git a/tests/Console/Commands/AssetsMetaTest.php b/tests/Console/Commands/AssetsMetaTest.php
index da5b693000..0e894104e1 100644
--- a/tests/Console/Commands/AssetsMetaTest.php
+++ b/tests/Console/Commands/AssetsMetaTest.php
@@ -72,7 +72,7 @@ public function it_generates_one_asset_meta_file_for_asset_with_no_meta_file()
Storage::disk('test')->assertMissing('foo/.meta/bar.txt.yaml');
$this->artisan('statamic:assets:meta test_container')
- ->expectsOutput('Asset metadata generated');
+ ->expectsOutputToContain('Generated metadata for 1 asset.');
Storage::disk('test')->assertExists('foo/bar.txt');
Storage::disk('test')->assertExists('foo/.meta/bar.txt.yaml');
@@ -90,7 +90,7 @@ public function it_preserves_data_property_in_meta_data_file()
);
$this->artisan('statamic:assets:meta test_container')
- ->expectsOutput('Asset metadata generated');
+ ->expectsOutputToContain('Generated metadata for 1 asset.');
$this->assertEquals(
Arr::get(YAML::parse(Storage::disk('test')->get('foo/.meta/bar.txt.yaml')), 'data.foo'),
diff --git a/tests/Console/Commands/MakeAddonTest.php b/tests/Console/Commands/MakeAddonTest.php
index 6b02194c9f..0e89bfc64b 100644
--- a/tests/Console/Commands/MakeAddonTest.php
+++ b/tests/Console/Commands/MakeAddonTest.php
@@ -56,10 +56,10 @@ public function it_can_generate_an_addon()
public function it_cannot_make_addon_with_invalid_composer_package_name()
{
$this->artisan('statamic:make:addon', ['addon' => 'deaths-tar-vulnerability'])
- ->expectsOutput('Please enter a valid composer package name (eg. hasselhoff/kung-fury).');
+ ->expectsOutputToContain('Please enter a valid composer package name (eg. hasselhoff/kung-fury).');
$this->artisan('statamic:make:addon', ['addon' => 'some/path/deaths-tar-vulnerability'])
- ->expectsOutput('Please enter a valid composer package name (eg. hasselhoff/kung-fury).');
+ ->expectsOutputToContain('Please enter a valid composer package name (eg. hasselhoff/kung-fury).');
$this->assertFileDoesNotExist(base_path('addons/erso/deaths-tar-vulnerability'));
}
diff --git a/tests/Console/Commands/MakeUserTest.php b/tests/Console/Commands/MakeUserTest.php
index 29c1c59303..3c01dfa0dc 100644
--- a/tests/Console/Commands/MakeUserTest.php
+++ b/tests/Console/Commands/MakeUserTest.php
@@ -44,8 +44,8 @@ public function it_can_make_a_super_user_interactively()
$this->artisan('statamic:make:user')
->expectsQuestion('Email', 'jason@ifyoucantescapeit.org')
->expectsQuestion('Name', 'Jason')
- ->expectsQuestion('Password (Your input will be hidden)', 'midnight')
- ->expectsQuestion('Super user', true)
+ ->expectsQuestion('Password', 'midnight')
+ ->expectsQuestion('Super user?', true)
->assertExitCode(0);
$user = User::all()->first();
@@ -65,8 +65,8 @@ public function it_can_make_a_non_super_user_interactively()
$this->artisan('statamic:make:user')
->expectsQuestion('Email', 'jesses.girl@springfield.com')
->expectsQuestion('Name', 'Gertrude')
- ->expectsQuestion('Password (Your input will be hidden)', 'iloverickie')
- ->expectsQuestion('Super user', false)
+ ->expectsQuestion('Password', 'iloverickie')
+ ->expectsQuestion('Super user?', false)
->assertExitCode(0);
$user = User::all()->first();
@@ -82,13 +82,13 @@ public function it_validates_email()
$this->assertEmpty(User::all());
$this->artisan('statamic:make:user', ['email' => 'jason'])
- ->expectsOutput(trans('validation.email', ['attribute' => 'input']));
+ ->expectsOutputToContain(trans('validation.email', ['attribute' => 'input']));
$this->artisan('statamic:make:user', ['email' => 'jason@keeponrunnin.com'])
- ->expectsOutput('User created successfully.');
+ ->expectsOutputToContain('User created successfully.');
$this->artisan('statamic:make:user', ['email' => 'jason@keeponrunnin.com'])
- ->expectsOutput('A user with this email already exists.');
+ ->expectsOutputToContain('A user with this email already exists.');
}
/** @test */
diff --git a/tests/StarterKits/RunPostInstallTest.php b/tests/StarterKits/RunPostInstallTest.php
index 3efcff0dae..83efc82b3b 100644
--- a/tests/StarterKits/RunPostInstallTest.php
+++ b/tests/StarterKits/RunPostInstallTest.php
@@ -79,7 +79,7 @@ public function it_errors_gracefully_if_post_install_hook_cannot_be_found()
->artisan('statamic:starter-kit:run-post-install', [
'package' => 'statamic/cool-runnings',
])
- ->expectsOutput('Cannot find post-install hook for [statamic/cool-runnings].')
+ ->expectsOutputToContain('Cannot find post-install hook for [statamic/cool-runnings].')
->assertExitCode(1);
$this->assertFalse(Blink::has('post-install-hook-run'));
@@ -97,7 +97,7 @@ public function it_errors_gracefully_if_starter_kit_package_doesnt_exist_in_vend
->artisan('statamic:starter-kit:run-post-install', [
'package' => 'statamic/non-existent',
])
- ->expectsOutput('Cannot find starter kit [statamic/non-existent] in vendor.')
+ ->expectsOutputToContain('Cannot find starter kit [statamic/non-existent] in vendor.')
->assertExitCode(1);
$this->assertFalse(Blink::has('post-install-hook-run'));