• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

orchestral / workbench / 12509286075

26 Dec 2024 11:04PM UTC coverage: 92.868% (-1.0%) from 93.842%
12509286075

push

github

crynobone
fixes tests

Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com>

11 of 12 new or added lines in 2 files covered. (91.67%)

24 existing lines in 3 files now uncovered.

586 of 631 relevant lines covered (92.87%)

17.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.33
/src/Console/DevToolCommand.php
1
<?php
2

3
namespace Orchestra\Workbench\Console;
4

5
use Composer\InstalledVersions;
6
use Illuminate\Console\Command;
7
use Illuminate\Contracts\Console\PromptsForMissingInput;
8
use Illuminate\Filesystem\Filesystem;
9
use Illuminate\Support\Arr;
10
use Illuminate\Support\Collection;
11
use Orchestra\Testbench\Foundation\Console\Actions\EnsureDirectoryExists;
12
use Orchestra\Testbench\Foundation\Console\Actions\GeneratesFile;
13
use Orchestra\Workbench\Actions\DumpComposerAutoloads;
14
use Orchestra\Workbench\Actions\ModifyComposer;
15
use Orchestra\Workbench\Events\InstallEnded;
16
use Orchestra\Workbench\Events\InstallStarted;
17
use Orchestra\Workbench\StubRegistrar;
18
use Orchestra\Workbench\Workbench;
19
use Symfony\Component\Console\Attribute\AsCommand;
20
use Symfony\Component\Console\Input\InputInterface;
21
use Symfony\Component\Console\Input\InputOption;
22
use Symfony\Component\Console\Output\OutputInterface;
23

24
use function Laravel\Prompts\confirm;
25
use function Orchestra\Testbench\join_paths;
26
use function Orchestra\Testbench\package_path;
27

