Skip to content

Commit 55f4cf2

Browse files
authored
Merge pull request #1117 from hydephp/add-build-warning-system
Add build warning system
2 parents 3ea5421 + ff094ee commit 55f4cf2

File tree

6 files changed

+363
-2
lines changed

6 files changed

+363
-2
lines changed

packages/framework/src/Console/Commands/BuildSiteCommand.php

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Hyde\Framework\Services\BuildService;
1313
use Hyde\Framework\Services\BuildTaskService;
1414
use Hyde\Hyde;
15+
use Hyde\Support\BuildWarnings;
1516
use Illuminate\Support\Facades\Config;
1617

1718
/**
@@ -54,7 +55,7 @@ public function handle(): int
5455

5556
$this->printFinishMessage($timeStart);
5657

57-
return Command::SUCCESS;
58+
return $this->getExitCode();
5859
}
5960

6061
protected function runPreBuildActions(): void
@@ -103,6 +104,13 @@ public function runPostBuildActions(): void
103104

104105
protected function printFinishMessage(float $timeStart): void
105106
{
107+
if ($this->hasWarnings()) {
108+
$this->newLine();
109+
$this->error('There were some warnings during the build process:');
110+
$this->newLine();
111+
BuildWarnings::writeWarningsToOutput($this->output, $this->output->isVerbose());
112+
}
113+
106114
$executionTime = (microtime(true) - $timeStart);
107115
$this->info(sprintf(
108116
"\nAll done! Finished in %s seconds (%sms) with %sMB peak memory usage",
@@ -148,4 +156,18 @@ protected function canGenerateSearch(): bool
148156
{
149157
return Features::hasDocumentationSearch();
150158
}
159+
160+
protected function hasWarnings(): bool
161+
{
162+
return BuildWarnings::hasWarnings() && BuildWarnings::reportsWarnings();
163+
}
164+
165+
protected function getExitCode(): int
166+
{
167+
if ($this->hasWarnings() && BuildWarnings::reportsWarningsAsExceptions()) {
168+
return self::INVALID;
169+
}
170+
171+
return Command::SUCCESS;
172+
}
151173
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Hyde\Framework\Exceptions;
6+
7+
use RuntimeException;
8+
9+
/**
10+
* @experimental Having a class like this extending an exception means it's easy to throw if enabled, however,
11+
* it's not required for the build warnings feature and may be replaced by a simple array.
12+
*/
13+
class BuildWarning extends RuntimeException
14+
{
15+
//
16+
}

packages/framework/src/Framework/Features/Blogging/Models/FeaturedImage.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Hyde\Framework\Exceptions\FileNotFoundException;
99
use Hyde\Hyde;
1010
use Hyde\Markdown\Contracts\FrontMatter\SubSchemas\FeaturedImageSchema;
11+
use Hyde\Support\BuildWarnings;
1112
use Illuminate\Support\Facades\Http;
1213
use Illuminate\Support\Str;
1314
use Stringable;
@@ -229,7 +230,7 @@ protected function getContentLengthForRemoteImage(): int
229230
return (int) key(array_flip($headers['Content-Length']));
230231
}
231232

232-
// Here we could throw an exception if we want to be strict about this, or add a warning.
233+
BuildWarnings::report('The image "'.$this->getSource().'" has a content length of zero.');
233234

