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

orchestral / sidekick / 20916681366

12 Jan 2026 10:51AM UTC coverage: 91.781% (+0.2%) from 91.549%
20916681366

push

github

crynobone
Merge branch '1.1.x' into 1.2.x

7 of 8 new or added lines in 1 file covered. (87.5%)

201 of 219 relevant lines covered (91.78%)

6.36 hits per line

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

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

3
namespace Orchestra\Sidekick;
4

5
use BackedEnum;
6
use Closure;
7
use Composer\InstalledVersions;
8
use Composer\Semver\VersionParser;
9
use Illuminate\Contracts\Foundation\Application as ApplicationContract;
10
use Illuminate\Foundation\Application;
11
use Illuminate\Support\Arr;
12
use OutOfBoundsException;
13
use PHPUnit\Runner\Version;
14
use RuntimeException;
15
use UnitEnum;
16

17
if (! \function_exists('Orchestra\Sidekick\enum_name')) {
18
    /**
19
     * Get the proper name from enum.
20
     *
21
     * @api
22
     *
23
     * @throws \RuntimeException
24
     */
25
    function enum_name(BackedEnum|UnitEnum $enum): string
26
    {
27
        return mb_convert_case(str_replace('_', ' ', $enum->name), MB_CASE_TITLE, 'UTF-8');
5✔
28
    }
29
}
30

31
if (! \function_exists('Orchestra\Sidekick\enum_value')) {
32
    /**
33
     * Get the proper name from enum.
34
     *
35
     * @api
36
     *
37
     * @template TValue
38
     * @template TDefault
39
     *
40
     * @param  TValue  $value
41
     * @param  TDefault|callable(TValue): TDefault  $default
42
     * @return ($value is empty ? TDefault : mixed)
43
     *
44
     * @throws \RuntimeException
45
     */
46
    function enum_value(mixed $value, mixed $default = null): mixed
47
    {
48
        return match (true) {
49
            $value instanceof BackedEnum => $value->value,
20✔
50
            $value instanceof UnitEnum => $value->name,
16✔
51

52
            default => $value ?? value($default),
20✔
53
        };
54
    }
55
}
56

57
if (! \function_exists('Orchestra\Sidekick\after_resolving')) {
58
    /**
59
     * Register after resolving callback.
60
     *
61
     * @api
62
     *
63
     * @template TLaravel of \Illuminate\Contracts\Foundation\Application
64
     *
65
     * @param  TLaravel  $app
66
     * @param  class-string|string  $name
67
     * @param  (\Closure(object, TLaravel):(mixed))|null  $callback
68
     */
69
    function after_resolving(ApplicationContract $app, string $name, ?Closure $callback = null): void
70
    {
71
        $app->afterResolving($name, $callback);
2✔
72

73
        if ($app->resolved($name)) {
2✔
74
            value($callback, $app->make($name), $app);
1✔
75
        }
76
    }
77
}
78

79
if (! \function_exists('Orchestra\Sidekick\join_paths')) {
80

81
    /**
82
     * Join the given paths together.
83
     *
84
     * @api
85
     *
86
     * @deprecated
87
     */
88
    function join_paths(?string $basePath, string ...$paths): string
89
    {
90
        return Filesystem\join_paths($basePath, ...$paths);
20✔
91
    }
92
}
93

94
if (! \function_exists('Orchestra\Sidekick\once')) {
95
    /**
96
     * Run callback only once.
97
     *
98
     * @api
99
     *
100
     * @param  mixed  $callback
101
     * @return \Closure():mixed
102
     */
103
    function once($callback): Closure
104
    {
105
        $response = new UndefinedValue;
24✔
106

107
        return function () use ($callback, &$response) {
24✔
108
            if ($response instanceof UndefinedValue) {
24✔
109
                $response = value($callback) ?? null;
24✔
110
            }
111

112
            return $response;
24✔
113
        };
24✔
114
    }
115
}
116

117
if (! \function_exists('Orchestra\Sidekick\is_safe_callable')) {
118
    /**
119
     * Determine if the value is a callable and not a string matching an available function name.
120
     *
121
     * @api
122
     */
123
    function is_safe_callable(mixed $value): bool
124
    {
125
        if ($value instanceof Closure) {
6✔
126
            return true;
1✔
127
        }
128

129
        if (! \is_callable($value)) {
5✔
130
            return false;
2✔
131
        }
132

133
        if (\is_array($value)) {
3✔
134
            return \count($value) === 2 && array_is_list($value) && method_exists(...$value);
1✔
135
        }
136

137
        return ! \is_string($value);
2✔
138
    }
139
}
140

141
if (! \function_exists('Orchestra\Sidekick\is_symlink')) {
142
    /**
143
     * Determine if the path is a symlink for both Unix and Windows environments.
144
     *
145
     * @api
146
     *
147
     * @deprecated
148
     */
149
    function is_symlink(string $path): bool
150
    {
151
        return Filesystem\is_symlink($path);
×
152
    }
153
}
154

155
if (! \function_exists('Orchestra\Sidekick\is_testbench_cli')) {
156
    /**
157
     * Determine if command executed via Testbench CLI.
158
     *
159
     * @api
160
     */
161
    function is_testbench_cli(?bool $dusk = null): bool
162
    {
163
        $usingTestbench = \defined('TESTBENCH_CORE');
1✔
164
        $usingTestbenchDusk = \defined('TESTBENCH_DUSK');
1✔
165

166
        return match ($dusk) {
1✔
167
            false => $usingTestbench === true && $usingTestbenchDusk === false,
×
168
            true => $usingTestbench === true && $usingTestbenchDusk === true,
1✔
169
            default => $usingTestbench === true,
1✔
170
        };
1✔
171
    }
172
}
173

174
if (! \function_exists('Orchestra\Sidekick\transform_relative_path')) {
175
    /**
176
     * Transform relative path.
177
     *
178
     * @api
179
     */
180
    function transform_relative_path(string $path, string $workingPath): string
181
    {
182
        return str_starts_with($path, './')
1✔
183
            ? rtrim($workingPath, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.mb_substr($path, 2)
1✔
184
            : $path;
1✔
185
    }
186
}
187

188
if (! \function_exists('Orchestra\Sidekick\package_path')) {
189
    /**
190
     * Get the package path.
191
     *
192
     * @api
193
     *
194
     * @no-named-arguments
195
     *
196
     * @param  array<int, string|null>|string  ...$path
197
     */
198
    function package_path(array|string $path = ''): string
199
    {
200
        $packagePath = once(fn () => match (true) {
2✔
201
            \defined('TESTBENCH_WORKING_PATH') => TESTBENCH_WORKING_PATH,
2✔
202
            \is_string(getenv('TESTBENCH_WORKING_PATH')) => getenv('TESTBENCH_WORKING_PATH'),
2✔
203
            default => realpath(InstalledVersions::getRootPackage()['install_path']),
2✔
204
        });
2✔
205

206
        return join_paths($packagePath(), ...Arr::wrap(\func_num_args() > 1 ? \func_get_args() : $path));
2✔
207
    }
208
}
209

210
if (! \function_exists('Orchestra\Sidekick\working_path')) {
211
    /**
212
     * Get the working path.
213
     *
214
     * @api
215
     *
216
     * @no-named-arguments
217
     *
218
     * @param  array<int, string|null>|string  ...$path
219
     */
220
    function working_path(array|string $path = ''): string
221
    {
222
        return is_testbench_cli()
1✔
NEW
223
            ? package_path($path)
×
224
            : base_path(join_paths(...Arr::wrap(\func_num_args() > 1 ? \func_get_args() : $path)));
1✔
225
    }
226
}
227

228
if (! \function_exists('Orchestra\Sidekick\laravel_normalize_version')) {
229
    /**
230
     * Laravel normalize version.
231
     *
232
     * @api
233
     *
234
     * @throws \OutOfBoundsException
235
     */
236
    function laravel_normalize_version(): string
237
    {
238
        if (! class_exists(Application::class)) {
20✔
239
            throw new OutOfBoundsException('Unable to verify "laravel/framework" version');
×
240
        }
241

242
        /** @var string $version */
243
        $version = transform(
20✔
244
            Application::VERSION,
20✔
245
            fn (string $version) => match ($version) {
20✔
246
                '13.x-dev' => '13.0.0',
20✔
247
                default => $version,
20✔
248
            }
249
        );
20✔
250

251
        return (new VersionParser)->normalize($version);
20✔
252
    }
253
}
254

255
if (! \function_exists('Orchestra\Sidekick\phpunit_normalize_version')) {
256
    /**
257
     * PHPUnit normalize version.
258
     *
259
     * @api
260
     *
261
     * @throws \OutOfBoundsException
262
     */
263
    function phpunit_normalize_version(): string
264
    {
265
        if (! class_exists(Version::class)) {
1✔
266
            throw new OutOfBoundsException('Unable to verify "phpunit/phpunit" version');
×
267
        }
268

269
        /** @var string $version */
270
        $version = transform(
1✔
271
            Version::id(),
1✔
272
            fn (string $version) => match (true) {
1✔
273
                str_starts_with($version, '13.0-') => '13.0.0',
1✔
274
                default => $version,
1✔
275
            }
276
        );
1✔
277

278
        return (new VersionParser)->normalize($version);
1✔
279
    }
280
}
281

282
if (! \function_exists('Orchestra\Sidekick\laravel_version_compare')) {
283
    /**
284
     * Laravel version compare.
285
     *
286
     * @api
287
     *
288
     * @template TOperator of string|null
289
     *
290
     * @param  TOperator  $operator
291
     * @return (TOperator is null ? int : bool)
292
     *
293
     * @throws \RuntimeException
294
     *
295
     * @codeCoverageIgnore
296
     */
297
    function laravel_version_compare(string $version, ?string $operator = null): int|bool
298
    {
299
        if (! class_exists(Application::class)) {
300
            return package_version_compare('laravel/framework', $version, $operator);
301
        }
302

303
        $laravel = laravel_normalize_version();
304
        $version = (new VersionParser)->normalize($version);
305

306
        if (\is_null($operator)) {
307
            return version_compare($laravel, $version);
308
        }
309

310
        return version_compare($laravel, $version, $operator);
311
    }
312
}
313

314
if (! \function_exists('Orchestra\Sidekick\package_version_compare')) {
315
    /**
316
     * Package version compare.
317
     *
318
     * @api
319
     *
320
     * @template TOperator of string|null
321
     *
322
     * @phpstan-param  TOperator  $operator
323
     *
324
     * @phpstan-return (TOperator is null ? int : bool)
325
     *
326
     * @throws \OutOfBoundsException
327
     * @throws \RuntimeException
328
     *
329
     * @codeCoverageIgnore
330
     */
331
    function package_version_compare(string $package, string $version, ?string $operator = null): int|bool
332
    {
333
        $prettyVersion = InstalledVersions::getPrettyVersion($package);
334

335
        if (\is_null($prettyVersion)) {
336
            throw new RuntimeException(\sprintf('Unable to compare "%s" version', $package));
337
        }
338

339
        $versionParser = new VersionParser;
340

341
        $package = $versionParser->normalize($prettyVersion);
342
        $version = $versionParser->normalize($version);
343

344
        if (\is_null($operator)) {
345
            return version_compare($package, $version);
346
        }
347

348
        return version_compare($package, $version, $operator);
349
    }
350
}
351

352
if (! \function_exists('Orchestra\Sidekick\phpunit_version_compare')) {
353
    /**
354
     * PHPUnit version compare.
355
     *
356
     * @api
357
     *
358
     * @template TOperator of string|null
359
     *
360
     * @param  TOperator  $operator
361
     * @return (TOperator is null ? int : bool)
362
     *
363
     * @throws \OutOfBoundsException
364
     * @throws \RuntimeException
365
     *
366
     * @codeCoverageIgnore
367
     */
368
    function phpunit_version_compare(string $version, ?string $operator = null): int|bool
369
    {
370
        if (! class_exists(Version::class)) {
371
            return package_version_compare('phpunit/phpunit', $version, $operator);
372
        }
373

374
        $phpunit = phpunit_normalize_version();
375
        $version = (new VersionParser)->normalize($version);
376

377
        if (\is_null($operator)) {
378
            return version_compare($phpunit, $version);
379
        }
380

381
        return version_compare($phpunit, $version, $operator);
382
    }
383
}
384

385
if (! \function_exists('Orchestra\Sidekick\php_binary')) {
386
    /**
387
     * Determine the PHP Binary.
388
     *
389
     * @api
390
     *
391
     * @codeCoverageIgnore
392
     */
393
    function php_binary(): string
394
    {
395
        return (new PhpExecutableFinder)->find(false) ?: 'php';
396
    }
397
}
398

399
if (! \function_exists('Orchestra\Sidekick\windows_os')) {
400
    /**
401
     * Determine whether the current environment is Windows-based.
402
     *
403
     * @api
404
     *
405
     * @codeCoverageIgnore
406
     */
407
    function windows_os(): bool
408
    {
409
        return PHP_OS_FAMILY === 'Windows';
410
    }
411
}
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