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

orchestral / workbench / 12245788578

09 Dec 2024 10:53PM UTC coverage: 91.356% (-2.8%) from 94.118%
12245788578

push

github

crynobone
Merge branch '7.x' into 8.x

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

14 of 14 new or added lines in 1 file covered. (100.0%)

30 existing lines in 2 files now uncovered.

539 of 590 relevant lines covered (91.36%)

13.57 hits per line

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

84.11
/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\Workbench;
18
use Symfony\Component\Console\Attribute\AsCommand;
19
use Symfony\Component\Console\Input\InputInterface;
20
use Symfony\Component\Console\Input\InputOption;
21
use Symfony\Component\Console\Output\OutputInterface;
22

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

27
#[AsCommand(name: 'workbench:devtool', description: 'Configure Workbench for package development')]
28
class DevToolCommand extends Command implements PromptsForMissingInput
29
{
30
    use Concerns\InteractsWithFiles;
31

32
    /**
33
     * Execute the console command.
34
     *
35
     * @return int
36
     */
37
    public function handle(Filesystem $filesystem)
38
    {
39
        $workingPath = package_path();
13✔
40

41
        event(new InstallStarted($this->input, $this->output, $this->components));
13✔
42

43
        $this->prepareWorkbenchDirectories($filesystem, $workingPath);
13✔
44
        $this->prepareWorkbenchNamespaces($filesystem, $workingPath);
13✔
45

46
        if ($this->option('install') === true) {
13✔
47
            $this->call('workbench:install', [
8✔
48
                '--force' => $this->option('force'),
8✔
49
                '--no-devtool' => true,
8✔
50
                '--basic' => $this->option('basic'),
8✔
51
            ]);
8✔
52
        }
53

54
        return tap(Command::SUCCESS, function ($exitCode) use ($workingPath) {
13✔
55
            event(new InstallEnded($this->input, $this->output, $this->components, $exitCode));
13✔
56

57
            (new DumpComposerAutoloads($workingPath))->handle();
13✔
58
        });
13✔
59
    }
60

61
    /**
62
     * Prepare workbench directories.
63
     */
64
    protected function prepareWorkbenchDirectories(Filesystem $filesystem, string $workingPath): void
65
    {
66
        $workbenchWorkingPath = join_paths($workingPath, 'workbench');
13✔
67

68
        (new EnsureDirectoryExists(
13✔
69
            filesystem: $filesystem,
13✔
70
            components: $this->components,
13✔
71
        ))->handle(
13✔
72
            Collection::make([
13✔
73
                join_paths('app', 'Models'),
13✔
74
                join_paths('database', 'factories'),
13✔
75
                join_paths('database', 'migrations'),
13✔
76
                join_paths('database', 'seeders'),
13✔
77
            ])->when(
13✔
78
                $this->option('basic') === false,
13✔
79
                fn ($directories) => $directories->push(...['routes', join_paths('resources', 'views')])
13✔
80
            )->map(static fn ($directory) => join_paths($workbenchWorkingPath, $directory))
13✔
81
        );
13✔
82

83
        $this->callSilently('make:provider', [
13✔
84
            'name' => 'WorkbenchServiceProvider',
13✔
85
            '--preset' => 'workbench',
13✔
86
            '--force' => (bool) $this->option('force'),
13✔
87
        ]);
13✔
88

89
        $this->prepareWorkbenchDatabaseSchema($filesystem, $workbenchWorkingPath);
13✔
90

91
        if ($this->option('basic') === false) {
13✔
92
            foreach (['api', 'console', 'web'] as $route) {
9✔
93
                (new GeneratesFile(
9✔
94
                    filesystem: $filesystem,
9✔
95
                    components: $this->components,
9✔
96
                    force: (bool) $this->option('force'),
9✔
97
                ))->handle(
9✔
98
                    (string) Workbench::stubFile("routes.{$route}"),
9✔
99
                    join_paths($workbenchWorkingPath, 'routes', "{$route}.php")
9✔
100
                );
9✔
101
            }
102
        }
103
    }
104

105
    /**
106
     * Prepare workbench namespace to `composer.json`.
107
     */
108
    protected function prepareWorkbenchNamespaces(Filesystem $filesystem, string $workingPath): void
109
    {
110
        (new ModifyComposer($workingPath))
13✔
111
            ->handle(fn (array $content) => $this->appendScriptsToComposer(
13✔
112
                $this->appendAutoloadDevToComposer($content, $filesystem), $filesystem
13✔
113
            ));
13✔
114
    }
115

116
    /**
117
     * Prepare workbench database schema including user model, factory and seeder.
118
     */
119
    protected function prepareWorkbenchDatabaseSchema(Filesystem $filesystem, string $workingPath): void
120
    {
121
        $this->callSilently('make:user-model', [
13✔
122
            '--preset' => 'workbench',
13✔
123
            '--force' => (bool) $this->option('force'),
13✔
124
        ]);
13✔
125

126
        $this->callSilently('make:user-factory', [
13✔
127
            '--preset' => 'workbench',
13✔
128
            '--force' => (bool) $this->option('force'),
13✔
129
        ]);
13✔
130

131
        (new GeneratesFile(
13✔
132
            filesystem: $filesystem,
13✔
133
            components: $this->components,
13✔
134
            force: (bool) $this->option('force'),
13✔
135
        ))->handle(
13✔
136
            (string) Workbench::stubFile('seeders.database'),
13✔
137
            join_paths($workingPath, 'database', 'seeders', 'DatabaseSeeder.php')
13✔
138
        );
13✔
139

140
        if ($filesystem->exists(join_paths($workingPath, 'database', 'factories', 'UserFactory.php'))) {
13✔
141
            $filesystem->replaceInFile([
13✔
142
                'use Orchestra\Testbench\Factories\UserFactory;',
13✔
143
            ], [
13✔
144
                'use Workbench\Database\Factories\UserFactory;',
13✔
145
            ], join_paths($workingPath, 'database', 'seeders', 'DatabaseSeeder.php'));
13✔
146
        }
147
    }
148

149
    /**
150
     * Append `scripts` to `composer.json`.
151
     */
152
    protected function appendScriptsToComposer(array $content, Filesystem $filesystem): array
153
    {
154
        $hasScriptsSection = \array_key_exists('scripts', $content);
13✔
155
        $hasTestbenchDusk = InstalledVersions::isInstalled('orchestra/testbench-dusk');
13✔
156

157
        if (! $hasScriptsSection) {
13✔
158
            $content['scripts'] = [];
13✔
159
        }
160

161
        $postAutoloadDumpScripts = array_filter([
13✔
162
            '@clear',
13✔
163
            '@prepare',
13✔
164
            $hasTestbenchDusk ? '@dusk:install-chromedriver' : null,
13✔
165
        ]);
13✔
166

167
        if (! \array_key_exists('post-autoload-dump', $content['scripts'])) {
13✔
168
            $content['scripts']['post-autoload-dump'] = $postAutoloadDumpScripts;
13✔
169
        } else {
UNCOV
170
            $content['scripts']['post-autoload-dump'] = array_values(array_unique([
×
UNCOV
171
                ...$postAutoloadDumpScripts,
×
UNCOV
172
                ...Arr::wrap($content['scripts']['post-autoload-dump']),
×
UNCOV
173
            ]));
×
174
        }
175

176
        $content['scripts']['clear'] = '@php vendor/bin/testbench package:purge-skeleton --ansi';
13✔
177
        $content['scripts']['prepare'] = '@php vendor/bin/testbench package:discover --ansi';
13✔
178

179
        if ($hasTestbenchDusk) {
13✔
UNCOV
180
            $content['scripts']['dusk:install-chromedriver'] = '@php vendor/bin/dusk-updater detect --auto-update --ansi';
×
181
        }
182

183
        $content['scripts']['build'] = '@php vendor/bin/testbench workbench:build --ansi';
13✔
184
        $content['scripts']['serve'] = [
13✔
185
            'Composer\\Config::disableProcessTimeout',
13✔
186
            '@build',
13✔
187
            $hasTestbenchDusk && \defined('TESTBENCH_DUSK')
13✔
UNCOV
188
                ? '@php vendor/bin/testbench-dusk serve --ansi'
×
189
                : '@php vendor/bin/testbench serve --ansi',
13✔
190
        ];
13✔
191

192
        if (! \array_key_exists('lint', $content['scripts'])) {
13✔
193
            $lintScripts = [];
13✔
194

195
            if (InstalledVersions::isInstalled('laravel/pint')) {
13✔
196
                $lintScripts[] = '@php vendor/bin/pint --ansi';
13✔
UNCOV
197
            } elseif ($filesystem->exists(Workbench::packagePath('pint.json'))) {
×
UNCOV
198
                $lintScripts[] = 'pint';
×
199
            }
200

201
            if (InstalledVersions::isInstalled('phpstan/phpstan')) {
13✔
202
                $lintScripts[] = '@php vendor/bin/phpstan analyse --verbose --ansi';
13✔
203
            }
204

205
            if (\count($lintScripts) > 0) {
13✔
206
                $content['scripts']['lint'] = $lintScripts;
13✔
207
            }
208
        }
209

210
        if (
211
            $filesystem->exists(Workbench::packagePath('phpunit.xml'))
13✔
212
            || $filesystem->exists(Workbench::packagePath('phpunit.xml.dist'))
13✔
213
        ) {
UNCOV
214
            if (! \array_key_exists('test', $content['scripts'])) {
×
UNCOV
215
                $content['scripts']['test'] = [
×
UNCOV
216
                    '@clear',
×
UNCOV
217
                    InstalledVersions::isInstalled('pestphp/pest')
×
UNCOV
218
                        ? '@php vendor/bin/pest'
×
UNCOV
219
                        : '@php vendor/bin/phpunit',
×
UNCOV
220
                ];
×
221
            }
222
        }
223

224
        return $content;
13✔
225
    }
226

227
    /**
228
     * Append `autoload-dev` to `composer.json`.
229
     */
230
    protected function appendAutoloadDevToComposer(array $content, Filesystem $filesystem): array
231
    {
232
        /** @var array{autoload-dev?: array{psr-4?: array<string, string>}} $content */
233
        if (! \array_key_exists('autoload-dev', $content)) {
13✔
UNCOV
234
            $content['autoload-dev'] = [];
×
235
        }
236

237
        /** @var array{autoload-dev: array{psr-4?: array<string, string>}} $content */
238
        if (! \array_key_exists('psr-4', $content['autoload-dev'])) {
13✔
UNCOV
239
            $content['autoload-dev']['psr-4'] = [];
×
240
        }
241

242
        $namespaces = [
13✔
243
            'Workbench\\App\\' => 'workbench/app/',
13✔
244
            'Workbench\\Database\\Factories\\' => 'workbench/database/factories/',
13✔
245
            'Workbench\\Database\\Seeders\\' => 'workbench/database/seeders/',
13✔
246
        ];
13✔
247

248
        foreach ($namespaces as $namespace => $path) {
13✔
249
            if (! \array_key_exists($namespace, $content['autoload-dev']['psr-4'])) {
13✔
UNCOV
250
                $content['autoload-dev']['psr-4'][$namespace] = $path;
×
251

UNCOV
252
                $this->components->task(\sprintf(
×
UNCOV
253
                    'Added [%s] for [%s] to Composer', $namespace, $path
×
UNCOV
254
                ));
×
255
            } else {
256
                $this->components->twoColumnDetail(
13✔
257
                    \sprintf('Composer already contain [%s] namespace', $namespace),
13✔
258
                    '<fg=yellow;options=bold>SKIPPED</>'
13✔
259
                );
13✔
260
            }
261
        }
262

263
        return $content;
13✔
264
    }
265

266
    /**
267
     * Prompt the user for any missing arguments.
268
     *
269
     * @return void
270
     */
271
    protected function promptForMissingArguments(InputInterface $input, OutputInterface $output)
272
    {
273
        $install = null;
13✔
274

275
        if ($input->getOption('skip-install') === true) {
13✔
UNCOV
276
            $install = false;
×
277
        } elseif (\is_null($input->getOption('install'))) {
13✔
UNCOV
278
            $install = confirm('Run Workbench installation?', true);
×
279
        }
280

281
        if (! \is_null($install)) {
13✔
UNCOV
282
            $input->setOption('install', $install);
×
283
        }
284
    }
285

286
    /**
287
     * Get the console command options.
288
     *
289
     * @return array
290
     */
291
    protected function getOptions()
292
    {
293
        return [
13✔
294
            ['force', 'f', InputOption::VALUE_NONE, 'Overwrite any existing files'],
13✔
295
            ['install', null, InputOption::VALUE_NEGATABLE, 'Run Workbench installation'],
13✔
296
            ['basic', null, InputOption::VALUE_NONE, 'Workbench installation without discovers and routes'],
13✔
297

298
            /** @deprecated */
299
            ['skip-install', null, InputOption::VALUE_NONE, 'Skipped Workbench installation (deprecated)'],
13✔
300
        ];
13✔
301
    }
302
}
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