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

orchestral / testbench-core / 13764189331

10 Mar 2025 12:05PM UTC coverage: 93.162% (+0.08%) from 93.085%
13764189331

Pull #326

github

web-flow
Merge 72c756a12 into d68076bb3
Pull Request #326: Add `Orchestra\Testbench\Foundation\Actions\RemoteCommand`.

15 of 17 new or added lines in 2 files covered. (88.24%)

4 existing lines in 1 file now uncovered.

1376 of 1477 relevant lines covered (93.16%)

62.92 hits per line

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

95.29
/src/functions.php
1
<?php
2

3
namespace Orchestra\Testbench;
4

5
use Closure;
6
use Illuminate\Contracts\Console\Kernel as ConsoleKernel;
7
use Illuminate\Contracts\Foundation\Application as ApplicationContract;
8
use Illuminate\Filesystem\Filesystem;
9
use Illuminate\Foundation\Application;
10
use Illuminate\Routing\Router;
11
use Illuminate\Support\Arr;
12
use Illuminate\Support\Collection;
13
use Illuminate\Support\ProcessUtils;
14
use Illuminate\Support\Str;
15
use Illuminate\Testing\PendingCommand;
16
use InvalidArgumentException;
17
use Orchestra\Sidekick;
18
use Orchestra\Testbench\Foundation\Env;
19
use PHPUnit\Runner\Version;
20
use Symfony\Component\Process\Process;
21

22
/**
23
 * Create Laravel application instance.
24
 *
25
 * @api
26
 *
27
 * @param  string|null  $basePath
28
 * @param  (callable(\Illuminate\Foundation\Application):(void))|null  $resolvingCallback
29
 * @param  array{extra?: array{providers?: array, dont-discover?: array, env?: array}, load_environment_variables?: bool, enabled_package_discoveries?: bool}  $options
30
 * @return \Orchestra\Testbench\Foundation\Application
31
 */
32
function container(?string $basePath = null, ?callable $resolvingCallback = null, array $options = []): Foundation\Application
33
{
34
    return Foundation\Application::make($basePath, $resolvingCallback, $options);
3✔
35
}
36

37
/**
38
 * Run artisan command.
39
 *
40
 * @api
41
 *
42
 * @param  \Orchestra\Testbench\Contracts\TestCase|\Illuminate\Contracts\Foundation\Application  $context
43
 * @param  string  $command
44
 * @param  array<string, mixed>  $parameters
45
 * @return int
46
 */
47
function artisan(Contracts\TestCase|ApplicationContract $context, string $command, array $parameters = []): int
48
{
49
    if ($context instanceof ApplicationContract) {
10✔
50
        return $context->make(ConsoleKernel::class)->call($command, $parameters);
1✔
51
    }
52

53
    $command = $context->artisan($command, $parameters);
10✔
54

55
    return $command instanceof PendingCommand ? $command->run() : $command;
10✔
56
}
57

58
/**
59
 * Run remote action using Testbench CLI.
60
 *
61
 * @api
62
 *
63
 * @param  array<int, string>|string  $command
64
 * @param  array<string, mixed>|string  $env
65
 * @param  bool|null  $tty
66
 * @return \Symfony\Component\Process\Process
67
 */
68
function remote(array|string $command, array|string $env = [], ?bool $tty = null): Process
69
{
70
    $remote = new Foundation\Actions\RemoteCommand($command, $env, $tty);
10✔
71

72
    return $remote();
10✔
73
}
74

75
/**
76
 * Run callback only once.
77
 *
78
 * @api
79
 *
80
 * @param  mixed  $callback
81
 * @return \Closure():mixed
82
 *
83
 * @deprecated 7.55.0 Use `Orchestra\Sidekick\once()` instead.
84
 *
85
 * @codeCoverageIgnore
86
 */
87
function once($callback): Closure
88
{
89
    return Sidekick\once($callback);
90
}
91

92
/**
93
 * Register after resolving callback.
94
 *
95
 * @api
96
 *
97
 * @param  \Illuminate\Contracts\Foundation\Application  $app
98
 * @param  string  $name
99
 * @param  (\Closure(object, \Illuminate\Contracts\Foundation\Application):(mixed))|null  $callback
100
 * @return void
101
 */