234235
return 0;
235236
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Hyde\Support;
6+
7+
use Hyde\Facades\Config;
8+
use Hyde\Framework\Exceptions\BuildWarning;
9+
use Illuminate\Contracts\Debug\ExceptionHandler;
10+
use Symfony\Component\Console\Style\OutputStyle;
11+
use function app;
12+
use function sprintf;
13+
14+
/**
15+
* @experimental
16+
*
17+
* @see \Hyde\Framework\Testing\Unit\BuildWarningsTest
18+
*/
19+
class BuildWarnings
20+
{
21+
/** @var array<\Hyde\Framework\Exceptions\BuildWarning> */
22+
protected array $warnings = [];
23+
24+
public static function getInstance(): static
25+
{
26+
if (! app()->bound(self::class)) {
27+
app()->singleton(self::class);
28+
}
29+
30+
return app(self::class);
31+
}
32+
33+
public static function report(BuildWarning|string $warning): void
34+
{
35+
static::getInstance()->warnings[] = $warning instanceof BuildWarning ? $warning : new BuildWarning($warning);
36+
}
37+
38+
/** @return array<\Hyde\Framework\Exceptions\BuildWarning> */
39+
public static function getWarnings(): array
40+
{
41+
return static::getInstance()->warnings;
42+
}
43+
44+
public static function hasWarnings(): bool
45+
{
46+
return count(static::getInstance()->warnings) > 0;
47+
}
48+
49+
public static function reportsWarnings(): bool
50+
{
51+
return Config::getBool('hyde.log_warnings', true);
52+
}
53+
54+
public static function reportsWarningsAsExceptions(): bool
55+
{
56+
return Config::getBool('hyde.convert_build_warnings_to_exceptions', false);
57+
}
58+
59+
public static function writeWarningsToOutput(OutputStyle $output, bool $verbose = false): void
60+
{
61+
if (static::reportsWarningsAsExceptions()) {
62+
self::renderWarningsAsExceptions($output);
63+
} else {
64+
self::renderWarnings($output, $verbose);
65+
}
66+
}
67+
68+
protected static function renderWarnings(OutputStyle $output, bool $verbose): void
69+
{
70+
foreach (static::getWarnings() as $number => $warning) {
71+
$output->writeln(sprintf(' %s. <comment>%s</comment>', $number + 1, $warning->getMessage()));
72+
if ($verbose) {
73+
$output->writeln(sprintf(' <fg=gray>%s:%s</>', $warning->getFile(), $warning->getLine()));
74+
}
75+
}
76+
}
77+
78+
protected static function renderWarningsAsExceptions(OutputStyle $output): void
79+
{
80+
foreach (static::getWarnings() as $warning) {
81+
app(ExceptionHandler::class)->renderForConsole($output, $warning);
82+
}
83+
}
84+
}

packages/framework/tests/Feature/StaticSiteServiceTest.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Hyde\Facades\Filesystem;
88
use Hyde\Facades\Site;
99
use Hyde\Hyde;
10+
use Hyde\Support\BuildWarnings;
1011
use Hyde\Testing\TestCase;
1112
use Illuminate\Support\Facades\File;
1213

@@ -245,4 +246,54 @@ public function test_aborts_when_non_standard_directory_is_emptied()
245246
$this->assertFileExists(Hyde::path('foo/keep.html'));
246247
File::deleteDirectory(Hyde::path('foo'));
247248
}
249+
250+
public function test_without_warnings()
251+
{
252+
$this->artisan('build')
253+
->doesntExpectOutput('There were some warnings during the build process:')
254+
->assertExitCode(0);
255+
}
256+
257+
public function test_with_warnings()
258+
{
259+
BuildWarnings::report('This is a warning');
260+
261+
$this->artisan('build')
262+
->expectsOutput('There were some warnings during the build process:')
263+
->expectsOutput(' 1. This is a warning')
264+
->assertExitCode(0);
265+
}
266+
267+
public function test_with_warnings_and_verbose()
268+
{
269+
BuildWarnings::report('This is a warning');
270+
271+
$this->artisan('build --verbose')
272+
->expectsOutput('There were some warnings during the build process:')
273+
->expectsOutput(' 1. This is a warning')
274+
->expectsOutputToContain('BuildWarnings.php')
275+
->assertExitCode(0);
276+
}
277+
278+
public function test_with_warnings_but_warnings_are_disabled()
279+
{
280+
config(['hyde.log_warnings' => false]);
281+
BuildWarnings::report('This is a warning');
282+
283+
$this->artisan('build')
284+
->doesntExpectOutput('There were some warnings during the build process:')
285+
->assertExitCode(0);
286+
}
287+
288+
public function test_with_warnings_converted_to_exceptions()
289+
{
290+
config(['hyde.convert_build_warnings_to_exceptions' => true]);
291+
BuildWarnings::report('This is a warning');
292+
293+
$this->artisan('build')
294+
->expectsOutput('There were some warnings during the build process:')
295+
->expectsOutputToContain('Hyde\Framework\Exceptions\BuildWarning')
296+
->doesntExpectOutput(' 1. This is a warning')
297+
->assertExitCode(2);
298+
}
248299
}

0 commit comments

Comments
 (0)