Deploy main automatically, and stop shipping stale PHP while doing it - #10
Merged
Merged
Conversation
…g it
Adds the missing half of the release process. `main` had no path to the
server: nine merged pull requests sat undeployed until someone ran the
script by hand, and the server was still on the commit before all of them.
.github/workflows/deploy.yml runs after tests go green on main
scripts/deploy.sh does the work, on the server
The workflow is the only one here that holds a secret, which tests.yml
warns against because the repository takes pull requests from forks. It
never runs on `pull_request`, never checks the repository out, and the
key it uses is pinned by `command=` in authorized_keys to the deploy
script alone, so a leaked copy can deploy main and nothing else.
scripts/deploy.sh keeps what the previous version got right — build the
bundles sideways and rename them in, do only the work the diff calls for
— and fixes what it got wrong:
* `resources/views/` was missing from the PHP change test. A Blade
template compiles to a PHP file named after its path, so its name
does not change when its contents do, and this host runs FPM with
opcache.validate_timestamps=0. The first release deployed from this
repository shipped a rewritten root template — the two scheme-aware
theme colours, the two font preloads — that reached no visitor at
all until FPM was reloaded by hand. tests/Feature/DeployScriptTest
now reads the patterns out of the script and checks them.
Note for anyone verifying this: `php -i` reads the CLI ini, which
says On while FPM says 0, and a probe file written and fetched
immediately is never cached at all thanks to file_update_protection.
Both roads lead to the wrong answer.
* Nothing verified a build before it went live. A manifest without an
entry for app.tsx now stops the deploy with the old bundle still in
place, and any failure after the rename puts both old bundles back.
* Nothing checked the result. It now asserts a 200 *and* a
server-rendered <h1>, because SSR falling over still returns 200
with an empty shell.
Also here:
* Hashed assets under /build/ get `immutable` for a year. The origin
sent no Cache-Control at all, so Cloudflare filled the gap with its
four-hour default and every returning visitor revalidated files
whose names change when their contents do. Deliberately not extended
to /images/, which carry no hash.
* Pest 4 -> 5 (PHPUnit 13), TypeScript 6 -> 7, mockery 1.6.13.
TypeScript 7 reports the SSR overload mismatch on the two offending
property lines rather than on the call, so the old @ts-expect-error no
longer covered it. resources/js/ssr.tsx now suppresses the one line that
genuinely cannot type — `render`, which every overload accepting it also
requires `resolve` for, and `resolve` must stay absent because
@inertiajs/vite only injects it into a call that lacks it.
139 passed (1950 assertions) with REQUIRE_SSR=1.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
mainhad no path to the server. Nine merged pull requests sat undeployed untilsomeone ran a script by hand — the server was still on
b4a340f, the commitbefore all of them.
The bug this turned up
Deploying by hand surfaced something worse than the missing automation. This
host runs FPM with
opcache.validate_timestamps=0, and the previousscripts/deploy.shdid not countresources/views/as a PHP change. A Bladetemplate compiles to a PHP file named after its path, so the compiled name does
not change when the contents do — opcache kept serving the previous
compilation.
The result: the redesign's root template never reached a visitor. Live HTML was
still
<meta name="theme-color" content="#FFAA46">with zero font preloads,hours after a deploy that reported success. Fixed on the server, and
tests/Feature/DeployScriptTestnow reads the patterns out of the script andchecks them — both regressions were re-injected and confirmed to fail the suite.
Two things make this easy to get wrong, so they are written down in
docs/deployment.md:php -ireads/etc/php/8.4/cli/php.ini, which saysOn. FPM reads its ownini, which says
0.of
opcache.file_update_protection. A naive probe reports that everythingreloads fine.
What ships
.github/workflows/deploy.ymlmainscripts/deploy.shdocs/deployment.mdThe workflow is the only one here that holds a secret, which
tests.ymlexplicitly warns against because this repository accepts pull requests from
forks. Three things keep it out of their reach: it never runs on
pull_request, it never checks the repository out, and its key is pinned bycommand=inauthorized_keysto the deploy script alone.The script keeps the previous version's good ideas — build both bundles sideways
and rename them in, do only the work the diff calls for — and adds:
app.tsxstops the deploy with the old bundle still serving.
and restarts SSR.
<h1>, becauseSSR falling over still returns 200 with an empty shell.
Also
/build/now carryimmutablefor a year. The originsent no
Cache-Controlat all, so Cloudflare filled the gap with itsfour-hour default and every returning visitor revalidated files whose names
change when their contents do. Not extended to
/images/, which carry nohash and are due to be replaced.
TypeScript 7 moved the SSR overload error off the call and onto the two
offending property lines, so the old
@ts-expect-errorstopped covering it.resources/js/ssr.tsxnow suppresses onlyrender— the one line thatgenuinely cannot type, since every overload that accepts it also requires
resolve, andresolvemust stay absent because@inertiajs/viteonly injectsit into a call that lacks one.
Verification
REQUIRE_SSR=1— 107 before, plus 32 newpint,shellcheckclean