102
function after_resolving(ApplicationContract $app, string $name, ?Closure $callback = null): void
103
{
104
    $app->afterResolving($name, $callback);
169✔
105

106
    if ($app->resolved($name)) {
169✔
107
        value($callback, $app->make($name), $app);
5✔
108
    }
109
}
110

111
/**
112
 * Load migration paths.
113
 *
114
 * @api
115
 *
116
 * @param  \Illuminate\Contracts\Foundation\Application  $app
117
 * @param  array<int, string>|string  $paths
118
 * @return void
119
 */
120
function load_migration_paths(ApplicationContract $app, array|string $paths): void
121
{
122
    after_resolving($app, 'migrator', static function ($migrator) use ($paths) {
37✔
123
        foreach (Arr::wrap($paths) as $path) {
15✔
124
            /** @var \Illuminate\Database\Migrations\Migrator $migrator */
125
            $migrator->path($path);
15✔
126
        }
127
    });
37✔
128
}
129

130
/**
131
 * Get default environment variables.
132
 *
133
 * @return array<int, string>
134
 *
135
 * @deprecated
136
 *
137
 * @codeCoverageIgnore
138
 */
139
function default_environment_variables(): array
140
{
141
    return [];
142
}
143

144
/**
145
 * Get defined environment variables.
146
 *
147
 * @api
148
 *
149
 * @return array<string, mixed>
150
 */
151
function defined_environment_variables(): array
152
{
153
    return Collection::make(array_merge($_SERVER, $_ENV))
10✔
154
        ->keys()
10✔
155
        ->mapWithKeys(static fn (string $key) => [$key => Env::forward($key)])
10✔
156
        ->unless(
10✔
157
            Env::has('TESTBENCH_WORKING_PATH'), static fn ($env) => $env->put('TESTBENCH_WORKING_PATH', package_path())
10✔
158
        )->all();
10✔
159
}
160

161
/**
162
 * Get default environment variables.
163
 *
164
 * @api
165
 *
166
 * @param  iterable<string, mixed>  $variables
167
 * @return array<int, string>
168
 */
169
function parse_environment_variables($variables): array
170
{
171
    return Collection::make($variables)
4✔
172
        ->transform(static function ($value, $key) {
4✔
173
            if (\is_bool($value) || \in_array($value, ['true', 'false'])) {
4✔
174
                $value = \in_array($value, [true, 'true']) ? '(true)' : '(false)';
4✔
175
            } elseif (\is_null($value) || \in_array($value, ['null'])) {
1✔
176
                $value = '(null)';
1✔
177
            } else {
178
                $value = $key === 'APP_DEBUG' ? \sprintf('(%s)', Str::of($value)->ltrim('(')->rtrim(')')) : "'{$value}'";
1✔
179
            }
180

181
            return "{$key}={$value}";
4✔
182
        })->values()->all();
4✔
183
}
184

185
/**
186
 * Refresh router lookups.
187
 *
188
 * @api
189
 *
190
 * @param  \Illuminate\Routing\Router  $router
191
 * @return void
192
 */
193
function refresh_router_lookups(Router $router): void
194
{
195
    $router->getRoutes()->refreshNameLookups();
169✔
196
}
197

198
/**
199
 * Transform realpath to alias path.
200
 *
201
 * @api
202
 *
203
 * @param  string  $path
204
 * @param  string|null  $workingPath
205
 * @return string
206
 */
207
function transform_realpath_to_relative(string $path, ?string $workingPath = null, string $prefix = ''): string
208
{
209
    $separator = DIRECTORY_SEPARATOR;
13✔
210

211
    if (! \is_null($workingPath)) {
13✔
212
        return str_replace(rtrim($workingPath, $separator).$separator, $prefix.$separator, $path);
1✔
213
    }
214

215
    $laravelPath = base_path();
12✔
216
    $workbenchPath = workbench_path();
12✔
217
    $packagePath = package_path();
12✔
218

219
    return match (true) {
12✔
220
        str_starts_with($path, $laravelPath) => str_replace($laravelPath.$separator, '@laravel'.$separator, $path),
12✔
221
        str_starts_with($path, $workbenchPath) => str_replace($workbenchPath.$separator, '@workbench'.$separator, $path),
12✔
222
        str_starts_with($path, $packagePath) => str_replace($packagePath.$separator, '.'.$separator, $path),
12✔
223
        ! empty($prefix) => implode($separator, [$prefix, ltrim($path, $separator)]),
12✔
224
        default => $path,
12✔
225
    };
12✔
226
}
227

228
/**
229
 * Transform relative path.
230
 *
231
 * @api
232
 *
233
 * @param  string  $path
234
 * @param  string  $workingPath
235
 * @return string
236
 *
237
 * @deprecated 7.55.0 Use `Orchestra\Sidekick\transform_relative_path()` instead.
238
 *
239
 * @codeCoverageIgnore
240
 */
241
function transform_relative_path(string $path, string $workingPath): string
242
{
243
    return Sidekick\transform_relative_path($path, $workingPath);
244
}
245

246
/**
247
 * Get the default skeleton path.
248
 *
249
 * @api
250
 *
251
 * @no-named-arguments
252
 *
253
 * @param  array<int, string|null>|string  ...$path
254
 * @return string
255
 */
256
function default_skeleton_path(array|string $path = ''): string
257
{
258
    return (string) realpath(join_paths(__DIR__, '..', 'laravel', ...Arr::wrap(\func_num_args() > 1 ? \func_get_args() : $path)));
166✔
259
}
260

261
/**
262
 * Get the migration path by type.
263
 *
264
 * @api
265
 *
266
 * @param  string|null  $type
267
 * @return string
268
 *
269
 * @throws \InvalidArgumentException
270
 */
271
function default_migration_path(?string $type = null): string
272
{
273
    $path = realpath(
43✔
274
        \is_null($type) ? base_path('migrations') : base_path(join_paths('migrations', $type))
43✔
275
    );
43✔
276

277
    if ($path === false) {
43✔
UNCOV
278
        throw new InvalidArgumentException(\sprintf('Unable to resolve migration path for type [%s]', $type ?? 'laravel'));
×
279
    }
280

281
    return $path;
43✔
282
}
283

284
/**
285
 * Get the path to the package folder.
286
 *
287
 * @api
288
 *
289
 * @no-named-arguments
290
 *
291
 * @param  array<int, string|null>|string  ...$path
292
 * @return string
293
 */
294
function package_path(array|string $path = ''): string
295
{
296
    $argumentCount = \func_num_args();
66✔
297

298
    $workingPath = \defined('TESTBENCH_WORKING_PATH')
66✔
299
        ? TESTBENCH_WORKING_PATH
32✔
300
        : Env::get('TESTBENCH_WORKING_PATH', getcwd());
35✔
301

302
    if ($argumentCount === 1 && \is_string($path) && str_starts_with($path, './')) {
66✔
UNCOV
303
        return transform_relative_path($path, $workingPath);
×
304
    }
305

306
    $path = join_paths(...Arr::wrap($argumentCount > 1 ? \func_get_args() : $path));
66✔
307

308
    return str_starts_with($path, './')
66✔
UNCOV
309
        ? transform_relative_path($path, $workingPath)
×
310
        : join_paths(rtrim($workingPath, DIRECTORY_SEPARATOR), $path);
66✔
311
}
312

313
/**
314
 * Get the workbench configuration.
315
 *
316
 * @api
317
 *
318
 * @return array<string, mixed>
319
 */
320
function workbench(): array
321
{
322
    /** @var \Orchestra\Testbench\Contracts\Config $config */
323
    $config = app()->bound(Contracts\Config::class)
34✔
324
        ? app()->make(Contracts\Config::class)
32✔
325
        : new Foundation\Config;
2✔
326

327
    return $config->getWorkbenchAttributes();
34✔
328
}
329

330
/**
331
 * Get the path to the workbench folder.
332
 *
333
 * @api
334
 *
335
 * @no-named-arguments
336
 *
337
 * @param  array<int, string|null>|string  ...$path
338
 * @return string
339
 */
340
function workbench_path(array|string $path = ''): string
341
{
342
    return package_path('workbench', ...Arr::wrap(\func_num_args() > 1 ? \func_get_args() : $path));
57✔
343
}
344