28
#[AsCommand(name: 'workbench:devtool', description: 'Configure Workbench for package development')]
29
class DevToolCommand extends Command implements PromptsForMissingInput
30
{
31
    /**
32
     * Namespace prefix for Workbench environment.
33
     */
34
    protected string $workbenchNamespacePrefix = 'Workbench\\';
35

36
    /**
37
     * Execute the console command.
38
     *
39
     * @return int
40
     */
41
    public function handle(Filesystem $filesystem)
42
    {
43
        $workingPath = package_path();
19✔
44

45
        event(new InstallStarted($this->input, $this->output, $this->components));
19✔
46

47
        $this->prepareWorkbenchNamespaces($filesystem, $workingPath);
19✔
48
        $this->prepareWorkbenchDirectories($filesystem, $workingPath);
19✔
49

50
        if ($this->option('install') === true) {
19✔
51
            $this->call('workbench:install', [
8✔
52
                '--force' => $this->option('force'),
8✔
53
                '--no-devtool' => true,
8✔
54
                '--basic' => $this->option('basic'),
8✔
55
            ]);
8✔
56
        }
57

58
        return tap(Command::SUCCESS, function ($exitCode) use ($workingPath) {
19✔
59
            event(new InstallEnded($this->input, $this->output, $this->components, $exitCode));
19✔
60

61
            (new DumpComposerAutoloads($workingPath))->handle();
19✔
62
        });
19✔
63
    }
64

65
    /**
66
     * Prepare workbench directories.
67
     */
68
    protected function prepareWorkbenchDirectories(Filesystem $filesystem, string $workingPath): void
69
    {
70
        $workbenchWorkingPath = join_paths($workingPath, 'workbench');
19✔
71

72
        (new EnsureDirectoryExists(
19✔
73
            filesystem: $filesystem,
19✔
74
            components: $this->components,
19✔
75
        ))->handle(
19✔
76
            Collection::make([
19✔
77
                join_paths('app', 'Models'),
19✔
78

79
                join_paths('database', 'factories'),
19✔
80
                join_paths('database', 'migrations'),
19✔
81
                join_paths('database', 'seeders'),
19✔
82
            ])->when(
19✔
83
                $this->option('basic') === false,
19✔
84
                fn ($directories) => $directories->push(...['bootstrap', 'routes', join_paths('resources', 'views')])
19✔
85
            )->map(static fn ($directory) => join_paths($workbenchWorkingPath, $directory))
19✔
86
        );
19✔
87

88
        $this->callSilently('make:provider', [
19✔
89
            'name' => 'WorkbenchServiceProvider',
19✔
90
            '--preset' => 'workbench',
19✔
91
            '--force' => (bool) $this->option('force'),
19✔
92
        ]);
19✔
93

94
        StubRegistrar::replaceInFile($filesystem, join_paths($workbenchWorkingPath, 'Providers', 'WorkbenchServiceProvider.php'));
19✔
95

96
        $this->prepareWorkbenchDatabaseSchema($filesystem, $workbenchWorkingPath);
19✔
97

98
        if ($this->option('basic') === false) {
19✔
99
            foreach (['console', 'web'] as $route) {
15✔
100
                (new GeneratesFile(
15✔
101
                    filesystem: $filesystem,
15✔
102
                    components: $this->components,
15✔
103
                    force: (bool) $this->option('force'),
15✔
104
                ))->handle(
15✔
105
                    (string) Workbench::stubFile("routes.{$route}"),
15✔
106
                    join_paths($workbenchWorkingPath, 'routes', "{$route}.php")
15✔
107
                );
15✔
108
            }
109
        }
110
    }
111

112
    /**
113
     * Prepare workbench namespace to `composer.json`.
114
     */
115
    protected function prepareWorkbenchNamespaces(Filesystem $filesystem, string $workingPath): void
116
    {
117
        (new ModifyComposer($workingPath))
19✔
118
            ->handle(fn (array $content) => $this->appendScriptsToComposer(
19✔
119
                $this->appendAutoloadDevToComposer($content, $filesystem), $filesystem
19✔
120
            ));
19✔
121

122
        Workbench::flushCachedClassAndNamespaces();
19✔
123
    }
124

125
    /**
126
     * Prepare workbench database schema including user model, factory and seeder.
127
     */
128
    protected function prepareWorkbenchDatabaseSchema(Filesystem $filesystem, string $workingPath): void
129
    {
130
        $this->callSilently('make:user-model', [
19✔
131
            '--preset' => 'workbench',
19✔
132
            '--force' => (bool) $this->option('force'),
19✔
133
        ]);
19✔
134

135
        StubRegistrar::replaceInFile($filesystem, join_paths($workingPath, 'app', 'Models', 'User.php'));
19✔
136

137
        $this->callSilently('make:user-factory', [
19✔
138
            '--preset' => 'workbench',
19✔
139
            '--force' => (bool) $this->option('force'),
19✔
140
        ]);
19✔
141

142
        StubRegistrar::replaceInFile($filesystem, join_paths($workingPath, 'database', 'factories', 'UserFactory.php'));
19✔
143

144
        (new GeneratesFile(
19✔
145
            filesystem: $filesystem,
19✔
146
            components: $this->components,
19✔
147
            force: (bool) $this->option('force'),
19✔
148
        ))->handle(
19✔
149
            (string) Workbench::stubFile('seeders.database'),
19✔
150
            join_paths($workingPath, 'database', 'seeders', 'DatabaseSeeder.php')
19✔
151
        );
19✔
152

153
        StubRegistrar::replaceInFile($filesystem, join_paths($workingPath, 'database', 'seeders', 'DatabaseSeeder.php'));
19✔
154
    }
155

156
    /**
157
     * Append `scripts` to `composer.json`.
158
     */
159
    protected function appendScriptsToComposer(array $content, Filesystem $filesystem): array
160
    {
161
        $hasScriptsSection = \array_key_exists('scripts', $content);
19✔
162
        $hasTestbenchDusk = InstalledVersions::isInstalled('orchestra/testbench-dusk');
19✔
163

164
        if (! $hasScriptsSection) {
19✔
165
            $content['scripts'] = [];
19✔
166
        }
167

168
        $postAutoloadDumpScripts = array_filter([
19✔
169
            '@clear',
19✔
170
            '@prepare',
19✔
171
            $hasTestbenchDusk ? '@dusk:install-chromedriver' : null,
19✔
172
        ]);
19✔
173

174
        if (! \array_key_exists('post-autoload-dump', $content['scripts'])) {
19✔
175
            $content['scripts']['post-autoload-dump'] = $postAutoloadDumpScripts;
19✔
176
        } else {
UNCOV
177
            $content['scripts']['post-autoload-dump'] = array_values(array_unique([
×
UNCOV
178
                ...$postAutoloadDumpScripts,
×
UNCOV
179
                ...Arr::wrap($content['scripts']['post-autoload-dump']),
×
UNCOV
180
            ]));
×
181
        }
182

183
        $content['scripts']['clear'] = '@php vendor/bin/testbench package:purge-skeleton --ansi';
19✔
184
        $content['scripts']['prepare'] = '@php vendor/bin/testbench package:discover --ansi';
19✔
185

186
        if ($hasTestbenchDusk) {
19✔
UNCOV
187
            $content['scripts']['dusk:install-chromedriver'] = '@php vendor/bin/dusk-updater detect --auto-update --ansi';
×
188
        }
189

190
        $content['scripts']['build'] = '@php vendor/bin/testbench workbench:build --ansi';
19✔
191
        $content['scripts']['serve'] = [
19✔
192
            'Composer\\Config::disableProcessTimeout',
19✔
193
            '@build',
19✔
194
            $hasTestbenchDusk && \defined('TESTBENCH_DUSK')
19✔
UNCOV
195
                ? '@php vendor/bin/testbench-dusk serve --ansi'
×
196
                : '@php vendor/bin/testbench serve --ansi',
19✔
197
        ];
19✔
198

199
        if (! \array_key_exists('lint', $content['scripts'])) {
19✔
200
            $lintScripts = [];
19✔
201

202
            if (InstalledVersions::isInstalled('laravel/pint')) {
19✔
203
                $lintScripts[] = '@php vendor/bin/pint --ansi';
19✔
UNCOV
204
            } elseif ($filesystem->isFile(Workbench::packagePath('pint.json'))) {
×
UNCOV
205
                $lintScripts[] = 'pint';
×
206
            }
207

208
            if (InstalledVersions::isInstalled('phpstan/phpstan')) {
19✔
209
                $lintScripts[] = '@php vendor/bin/phpstan analyse --verbose --ansi';
19✔
210
            }
211

212
            if (\count($lintScripts) > 0) {
19✔
213
                $content['scripts']['lint'] = $lintScripts;
19✔
214
            }
215
        }
216

217
        if (
218
            $filesystem->isFile(Workbench::packagePath('phpunit.xml'))
19✔
219
            || $filesystem->isFile(Workbench::packagePath('phpunit.xml.dist'))
19✔
220
        ) {
221
            if (! \array_key_exists('test', $content['scripts'])) {
19✔
222
                $content['scripts']['test'] = [
19✔
223
                    '@clear',
19✔
224
                    InstalledVersions::isInstalled('pestphp/pest')
19✔
UNCOV
225
                        ? '@php vendor/bin/pest'
×
226
                        : '@php vendor/bin/phpunit',
19✔
227
                ];
19✔
228
            }
229
        }
230

231
        return $content;
19✔
232
    }
233

234
    /**
235
     * Append `autoload-dev` to `composer.json`.
236
     */
237
    protected function appendAutoloadDevToComposer(array $content, Filesystem $filesystem): array
238
    {
239
        /** @var array{autoload-dev?: array{psr-4?: array<string, string>}} $content */
240
        if (! \array_key_exists('autoload-dev', $content)) {
19✔
241
            $content['autoload-dev'] = [];
19✔
242
        }
243

244
        /** @var array{autoload-dev: array{psr-4?: array<string, string>}} $content */
245
        if (! \array_key_exists('psr-4', $content['autoload-dev'])) {
19✔
246
            $content['autoload-dev']['psr-4'] = [];
19✔
247
        }
248

249
        if (confirm('Prefix with `Workbench` namespace?', default: true) === false) {
19✔
250
            $this->workbenchNamespacePrefix = '';
4✔
251
        }
252

253
        $namespaces = [
19✔
254
            'workbench/app/' => $this->workbenchNamespacePrefix.'App\\',
19✔
255
            'workbench/database/factories/' => $this->workbenchNamespacePrefix.'Database\\Factories\\',
19✔
256
            'workbench/database/seeders/' => $this->workbenchNamespacePrefix.'Database\\Seeders\\',
19✔
257
        ];
19✔
258

259
        $autoloads = array_flip($content['autoload-dev']['psr-4']);
19✔
260

261
        foreach ($namespaces as $path => $namespace) {
19✔
262
            if (! \array_key_exists($path, $autoloads)) {
19✔
263
                $content['autoload-dev']['psr-4'][$namespace] = $path;
19✔
264

265
                $this->components->task(\sprintf(
19✔
266
                    'Added [%s] for [%s] to Composer', $namespace, './'.rtrim($path, '/')
19✔
267
                ));
19✔
268
            } else {
UNCOV
269
                $this->components->twoColumnDetail(
×
UNCOV
270
                    \sprintf('Composer already contains [%s] path assigned to [%s] namespace', './'.rtrim($path, '/'), $autoloads[$path]),
×
UNCOV
271
                    '<fg=yellow;options=bold>SKIPPED</>'
×
UNCOV
272
                );
×
273
            }
274
        }
275

276
        return $content;
19✔
277
    }
278

279
    /**
280
     * Prompt the user for any missing arguments.
281
     *
282
     * @return void
283
     */
284
    protected function promptForMissingArguments(InputInterface $input, OutputInterface $output)
285
    {
286
        $install = null;
18✔
287

288
        if (\is_null($input->getOption('install'))) {
18✔
289
            $install = confirm('Run Workbench installation?', true);
1✔
290
        }
291

292
        if (! \is_null($install)) {
18✔
293
            $input->setOption('install', $install);
1✔
294
        }
295
    }
296

297
    /**
298
     * Get the console command options.
299
     *
300
     * @return array
301
     */
302
    protected function getOptions()
303
    {
304
        return [
19✔
305
            ['force', 'f', InputOption::VALUE_NONE, 'Overwrite any existing files'],
19✔
306
            ['install', null, InputOption::VALUE_NEGATABLE, 'Run Workbench installation'],
19✔
307
            ['basic', null, InputOption::VALUE_NONE, 'Workbench installation without discovers and routes'],
19✔
308
        ];
19✔
309
    }
310
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc