Skip to content

Commit 7c221fd

Browse files
committed
- Fix for check timestamp, normalize timestamp comparison
1 parent b9a06df commit 7c221fd

2 files changed

Lines changed: 106 additions & 4 deletions

File tree

‎src/Commands/GenerateDocsCommand.php‎

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public function handle(): int
5858
$content = $generator->generate($groups, $title);
5959

6060
if ($this->option('check')) {
61-
return $this->runCheck($content, $resolvedOutput);
61+
return $this->runCheck($content, $resolvedOutput, $format);
6262
}
6363

6464
$this->writeOutput($content, $resolvedOutput);
@@ -115,7 +115,9 @@ private function gatherCommands(): array
115115
continue;
116116
}
117117

118-
// Only-custom filter (overrides vendor filter)
118+
// Only-custom filter: restricts output to application-defined commands only
119+
// (matched against app_command_paths). Runs independently of the vendor
120+
// filter; application commands are never vendor commands.
119121
if ($onlyCustom && ! $this->inspector->isApplicationCommand($command, $appPaths)) {
120122
continue;
121123
}
@@ -213,8 +215,13 @@ private function writeOutput(string $content, string $absolutePath): void
213215
/**
214216
* Compare generated content against the existing file on disk.
215217
* Exits with code 1 when the file is missing or differs.
218+
*
219+
* Timestamps embedded by the generators (Markdown blockquote, JSON
220+
* "generated_at" field, HTML meta line) are stripped from both strings
221+
* before comparison so that --check does not fail solely because the
222+
* documentation was generated at an earlier point in time.
216223
*/
217-
private function runCheck(string $content, string $absolutePath): int
224+
private function runCheck(string $content, string $absolutePath, string $format): int
218225
{
219226
if (! File::exists($absolutePath)) {
220227
$this->error("❌ Check failed: documentation file does not exist at [{$absolutePath}].");
@@ -225,7 +232,10 @@ private function runCheck(string $content, string $absolutePath): int
225232

226233
$existing = File::get($absolutePath);
227234

228-
if (trim($existing) === trim($content)) {
235+
$normalizedExisting = $this->normalizeForCheck(trim($existing), $format);
236+
$normalizedContent = $this->normalizeForCheck(trim($content), $format);
237+
238+
if ($normalizedExisting === $normalizedContent) {
229239
$this->info('✅ Documentation is up-to-date.');
230240

231241
return self::SUCCESS;
@@ -236,4 +246,26 @@ private function runCheck(string $content, string $absolutePath): int
236246

237247
return self::FAILURE;
238248
}
249+
250+
/**
251+
* Strip format-specific timestamp markers from generated content before
252+
* performing an equality check.
253+
*
254+
* Each generator embeds a live timestamp that changes on every run:
255+
* – Markdown : the "Auto-generated on …" blockquote line
256+
* – JSON : the "generated_at" top-level property
257+
* – HTML : the "Generated …" suffix inside the <p class="meta"> element
258+
*
259+
* Removing these markers allows --check to compare only the structural
260+
* content (commands, arguments, options, groups) and pass even when the
261+
* documentation file was generated at an earlier time.
262+
*/
263+
private function normalizeForCheck(string $content, string $format): string
264+
{
265+
return match (strtolower($format)) {
266+
'json' => (string) preg_replace('/"generated_at"\s*:\s*"[^"]*",?\n?/', '', $content),
267+
'html' => (string) preg_replace('/ &mdash; Generated [^<]+/', '', $content),
268+
default => (string) preg_replace('/^> Auto-generated on .+$/m', '', $content),
269+
};
270+
}
239271
}

‎tests/Feature/GenerateDocsCommandTest.php‎

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use CodeInstinct\ArtisanDocs\Tests\TestCase;
66
use Illuminate\Console\Command;
77
use Illuminate\Contracts\Console\Kernel;
8+
use Illuminate\Support\Carbon;
89
use Illuminate\Support\Facades\File;
910
use Mockery;
1011
use PHPUnit\Framework\Attributes\Test;
@@ -27,6 +28,9 @@ protected function setUp(): void
2728

2829
protected function tearDown(): void
2930
{
31+
// Reset any frozen Carbon time set by individual tests.
32+
Carbon::setTestNow();
33+
3034
if (File::exists(base_path($this->outputPath))) {
3135
File::delete(base_path($this->outputPath));
3236
}
@@ -333,4 +337,70 @@ public function it_accepts_a_nested_relative_path_without_traversal(): void
333337

334338
File::delete(base_path($nested));
335339
}
340+
341+
// -------------------------------------------------------------------------
342+
// --check: timestamp normalisation tests
343+
// -------------------------------------------------------------------------
344+
345+
#[Test]
346+
public function it_check_passes_for_markdown_when_only_the_timestamp_has_changed(): void
347+
{
348+
// Generate the markdown file at time T.
349+
Carbon::setTestNow(Carbon::parse('2025-01-01 00:00:00'));
350+
$this->artisan('docs:commands', ['--output' => $this->outputPath]);
351+
352+
// Advance to T + 1 day – the "Auto-generated on …" line will differ,
353+
// but the structural content is identical.
354+
Carbon::setTestNow(Carbon::parse('2025-01-02 00:00:00'));
355+
$this->artisan('docs:commands', [
356+
'--output' => $this->outputPath,
357+
'--check' => true,
358+
])->assertExitCode(0);
359+
}
360+
361+
#[Test]
362+
public function it_check_passes_for_json_when_only_the_timestamp_has_changed(): void
363+
{
364+
$jsonPath = str_replace('.md', '.json', $this->outputPath);
365+
366+
// Generate the JSON file at time T.
367+
Carbon::setTestNow(Carbon::parse('2025-01-01 00:00:00'));
368+
$this->artisan('docs:commands', [
369+
'--format' => 'json',
370+
'--output' => $jsonPath,
371+
]);
372+
373+
// Advance time – only "generated_at" will differ.
374+
Carbon::setTestNow(Carbon::parse('2025-01-02 00:00:00'));
375+
$this->artisan('docs:commands', [
376+
'--format' => 'json',
377+
'--output' => $jsonPath,
378+
'--check' => true,
379+
])->assertExitCode(0);
380+
381+
File::delete(base_path($jsonPath));
382+
}
383+
384+
#[Test]
385+
public function it_check_passes_for_html_when_only_the_timestamp_has_changed(): void
386+
{
387+
$htmlPath = str_replace('.md', '.html', $this->outputPath);
388+
389+
// Generate the HTML file at time T.
390+
Carbon::setTestNow(Carbon::parse('2025-01-01 00:00:00'));
391+
$this->artisan('docs:commands', [
392+
'--format' => 'html',
393+
'--output' => $htmlPath,
394+
]);
395+
396+
// Advance time – only the "Generated …" meta suffix will differ.
397+
Carbon::setTestNow(Carbon::parse('2025-01-02 00:00:00'));
398+
$this->artisan('docs:commands', [
399+
'--format' => 'html',
400+
'--output' => $htmlPath,
401+
'--check' => true,
402+
])->assertExitCode(0);
403+
404+
File::delete(base_path($htmlPath));
405+
}
336406
}

0 commit comments

Comments
 (0)