345
/**
346
 * Get the migration path by type.
347
 *
348
 * @api
349
 *
350
 * @param  string|null  $type
351
 * @return string
352
 *
353
 * @throws \InvalidArgumentException
354
 *
355
 * @deprecated
356
 */
357
function laravel_migration_path(?string $type = null): string
358
{
359
    return default_migration_path($type);
1✔
360
}
361

362
/**
363
 * Determine if vendor symlink exists on the laravel application.
364
 *
365
 * @api
366
 *
367
 * @param  \Illuminate\Contracts\Foundation\Application  $app
368
 * @param  string|null  $workingPath
369
 * @return bool
370
 */
371
function laravel_vendor_exists(ApplicationContract $app, ?string $workingPath = null): bool
372
{
373
    $filesystem = new Filesystem;
8✔
374

375
    $appVendorPath = $app->basePath('vendor');
8✔
376
    $workingPath ??= package_path('vendor');
8✔
377

378
    return $filesystem->isFile(join_paths($appVendorPath, 'autoload.php')) &&
8✔
379
        $filesystem->hash(join_paths($appVendorPath, 'autoload.php')) === $filesystem->hash(join_paths($workingPath, 'autoload.php'));
8✔
380
}
381

382
/**
383
 * Laravel version compare.
384
 *
385
 * @api
386
 *
387
 * @template TOperator of string|null
388
 *
389
 * @param  string  $version
390
 * @param  string|null  $operator
391
 * @return int|bool
392
 *
393
 * @phpstan-param  TOperator  $operator
394
 *
395
 * @phpstan-return (TOperator is null ? int : bool)
396
 */
397
function laravel_version_compare(string $version, ?string $operator = null)
398
{
399
    return Sidekick\laravel_version_compare($version, $operator);
1✔
400
}
401

402
/**
403
 * PHPUnit version compare.
404
 *
405
 * @api
406
 *
407
 * @template TOperator of string|null
408
 *
409
 * @param  string  $version
410
 * @param  string|null  $operator
411
 * @return int|bool
412
 *
413
 * @throws \RuntimeException
414
 *
415
 * @phpstan-param  TOperator  $operator
416
 *
417
 * @phpstan-return (TOperator is null ? int : bool)
418
 */
419
function phpunit_version_compare(string $version, ?string $operator = null)
420
{
421
    return Sidekick\phpunit_version_compare($version, $operator);
1✔
422
}
423

424
/**
425
 * Determine the PHP Binary.
426
 *
427
 * @api
428
 *
429
 * @param  bool  $escape
430
 * @return string
431
 */
432
function php_binary(bool $escape = false): string
433
{
434
    $phpBinary = Sidekick\php_binary();
10✔
435

436
    return $escape === true ? ProcessUtils::escapeArgument((string) $phpBinary) : $phpBinary;
10✔
437
}
438

439
/**
440
 * Join the given paths together.
441
 *
442
 * @param  string|null  $basePath
443
 * @param  string  ...$paths
444
 * @return string
445
 */
446
function join_paths(?string $basePath, string ...$paths): string
447
{
448
    return Sidekick\join_paths($basePath, ...$paths);
169✔
449
}
450

451
/**
452
 * Ensure the provided `$app` return an instance of Laravel application or throw an exception.
453
 *
454
 * @internal
455
 *
456
 * @param  \Illuminate\Foundation\Application|null  $app
457
 * @param  string|null  $caller
458
 * @return \Illuminate\Foundation\Application
459
 *
460
 * @throws \Orchestra\Testbench\Exceptions\ApplicationNotAvailableException
461
 */
462
function laravel_or_fail($app, ?string $caller = null): Application
463
{
464
    if ($app instanceof Application) {
163✔
465
        return $app;
163✔
466
    }
467

468
    if (\is_null($caller)) {
1✔
469
        $caller = transform(debug_backtrace()[1] ?? null, function ($debug) {
1✔
470
            if (isset($debug['class']) && isset($debug['function'])) {
1✔
471
                return \sprintf('%s::%s', $debug['class'], $debug['function']);
1✔
472
            }
473

UNCOV
474
            return $debug['function'];
×
475
        });
1✔
476
    }
477

478
    throw Exceptions\ApplicationNotAvailableException::make($caller);
1✔
479
}
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

© 2026 Coveralls, Inc