Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
88.89% covered (warning)
88.89%
16 / 18
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
VersionService
88.89% covered (warning)
88.89%
16 / 18
75.00% covered (warning)
75.00%
3 / 4
10.14
0.00% covered (danger)
0.00%
0 / 1
 resolve
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 fromFile
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
4
 fromGit
66.67% covered (warning)
66.67%
4 / 6
0.00% covered (danger)
0.00%
0 / 1
3.33
 exec
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3namespace App\Services;
4
5class VersionService
6{
7    /**
8     * Resolve the application version string.
9     *
10     * Priority:
11     *  1. .version file (baked into Docker image at build time)
12     *  2. git describe / git rev-parse (local / Sail dev)
13     *  3. "dev" fallback
14     */
15    public function resolve(): string
16    {
17        return $this->fromFile() ?? $this->fromGit() ?? 'dev';
18    }
19
20    private function fromFile(): ?string
21    {
22        $path = base_path('.version');
23
24        if (! file_exists($path)) {
25            return null;
26        }
27
28        $content = trim(file_get_contents($path));
29
30        if ($content === '') {
31            return null;
32        }
33
34        // Full SHA from Docker build — show short form
35        if (preg_match('/^[0-9a-f]{40}$/', $content)) {
36            return substr($content, 0, 7);
37        }
38
39        return $content;
40    }
41
42    private function fromGit(): ?string
43    {
44        if (! is_dir(base_path('.git'))) {
45            return null;
46        }
47
48        // Try git describe first (picks up tags like v1.0.0)
49        $describe = $this->exec('git describe --tags --always 2>/dev/null');
50        if ($describe !== null) {
51            return $describe;
52        }
53
54        // Fallback to short SHA
55        return $this->exec('git rev-parse --short HEAD 2>/dev/null');
56    }
57
58    private function exec(string $command): ?string
59    {
60        $result = trim((string) shell_exec("cd " . escapeshellarg(base_path()) . " && $command"));
61
62        return $result !== '' ? $result : null;
63    }
64}