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

orchestral / sidekick / 19785211315

29 Nov 2025 02:32PM UTC coverage: 91.5% (-0.3%) from 91.848%
19785211315

Pull #57

github

web-flow
Merge 4694c3244 into a3d28f601
Pull Request #57: Add `Orchestra\Sidekick\package_version_compare()` function

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

183 of 200 relevant lines covered (91.5%)

6.09 hits per line

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

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

3
namespace Orchestra\Sidekick;
4

5
use Closure;
6
use Composer\InstalledVersions;
7
use Composer\Semver\VersionParser;
8
use Illuminate\Foundation\Application;
9
use Illuminate\Support\Arr;
10
use PHPUnit\Runner\Version;
11
use RuntimeException;
12

13
if (! \function_exists('Orchestra\Sidekick\join_paths')) {
14
    /**
15
     * Join the given paths together.
16
     *
17
     * @api
18
     */
19
    function join_paths(?string $basePath, string ...$paths): string
20
    {
21
        foreach ($paths as $index => $path) {
18✔
22
            if (empty($path) && $path !== '0') {
18✔
23
                unset($paths[$index]);
18✔
24
            } else {
25
                $paths[$index] = DIRECTORY_SEPARATOR.ltrim($path, DIRECTORY_SEPARATOR);
18✔
26
            }
27
        }
28

29
        return $basePath.implode('', $paths);
18✔
30
    }
31
}
32

33
if (! \function_exists('Orchestra\Sidekick\once')) {
34
    /**
35
     * Run callback only once.
36
     *
37
     * @api
38
     *
39
     * @param  mixed  $callback
40
     * @return \Closure():mixed
41
     */
42
    function once($callback): Closure
43
    {
44
        $response = new UndefinedValue;
22✔
45

46
        return function () use ($callback, &$response) {
22✔
47
            if ($response instanceof UndefinedValue) {
22✔
48
                $response = value($callback) ?? null;
22✔
49
            }
50

51
            return $response;
22✔
52
        };
22✔
53
    }
54
}
55

56
if (! \function_exists('Orchestra\Sidekick\is_safe_callable')) {
57
    /**
58
     * Determine if the value is a callable and not a string matching an available function name.
59
     *
60
     * @api
61
     */
62
    function is_safe_callable(mixed $value): bool
63
    {
64
        if ($value instanceof Closure) {
6✔
65
            return true;
1✔
66
        }
67

68
        if (! \is_callable($value)) {
5✔
69
            return false;
2✔
70
        }
71

72
        if (\is_array($value)) {
3✔
73
            $isList = \function_exists('array_is_list')
1✔
74
                ? array_is_list($value)
1✔
75
                : ! Arr::isAssoc($value);
×
76

77
            return \count($value) === 2 && $isList && method_exists(...$value);
1✔
78
        }
79

80
        return ! \is_string($value);
2✔
81
    }
82
}
83

84
if (! \function_exists('Orchestra\Sidekick\is_symlink')) {
85
    /**
86
     * Determine if the path is a symlink for both Unix and Windows environments.
87
     *
88
     * @api
89
     */
90
    function is_symlink(string $path): bool
91
    {
92
        if (windows_os() && is_dir($path) && readlink($path) !== $path) {
1✔
93
            return true;
×
94
        } elseif (is_link($path)) {
1✔
95
            return true;
×
96
        }
97

98
        return false;
1✔
99
    }
100
}
101

102
if (! \function_exists('Orchestra\Sidekick\is_testbench_cli')) {
103
    /**
104
     * Determine if command executed via Testbench CLI.
105
     *
106
     * @api
107
     */
108
    function is_testbench_cli(?bool $dusk = null): bool
109
    {
110
        $usingTestbench = \defined('TESTBENCH_CORE');
1✔
111
        $usingTestbenchDusk = \defined('TESTBENCH_DUSK');
1✔
112

113
        return match ($dusk) {
1✔
114
            false => $usingTestbench === true && $usingTestbenchDusk === false,
×
115
            true => $usingTestbench === true && $usingTestbenchDusk === true,
1✔
116
            default => $usingTestbench === true,
1✔
117
        };
1✔
118
    }
119
}
120

