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

avoutic / web-framework / 19924475863

04 Dec 2025 09:42AM UTC coverage: 72.979% (-0.03%) from 73.006%
19924475863

push

github

avoutic
SanityCheckRunner handles multiple simultanous checks better

1 of 2 new or added lines in 1 file covered. (50.0%)

1977 of 2709 relevant lines covered (72.98%)

2.77 hits per line

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

94.12
/src/SanityCheck/SanityCheckRunner.php
1
<?php
2

3
/*
4
 * This file is part of WebFramework.
5
 *
6
 * (c) Avoutic <avoutic@gmail.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11

12
namespace WebFramework\SanityCheck;
13

14
use Carbon\Carbon;
15
use Psr\Container\ContainerInterface as Container;
16
use WebFramework\Diagnostics\Instrumentation;
17
use WebFramework\Exception\SanityCheckException;
18
use WebFramework\Support\StoredValuesService;
19

20
/**
21
 * Class SanityCheckRunner.
22
 *
23
 * Manages and executes sanity checks for the application.
24
 */
25
class SanityCheckRunner
26
{
27
    /** @var array<array{class: string, config: array<mixed>}> */
28
    private array $modules = [];
29
    private bool $forceRun = false;
30
    private bool $verbose = false;
31
    private bool $fixing = false;
32

33
    /**
34
     * SanityCheckRunner constructor.
35
     *
36
     * @param Container            $container           The dependency injection container
37
     * @param Instrumentation      $instrumentation     The instrumentation service
38
     * @param StoredValuesService  $storedValuesService The stored values service
39
     * @param array<string, mixed> $buildInfo           Information about the current build
40
     */
41
    public function __construct(
×
42
        private Container $container,
43
        private Instrumentation $instrumentation,
44
        private StoredValuesService $storedValuesService,
45
        private array $buildInfo,
46
    ) {}
×
47

48
    /**
49
     * Add a sanity check module to the runner.
50
     *
51
     * @param string       $moduleClass  The class name of the sanity check module
52
     * @param array<mixed> $moduleConfig Configuration for the module
53
     */
54
    public function add(string $moduleClass, array $moduleConfig): void
7✔
55
    {
56
        $this->modules[] = [
7✔
57
            'class' => $moduleClass,
7✔
58
            'config' => $moduleConfig,
7✔
59
        ];
7✔
60
    }
61

62
    /**
63
     * Execute all registered sanity checks.
64
     *
65
     * @return bool True if all checks pass, false otherwise
66
     *
67
     * @throws \RuntimeException If a sanity check fails
68
     */
69
    public function execute(): bool
8✔
70
    {
71
        if (!count($this->modules))
8✔
72
        {
73
            return true;
1✔
74
        }
75

76
        $commit = $this->buildInfo['commit'];
7✔
77

78
        $needsRun = $this->needsRun($commit);
7✔
79
        if (!$needsRun)
7✔
80
        {
81
            return true;
1✔
82
        }
83

84
        foreach ($this->modules as $info)
6✔
85
        {
86
            $module = $this->container->get($info['class']);
6✔
87
            if (!($module instanceof SanityCheckModule))
6✔
88
            {
89
                throw new \RuntimeException("Class '{$info['class']}' in not a SanityCheckModule");
1✔
90
            }
91

92
            $module->setConfig($info['config']);
5✔
93

94
            if ($this->fixing)
5✔
95
            {
96
                $module->allowFixing();
1✔
97
            }
98

99
            if ($this->verbose)
5✔
100
            {
101
                $module->setVerbose();
1✔
102
            }
103

104
            $span = $this->instrumentation->startSpan('sanity_check.'.$info['class']);
5✔
105
            $result = $module->performChecks();
5✔
106
            $this->instrumentation->finishSpan($span);
5✔
107

108
            if ($result === false)
5✔
109
            {
110
                throw new SanityCheckException('Sanity check failed');
1✔
111
            }
112
        }
113

114
        $this->registerRun($commit);
4✔
115

116
        return true;
4✔
117
    }
118

119
    /**
120
     * Determine if sanity checks need to be run.
121
     *
122
     * @param null|string $commit The current commit hash
123
     *
124
     * @return bool True if checks should be run, false otherwise
125
     */
126
    public function needsRun(?string $commit): bool
12✔
127
    {
128
        if ($this->forceRun)
12✔
129
        {
130
            return true;
1✔
131
        }
132

133
        if ($commit == null)
11✔
134
        {
135
            // We are in live / development code.
136
            // Prevent flooding. Only start check once per
137
            // five seconds.
138
            //
139
            $lastTimestamp = Carbon::createFromTimestamp((int) $this->storedValuesService->getValue('sanity_check.last_check', '0'));
2✔
140

141
            if ($lastTimestamp->diffInSeconds(Carbon::now()) < 5)
2✔
142
            {
143
                return false;
1✔
144
            }
145

146
            $this->storedValuesService->setValue('sanity_check.last_check', (string) Carbon::now()->timestamp);
1✔
147

148
            return true;
1✔
149
        }
150

151
        // We are in an image
152
        // Only check if this commit was not yet successfully checked
153
        //
154
        $checked = $this->storedValuesService->getValue('sanity_check.checked_'.$commit, '0');
9✔
155

156
        return ($checked === '0');
9✔
157
    }
158

159
    /**
160
     * Register a successful run of sanity checks.
161
     *
162
     * @param null|string $commit The current commit hash
163
     */
164
    private function registerRun(?string $commit): void
4✔
165
    {
166
        // Register successful check of this commit
167
        //
168
        if ($commit !== null)
4✔
169
        {
170
            try
171
            {
172
                $this->storedValuesService->setValue('sanity_check.checked_'.$commit, '1');
4✔
173
            }
NEW
174
            catch (\Throwable)
×
175
            {
176
                // Ignore race conditions
177
            }
178
        }
179
    }
180

181
    /**
182
     * Force the sanity checks to run regardless of other conditions.
183
     */
184
    public function forceRun(): void
1✔
185
    {
186
        $this->forceRun = true;
1✔
187
    }
188

189
    /**
190
     * Allow fixing of issues during sanity checks.
191
     */
192
    public function allowFixing(): void
1✔
193
    {
194
        $this->fixing = true;
1✔
195
    }
196

197
    /**
198
     * Enable verbose output during sanity checks.
199
     */
200
    public function setVerbose(): void
1✔
201
    {
202
        $this->verbose = true;
1✔
203
    }
204
}
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