A GitHub Action That Checks Your Own Deploy After It Ships

post-merge-prod-check.yml runs a small Playwright script against the real fishing.nissaar.com URL after every push to main — because a green CI build says nothing about whether the deploy actually worked.

A GitHub Action That Checks Your Own Deploy After It Ships

The E2E workflow that runs on every push and PR tests a fresh build spun up inside CI — its own Postgres service container, its own backend, its own frontend served on localhost:3000. It can pass with 165/165 green and the actual production deploy at fishing.nissaar.com can still be down, because CI's "it works" and production's "it deployed" are two different claims that nothing was checking together. post-merge-prod-check.yml closes that gap by running after the merge, against the real domain, once the deploy has actually landed.

A workflow that checks its own deploy
A workflow that checks its own deploy

HTML report artifact uploaded even on failure — you get evidence, not just a red X.

The trigger is the deploy signal, not a schedule

on:
  push:
    branches: [main]
  workflow_dispatch:

There's no polling, no separate deploy webhook — the assumption baked into this workflow is that a push to main is the deploy trigger (a self-hosted or manually-pulled server watching that branch), so checking right after the push lands is checking right after the deploy should have happened. workflow_dispatch is there for the case where you want to re-verify production without pushing anything — after restarting a container manually, say.

It's the same tool as the E2E suite, pointed somewhere real

- name: Install deps
  run: npm install [email protected] axios

- name: Install Playwright Browsers
  run: npx playwright install chromium

- name: Run checks
  env:
    BASE_URL: https://fishing.nissaar.com
  run: node .github/scripts/prod-check.js

Rather than building a separate uptime-monitoring integration, this reuses Playwright — already a project dependency for E2E testing — with a hand-rolled script instead of the full test suite. prod-check.js isn't running 165 specs against production (that would create real accounts, real trip logs, and real load against the WeatherAPI quota on every single merge); it's a small, deliberately narrow smoke test: does the landing page render, does /health respond, can the login page be reached, is there a JS console error on first load. The line between "E2E suite" and "prod health check" is not the tooling, it's the scope.

Reports get uploaded even when it fails

- name: Upload HTML report (artifact)
  if: always()
  uses: actions/upload-artifact@v4
  with:
    name: prod-check-report
    path: .github/scripts/prod-check-report.html

if: always() is the detail that makes this workflow actually useful at 2 AM. A prod check that only uploads its report on success tells you nothing new when it fails — you already know it failed from the red X. Getting the HTML report artifact attached to the failed run means the next morning's debugging starts with "here's a screenshot of what the landing page actually looked like," not "let me SSH in and try to reproduce whatever went wrong six hours ago."

What it deliberately doesn't do

There's no automatic rollback wired to a failure here, and no paging/alerting integration — a failed run is a red X on the Actions tab and nothing more. For a project with one maintainer, that's a reasonable line to draw: the signal exists, it's checked whenever someone happens to look, and building an alerting pipeline on top of it would be solving a problem ("I might not notice for hours") that a solo maintainer checking Actions after every merge mostly doesn't have yet.

Series: Fishing Tracker Pro. Next: the E2E suite this workflow borrows its tooling from — Playwright across Chrome, Firefox, and Mobile Chrome.