121
if (! \function_exists('Orchestra\Sidekick\transform_relative_path')) {
122
    /**
123
     * Transform relative path.
124
     *
125
     * @api
126
     */
127
    function transform_relative_path(string $path, string $workingPath): string
128
    {
129
        return str_starts_with($path, './')
1✔
130
            ? rtrim($workingPath, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.mb_substr($path, 2)
1✔
131
            : $path;
1✔
132
    }
133
}
134

135
if (! \function_exists('Orchestra\Sidekick\working_path')) {
136
    /**
137
     * Get the working path.
138
     *
139
     * @api
140
     *
141
     * @no-named-arguments
142
     *
143
     * @param  array<int, string|null>|string  ...$path
144
     */
145
    function working_path(array|string $path = ''): string
146
    {
147
        return is_testbench_cli() && \function_exists('Orchestra\Testbench\package_path')
1✔
148
            ? \Orchestra\Testbench\package_path($path)
×
149
            : base_path(join_paths(...Arr::wrap(\func_num_args() > 1 ? \func_get_args() : $path)));
1✔
150
    }
151
}
152

153
if (! \function_exists('Orchestra\Sidekick\laravel_normalize_version')) {
154
    /**
155
     * Laravel normalize version.
156
     *
157
     * @api
158
     *
159
     * @throws \RuntimeException
160
     */
161
    function laravel_normalize_version(): string
162
    {
163
        if (! class_exists(Application::class)) {
18✔
NEW
164
            throw new RuntimeException('Unable to verify Laravel Framework version');
×
165
        }
166

167
        return transform(
18✔
168
            Application::VERSION,
18✔
169
            fn (string $version) => match ($version) {
18✔
170
                '13.x-dev' => '13.0.0',
18✔
171
                default => $version,
18✔
172
            }
173
        );
18✔
174
    }
175
}
176

177
if (! \function_exists('Orchestra\Sidekick\phpunit_normalize_version')) {
178
    /**
179
     * PHPUnit normalize version.
180
     *
181
     * @api
182
     *
183
     * @throws \RuntimeException
184
     */
185
    function phpunit_normalize_version(): string
186
    {
187
        if (! class_exists(Version::class)) {
1✔
NEW
188
            throw new RuntimeException('Unable to verify PHPUnit version');
×
189
        }
190

191
        return transform(
1✔
192
            Version::id(),
1✔
193
            fn (string $version) => match (true) {
1✔
194
                str_starts_with($version, '12.4-') => '12.4.0',
1✔
195
                default => $version,
1✔
196
            }
197
        );
1✔
198
    }
199
}
200

201
if (! \function_exists('Orchestra\Sidekick\laravel_version_compare')) {
202
    /**
203
     * Laravel version compare.
204
     *
205
     * @api
206
     *
207
     * @template TOperator of string|null
208
     *
209
     * @phpstan-param  TOperator  $operator
210
     *
211
     * @phpstan-return (TOperator is null ? int : bool)
212
     *
213
     * @throws \RuntimeException
214
     *
215
     * @codeCoverageIgnore
216
     */
217
    function laravel_version_compare(string $version, ?string $operator = null): int|bool
218
    {
219
        if (! class_exists(Application::class)) {
220
            throw new RuntimeException('Unable to verify Laravel Framework version');
221
        }
222

223
        $versionParser = new VersionParser;
224

225
        $laravel = $versionParser->normalize(laravel_normalize_version());
226
        $version = $versionParser->normalize($version);
227

228
        if (\is_null($operator)) {
229
            return version_compare($laravel, $version);
230
        }
231

232
        return version_compare($laravel, $version, $operator);
233
    }
234
}
235

236
if (! \function_exists('Orchestra\Sidekick\package_version_compare')) {
237
    /**
238
     * Package version compare.
239
     *
240
     * @api
241
     *
242
     * @template TOperator of string|null
243
     *
244
     * @phpstan-param  TOperator  $operator
245
     *
246
     * @phpstan-return (TOperator is null ? int : bool)
247
     *
248
     * @throws \RuntimeException
249
     *
250
     * @codeCoverageIgnore
251
     */
252
    function package_version_compare(string $package, string $version, ?string $operator = null): int|bool
253
    {
254
        $versionParser = new VersionParser;
255

256
        $package = $versionParser->normalize(InstalledVersions::getPrettyVersion($package));
257
        $version = $versionParser->normalize($version);
258

259
        if (\is_null($operator)) {
260
            return version_compare($package, $version);
261
        } elseif ($operator === '=') {
262

263
        }
264

265
        return version_compare($package, $version, $operator);
266
    }
267
}
268

269
if (! \function_exists('Orchestra\Sidekick\phpunit_version_compare')) {
270
    /**
271
     * PHPUnit version compare.
272
     *
273
     * @api
274
     *
275
     * @template TOperator of string|null
276
     *
277
     * @phpstan-param  TOperator  $operator
278
     *
279
     * @phpstan-return (TOperator is null ? int : bool)
280
     *
281
     * @throws \RuntimeException
282
     *
283
     * @codeCoverageIgnore
284
     */
285
    function phpunit_version_compare(string $version, ?string $operator = null): int|bool
286
    {
287
        if (! class_exists(Version::class)) {
288
            throw new RuntimeException('Unable to verify PHPUnit version');
289
        }
290

291
        $versionParser = new VersionParser;
292

293
        $phpunit = $versionParser->normalize(phpunit_normalize_version());
294
        $version = $versionParser->normalize($version);
295

296
        if (\is_null($operator)) {
297
            return version_compare($phpunit, $version);
298
        }
299

300
        return version_compare($phpunit, $version, $operator);
301
    }
302
}
303

304
if (! \function_exists('Orchestra\Sidekick\php_binary')) {
305
    /**
306
     * Determine the PHP Binary.
307
     *
308
     * @api
309
     *
310
     * @codeCoverageIgnore
311
     */
312
    function php_binary(): string
313
    {
314
        return (new PhpExecutableFinder)->find(false) ?: 'php';
315
    }
316
}
317

318
if (! \function_exists('Orchestra\Sidekick\windows_os')) {
319
    /**
320
     * Determine whether the current environment is Windows-based.
321
     *
322
     * @api
323
     *
324
     * @codeCoverageIgnore
325
     */
326
    function windows_os(): bool
327
    {
328
        return PHP_OS_FAMILY === 'Windows';
329
    }
330
}
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