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

orchestral / workbench / 12239578785

09 Dec 2024 04:08PM UTC coverage: 92.599% (-1.9%) from 94.49%
12239578785

push

github

web-flow
[7.x] Improves `workbench:install` workflow and tests (#58)

* [7.x] Test Improvements

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

* wip

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

* wip

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

* wip

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

* wip

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

* wip

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

* wip

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

* wip

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

* wip

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

* wip

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

* wip

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

* wip

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

* wip

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

* wip

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

* wip

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

* wip

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

---------

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

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

23 existing lines in 2 files now uncovered.

538 of 581 relevant lines covered (92.6%)

15.26 hits per line

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

85.42
/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\Filesystem\Filesystem;
8
use Illuminate\Support\Arr;
9
use Illuminate\Support\Collection;
10
use Orchestra\Testbench\Foundation\Console\Actions\EnsureDirectoryExists;
11
use Orchestra\Testbench\Foundation\Console\Actions\GeneratesFile;
12
use Orchestra\Workbench\Actions\DumpComposerAutoloads;
13
use Orchestra\Workbench\Actions\ModifyComposer;
14
use Orchestra\Workbench\Events\InstallEnded;
15
use Orchestra\Workbench\Events\InstallStarted;
16
use Orchestra\Workbench\Workbench;
17
use Symfony\Component\Console\Attribute\AsCommand;
18
use Symfony\Component\Console\Input\InputOption;
19

20
use function Orchestra\Testbench\join_paths;
21
use function Orchestra\Testbench\package_path;
22

23
#[AsCommand(name: 'workbench:devtool', description: 'Configure Workbench for package development')]
24
class DevToolCommand extends Command
25
{
26
    use Concerns\InteractsWithFiles;
27

28
    /**
29
     * Execute the console command.
30
     *
31
     * @return int
32
     */
33
    public function handle(Filesystem $filesystem)
34
    {
35
        $workingPath = package_path();
16✔
36

37
        event(new InstallStarted($this->input, $this->output, $this->components));
16✔
38

39
        $this->prepareWorkbenchDirectories($filesystem, $workingPath);
16✔
40
        $this->prepareWorkbenchNamespaces($filesystem, $workingPath);
16✔
41

42
        if ($this->option('install') === true && $this->option('skip-install') === false) {
16✔
43
            $this->call('workbench:install', [
10✔
44
                '--force' => $this->option('force'),
10✔
45
                '--no-devtool' => true,
10✔
46
                '--basic' => $this->option('basic'),
10✔
47
            ]);
10✔
48
        }
49

50
        return tap(Command::SUCCESS, function ($exitCode) use ($workingPath) {
16✔
51
            event(new InstallEnded($this->input, $this->output, $this->components, $exitCode));
16✔
52

53
            (new DumpComposerAutoloads($workingPath))->handle();
16✔
54
        });
16✔
55
    }
56

57
    /**
58
     * Prepare workbench directories.
59
     */
60
    protected function prepareWorkbenchDirectories(Filesystem $filesystem, string $workingPath): void
61
    {
62
        $workbenchWorkingPath = join_paths($workingPath, 'workbench');
16✔
63

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

79
        $this->callSilently('make:provider', [
16✔
80
            'name' => 'WorkbenchServiceProvider',
16✔
81
            '--preset' => 'workbench',
16✔
82
            '--force' => (bool) $this->option('force'),
16✔
83
        ]);
16✔
84

85
        $this->prepareWorkbenchDatabaseSchema($filesystem, $workbenchWorkingPath);
16✔
86

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

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

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

122
        $this->callSilently('make:user-factory', [
16✔
123
            '--preset' => 'workbench',
16✔
124
            '--force' => (bool) $this->option('force'),
16✔
125
        ]);
16✔
126

127
        (new GeneratesFile(
16✔
128
            filesystem: $filesystem,
16✔
129
            components: $this->components,
16✔
130
            force: (bool) $this->option('force'),
16✔
131
        ))->handle(
16✔
132
            (string) Workbench::stubFile('seeders.database'),
16✔
133
            join_paths($workingPath, 'database', 'seeders', 'DatabaseSeeder.php')
16✔
134
        );
16✔
135

136
        if ($filesystem->exists(join_paths($workingPath, 'database', 'factories', 'UserFactory.php'))) {
16✔
137
            $this->replaceInFile($filesystem, [
16✔
138
                'use Orchestra\Testbench\Factories\UserFactory;',
16✔
139
            ], [
16✔
140
                'use Workbench\Database\Factories\UserFactory;',
16✔
141
            ], join_paths($workingPath, 'database', 'seeders', 'DatabaseSeeder.php'));
16✔
142
        }
143
    }
144

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

153
        if (! $hasScriptsSection) {
16✔
154
            $content['scripts'] = [];
16✔
155
        }
156

157
        $postAutoloadDumpScripts = array_filter([
16✔
158
            '@clear',
16✔
159
            '@prepare',
16✔
160
            $hasTestbenchDusk ? '@dusk:install-chromedriver' : null,
16✔
161
        ]);
16✔
162

163
        if (! \array_key_exists('post-autoload-dump', $content['scripts'])) {
16✔
164
            $content['scripts']['post-autoload-dump'] = $postAutoloadDumpScripts;
16✔
165
        } else {
UNCOV
166
            $content['scripts']['post-autoload-dump'] = array_values(array_unique([
×
UNCOV
167
                ...$postAutoloadDumpScripts,
×
UNCOV
168
                ...Arr::wrap($content['scripts']['post-autoload-dump']),
×
UNCOV
169
            ]));
×
170
        }
171

172
        $content['scripts']['clear'] = '@php vendor/bin/testbench package:purge-skeleton --ansi';
16✔
173
        $content['scripts']['prepare'] = '@php vendor/bin/testbench package:discover --ansi';
16✔
174

175
        if ($hasTestbenchDusk) {
16✔
UNCOV
176
            $content['scripts']['dusk:install-chromedriver'] = '@php vendor/bin/dusk-updater detect --auto-update --ansi';
×
177
        }
178

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

188
        if (! \array_key_exists('lint', $content['scripts'])) {
16✔
189
            $lintScripts = [];
16✔
190

191
            if (InstalledVersions::isInstalled('laravel/pint')) {
16✔
192
                $lintScripts[] = '@php vendor/bin/pint --ansi';
16✔
UNCOV
193
            } elseif ($filesystem->exists(Workbench::packagePath('pint.json'))) {
×
UNCOV
194
                $lintScripts[] = 'pint';
×
195
            }
196

197
            if (InstalledVersions::isInstalled('phpstan/phpstan')) {
16✔
198
                $lintScripts[] = '@php vendor/bin/phpstan analyse --verbose --ansi';
16✔
199
            }
200

201
            if (\count($lintScripts) > 0) {
16✔
202
                $content['scripts']['lint'] = $lintScripts;
16✔
203
            }
204
        }
205

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

220
        return $content;
16✔
221
    }
222

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

233
        /** @var array{autoload-dev: array{psr-4?: array<string, string>}} $content */
234
        if (! \array_key_exists('psr-4', $content['autoload-dev'])) {
16✔
UNCOV
235
            $content['autoload-dev']['psr-4'] = [];
×
236
        }
237

238
        $namespaces = [
16✔
239
            'Workbench\\App\\' => 'workbench/app/',
16✔
240
            'Workbench\\Database\\Factories\\' => 'workbench/database/factories/',
16✔
241
            'Workbench\\Database\\Seeders\\' => 'workbench/database/seeders/',
16✔
242
        ];
16✔
243

244
        foreach ($namespaces as $namespace => $path) {
16✔
245
            if (! \array_key_exists($namespace, $content['autoload-dev']['psr-4'])) {
16✔
UNCOV
246
                $content['autoload-dev']['psr-4'][$namespace] = $path;
×
247

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

259
        return $content;
16✔
260
    }
261

262
    /**
263
     * Get the console command options.
264
     *
265
     * @return array
266
     */
267
    protected function getOptions()
268
    {
269
        return [
16✔
270
            ['force', 'f', InputOption::VALUE_NONE, 'Overwrite any existing files'],
16✔
271
            ['install', null, InputOption::VALUE_NEGATABLE, 'Run Workbench installation'],
16✔
272
            ['basic', null, InputOption::VALUE_NONE, 'Workbench installation without discovers and routes'],
16✔
273

274
            /** @deprecated */
275
            ['skip-install', null, InputOption::VALUE_NONE, 'Skipped Workbench installation (deprecated)'],
16✔
276
        ];
16✔
277
    }
278
}
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