Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
62 / 62
100.00% covered (success)
100.00%
8 / 8
CRAP
100.00% covered (success)
100.00%
1 / 1
BuildSiteCommand
100.00% covered (success)
100.00%
62 / 62
100.00% covered (success)
100.00%
8 / 8
17
100.00% covered (success)
100.00%
1 / 1
 handle
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
1
 configureBuildTaskService
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 runPreBuildActions
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
3
 runPostBuildActions
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
4
 printFinishMessage
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
2
 runNodeCommand
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 hasWarnings
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 getExitCode
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3declare(strict_types=1);
4
5namespace Hyde\Console\Commands;
6
7use Hyde\Hyde;
8use Hyde\Facades\Config;
9use Hyde\Support\BuildWarnings;
10use Hyde\Console\Concerns\Command;
11use Hyde\Framework\Services\BuildService;
12use Hyde\Framework\Services\BuildTaskService;
13use Illuminate\Support\Facades\Process;
14
15use function memory_get_peak_usage;
16use function number_format;
17use function array_search;
18use function microtime;
19use function sprintf;
20use function app;
21
22/**
23 * Run the static site build process.
24 */
25class BuildSiteCommand extends Command
26{
27    /** @var string */
28    protected $signature = 'build
29        {--run-dev : Run the NPM dev script after build}
30        {--run-prod : Run the NPM prod script after build}
31        {--run-prettier : Format the output using NPM Prettier}
32        {--pretty-urls : Should links in output use pretty URLs?}
33        {--no-api : Disable API calls, for example, Torchlight}';
34
35    /** @var string */
36    protected $description = 'Build the static site';
37
38    protected BuildService $service;
39    protected BuildTaskService $taskService;
40
41    public function handle(): int
42    {
43        $timeStart = microtime(true);
44
45        $this->title('Building your static site!');
46
47        $this->service = new BuildService($this->output);
48
49        $this->configureBuildTaskService();
50
51        $this->runPreBuildActions();
52
53        $this->service->transferMediaAssets();
54
55        $this->service->compileStaticPages();
56
57        $this->runPostBuildActions();
58
59        $this->printFinishMessage($timeStart);
60
61        return $this->getExitCode();
62    }
63
64    protected function configureBuildTaskService(): void
65    {
66        /** @var BuildTaskService $taskService */
67        $taskService = app(BuildTaskService::class);
68
69        $this->taskService = $taskService;
70        $this->taskService->setOutput($this->output);
71    }
72
73    protected function runPreBuildActions(): void
74    {
75        if ($this->option('no-api')) {
76            $this->info('Disabling external API calls');
77            $this->newLine();
78            /** @var array<string, string> $config */
79            $config = Config::getArray('hyde.features', []);
80            unset($config[array_search('torchlight', $config)]);
81            Config::set(['hyde.features' => $config]);
82        }
83
84        if ($this->option('pretty-urls')) {
85            $this->info('Generating site with pretty URLs');
86            $this->newLine();
87            Config::set(['hyde.pretty_urls' => true]);
88        }
89
90        $this->taskService->runPreBuildTasks();
91    }
92
93    public function runPostBuildActions(): void
94    {
95        $this->taskService->runPostBuildTasks();
96
97        if ($this->option('run-prettier')) {
98            $this->runNodeCommand(
99                'npx prettier '.Hyde::pathToRelative(Hyde::sitePath()).'/**/*.html --write --bracket-same-line',
100                'Prettifying code!',
101                'prettify code'
102            );
103        }
104
105        if ($this->option('run-dev')) {
106            $this->runNodeCommand('npm run dev', 'Building frontend assets for development!');
107        }
108
109        if ($this->option('run-prod')) {
110            $this->runNodeCommand('npm run prod', 'Building frontend assets for production!');
111        }
112    }
113
114    protected function printFinishMessage(float $timeStart): void
115    {
116        if ($this->hasWarnings()) {
117            $this->newLine();
118            $this->error('There were some warnings during the build process:');
119            $this->newLine();
120            BuildWarnings::writeWarningsToOutput($this->output, $this->output->isVerbose());
121        }
122
123        $executionTime = (microtime(true) - $timeStart);
124        $this->info(sprintf(
125            "\nAll done! Finished in %s seconds (%sms) with %sMB peak memory usage",
126            number_format($executionTime, 2),
127            number_format($executionTime * 1000, 2),
128            number_format(memory_get_peak_usage() / 1024 / 1024, 2)
129        ));
130
131        $this->info('Congratulations! ðŸŽ‰ Your static site has been built!');
132        $this->line(
133            'Your new homepage is stored here -> '.
134            static::fileLink(Hyde::sitePath('index.html'))
135        );
136    }
137
138    protected function runNodeCommand(string $command, string $message, ?string $actionMessage = null): void
139    {
140        $this->info($message.' This may take a second.');
141
142        $output = Process::command($command)->run();
143
144        $this->line($output->output() ?? sprintf(
145            '<fg=red>Could not %s! Is NPM installed?</>',
146            $actionMessage ?? 'run script'
147        ));
148    }
149
150    protected function hasWarnings(): bool
151    {
152        return BuildWarnings::hasWarnings() && BuildWarnings::reportsWarnings();
153    }
154
155    protected function getExitCode(): int
156    {
157        if ($this->hasWarnings() && BuildWarnings::reportsWarningsAsExceptions()) {
158            return Command::INVALID;
159        }
160
161        return Command::SUCCESS;
162    }
163}