Add reusable deploy file for new projects - #52
Conversation
0c73367 to
d547ab9
Compare
There was a problem hiding this comment.
Pull request overview
Adds a new reusable GitHub Actions workflow intended to deploy a WordPress site to Kinsta over SSH (with Tailscale), including build steps and post-deploy smoke checks. This lives in the central .github repo so other projects can call it via workflow_call.
Changes:
- Introduces a reusable
deploy-wp.ymlworkflow that installs dependencies, builds the theme, and rsyncs a release to a remote host. - Adds remote release management (uploads/.env symlinks, promote release, rollback on failure, cleanup old releases).
- Adds optional smoke testing (with/without basic auth) and WP language pack installation/purging.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds a guarded step that runs `wp core install` only when the site isn't installed yet, so brand-new sites don't fail at the language install step. No-op for every already-installed site using this reusable workflow. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This reverts commit a6e1d97.
Replaces the wp core install bootstrap with a lighter guard: check wp core is-installed once, then skip language pack install, cache purge, and plugin/theme language install when it isn't. Avoids storing WP admin credentials, and is a no-op for every site that's already live. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…l sites Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Add --skip-plugins --skip-themes to every wp-cli invocation so deploy steps don't fail on plugin/theme fatals during bootstrap. Symlink ~/deploy/shared/wordfence-waf.php into each release so the Wordfence WAF bootstrap persists across deploys (touch guards against a dangling symlink on first deploy). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wordfence doesn't support symlinks.
e4fdaca to
6781961
Compare
… quoting - rm the release's wp-content/uploads before ln -sfn: a symlink cannot replace a real directory (e.g. a committed uploads/.gitkeep) - Skip the rollback relink when there is no previous release (first deploy) but still remove the failed release directory - Quote WP_LANG in remote wp-cli commands - Rename the Wordfence step (it copies now) and skip when the shared file does not exist yet (brand-new sites) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Update: rebased, review addressed, OPcache purge addedRebased onto
(An earlier commit sharing Copilot review verdicts (inline replies on each thread): accepted the uploads-symlink guard, first-deploy rollback guard,
Per-site follow-ups (not this PR): each hybrid project needs the itineris-opcache-purge mu-plugin + the 🤖 Generated with Claude Code |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.
Suppressed comments (3)
.github/workflows/deploy-wp.yml:191
- On a first Kinsta deployment,
~/publicis a real web-root directory.ln -sfn TARGET ~/publicdoes not replace that directory; it creates a link inside it, so the web root is never promoted. Remove only an empty non-symlink directory first (and fail safely when migration is required) before creating the release symlink.
run: ssh ${{ inputs.SSH_USER }}@${{ inputs.SSH_HOST }} -p ${{ vars.SSH_PORT }} 'ln -sfn ~/deploy/releases/${{ github.sha }} ~/public'
.github/workflows/deploy-wp.yml:222
- This failure handler is evaluated before the cache purge, plugin/theme language installation, and cleanup steps. A failure in any of those later steps therefore leaves the new release promoted (and potentially partially modified) while the workflow reports failure. Place the rollback handler after all fallible post-promotion steps, or explicitly make non-critical post-deployment tasks non-failing.
- name: Rollback deployment on failure
if: failure()
.github/workflows/deploy-wp.yml:196
- The secret is interpolated directly into shell syntax, so a valid basic-auth password containing a double quote, backtick, or command-substitution characters can break or alter this test. Pass the secret through the step environment and test the environment variable instead.
if [ -n "${{ secrets.BASIC_AUTH_PASSWORD }}" ]; then
Atomic deploys leave OPcache saturated with stale release paths, forcing PHP to recompile every script until entries expire. After promoting the new release, request the site with the X-Opcache-Purge token so the itineris-opcache-purge mu-plugin resets OPcache. Fail-safe: warns but never fails the deploy; skips silently when the org secret is absent. Sends basic auth when the site is protected, mirroring the smoke tests. Same architecture as trellis-deploy.yml: the raw token is compared server-side against the committed SHA-256 fingerprint, so it never lives on the server. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Keying release directories on github.sha alone reuses the directory when the same commit is redeployed (workflow_dispatch or a re-run). If that release is currently live, rsync mutates production in place - and on a failed re-run the rollback step relinks ~/public to that same directory and then deletes it, taking the site down. RELEASE_ID = sha + run_id + run_attempt is unique per attempt, so a redeploy always builds alongside the live release and rollback always has a distinct directory to remove. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
6981720 to
96a4861
Compare
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
No description provided.