Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions scripts/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,23 @@ if changed '^(resources/(js|css|data)/|vite\.config\.|package(-lock)?\.json|tsco
FRONTEND_CHANGED=true
fi

# The pattern above classifies a diff. This asks the far simpler question the
# diff is only a proxy for: is what we built older than what we built it from?
#
# The two disagree whenever a release is skipped, and a skipped rebuild does not
# retry itself — the next deploy diffs against the commit that skipped it, sees
# nothing front-end in that range, and leaves the stale bundle in place forever.
# One misclassified path therefore strands the site until somebody runs FORCE=1.
# It happened: data corrections deployed green and never reached the page, and
# the deploy that fixed the classifier could not undo its own backlog.
#
# Comparing artifacts to sources costs one `find` and cannot be fooled by a
# pattern nobody updated.
if [ "$FRONTEND_CHANGED" = false ] && bundles_are_stale; then
echo " the built bundles are older than the sources — rebuilding regardless of the diff"
FRONTEND_CHANGED=true
fi

# Kept apart from PHP_CHANGED below: a Blade edit needs the caches rebuilt and
# the bytecode dropped, but there is nothing new to download for it.
if changed '^composer\.(json|lock)$'; then
Expand Down
34 changes: 34 additions & 0 deletions tests/Feature/DeployScriptTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -290,3 +290,37 @@ function deployMatches(string $flag, string $path): bool
expect(strpos($script, 'no server-rendered <h1>'))
->toBeLessThan(strpos($script, 'serving a different build'));
});

it('rebuilds when the artifacts are older than the sources, whatever the diff says', function (): void {
/*
* The changed-paths pattern classifies a diff. This asks the question the
* diff is only a proxy for: is what we built older than what we built it
* from?
*
* They disagree whenever a release is skipped, and a skipped rebuild does
* not retry itself — the next deploy diffs against the commit that skipped
* it, sees nothing front-end in that range, and leaves the stale bundle in
* place indefinitely. One misclassified path strands the site until someone
* runs FORCE=1 by hand.
*
* That is not hypothetical. `resources/data/*.json` was classified as
* content, so corrected prices deployed green and never reached the page —
* and the deploy that fixed the classifier could not undo its own backlog,
* because by then the data change was behind it.
*/
$script = file_get_contents(base_path('scripts/deploy.sh'));

// The staleness check must be consulted for the front-end decision, not
// only inside the unchanged-commit branch.
expect(substr_count($script, 'bundles_are_stale'))->toBeGreaterThanOrEqual(
3,
'bundles_are_stale should be defined and consulted in both the skip branch and the front-end decision',
);

expect($script)->toMatch('/FRONTEND_CHANGED"?\s*=\s*false.*bundles_are_stale/s');

// And it has to be defined before both uses, or the shell sees an empty command.
$definedAt = strpos($script, 'bundles_are_stale() {');
expect($definedAt)->not->toBeFalse();
expect($definedAt)->toBeLessThan(strrpos($script, 'bundles_are_stale;'));
});
Loading