E2E testing moved to Playwright MCP with Shedward Scissorhands in UAT
per GRO-904. The e2e job was blocking the docker job, which blocked the
entire release pipeline.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Even after nginx is listening on port 80, there can be a brief window
where the first Playwright requests hit still-warming router logic or
upstream connection pool setup, causing inconsistent E2E failures.
Now the readiness step:
1. Polls until both http://localhost:8080 and http://localhost:3000/health
return HTTP 200 (up to 60 attempts = 10 min max)
2. Once both are confirmed up, sleeps 30 additional seconds before
proceeding to E2E tests — a settling period for nginx and the Node
server to fully stabilize
Co-Authored-By: Paperclip <noreply@paperclip.ing>
returns immediately after Docker reports
containers started, not after services inside those containers are actually
listening. This causes Playwright to hit nginx before it's ready.
Now:
- Start containers with (no --wait)
- Poll http://localhost:8080 AND http://localhost:3000/health every 10s,
up to 30 attempts (5 minutes total)
- Only proceed to E2E tests once both are reachable
Co-Authored-By: Paperclip <noreply@paperclip.ing>
host.docker.internal is a Docker Desktop feature unavailable on Gitea Actions
ubuntu-latest runners. Linux runners can reach the Docker Compose service
via localhost when using docker compose expose/published ports.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Remove workflow_dispatch.inputs block (GitHub-specific manual trigger args)
- Remove actions/upload-artifact@v4 from e2e job (not available in Gitea Actions)
- Remove actions/upload-artifact@v4 from web-e2e job (not available in Gitea Actions)
tibdex/github-app-token was already removed in prior commits.
- Use git.farh.net registry with REGISTRY_TOKEN instead of ghcr.io/GITHUB_TOKEN
- Migrate all image tags from ghcr.io/groombook/* to git.fars.net/groombook/*
- Replace GHA cache with OCI registry cache (type=registry)
- Replace tibdex/github-app-token with oauth2+REGISTRY_TOKEN for infra clone
- Replace gh pr create/merge with Gitea API curl calls
- Replace actions/github-script@v7 Comment on PR with Gitea issues API curl
- Remove permissions: blocks from deploy-dev and cd jobs (Gitea-native)
- Update deploy-dev kubectl image refs to git.farh.net/groombook/*
Refs: GRO-1344
Ensures Vite sees VITE_API_URL as an empty string (not undefined) during
pnpm build, so the || window.location.origin fallback fires at runtime
instead of baking in the UAT URL.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Update the Update Infra Image Tags job condition to also trigger
on pushes to the dev branch, not just main.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Pin pnpm/action-setup@v4 to version 9.15.4 in all 5 jobs
- Add duplicate PR guard in CD job before gh pr create
- Remove stale kubectl delete job migrate-schema command
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Add ALLOW_RESET env var override to reset.ts safety guard
- Add reset Docker build target to Dockerfile
- Add reset image build step to CI docker job
- Add reset image tag update to CD job dev overlay update
Co-Authored-By: Paperclip <noreply@paperclip.ing>
groombook/infra has no required status checks, so GitHub refuses to
enable auto-merge (PR is immediately in clean status). Replace
--auto --merge with --merge for immediate merge since there are no
checks to wait for.
Fixes: GRO-378
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The //= compound assignment operator is not supported in the version
of yq installed in CI. Replace both usages with the equivalent
(.spec.ttlSecondsAfterFinished // 86400) form.
Fixes GRO-360.
Co-authored-by: groombook-engineer[bot] <3141748+groombook-engineer[bot]@users.noreply.github.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
yq env(SHORT_SHA) on lines 330 and 339 requires SHORT_SHA as an
environment variable, not just a shell variable. Without export, yq
receives an empty value and the Update Infra Image Tags job fails on
every merge to main.
Regression from GRO-311 fix (commit 0d610f5).
Co-authored-by: Barkley Trimsworth <barkley@groombook.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
Implements the automated Playwright E2E suite as the pre-UAT gate following
the UAT failures identified in GRO-299. Creates 5 test files in apps/web/e2e/:
- portal-auth.spec.ts: verifies client portal auth (client name shown, not "Hi, Guest")
- portal-data.spec.ts: verifies portal sections render without auth gates
- admin-services.spec.ts: asserts no duplicate service names in admin/services and booking wizard
- admin-reports.spec.ts: verifies reports page shows non-zero data for last 60 days
- console-health.spec.ts: asserts no 404s for favicon/PWA assets and no JS exceptions
Also adds:
- apps/web/e2e/ with Playwright config targeting groombook.dev.farh.net
- Shared fixtures with storageState-based auth via dev login selector
- test:e2e npm script in apps/web/package.json
- web-e2e CI job targeting PRs (runs after deploy-dev)
Note: Tests 1 & 2 (portal auth/data) depend on GRO-300 being deployed.
Tests 3-5 run against current dev state.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Since Kubernetes Job spec.template is immutable, Flux cannot update a
completed Job with a new image tag. This change ensures the CI workflow
updates both the image newTag AND the Job metadata.name to include the
short SHA (e.g., migrate-schema-026a2c8), making each deploy's Job
unique and allowing Flux to reconcile consecutive deploys without
immutable field errors.
Co-authored-by: Barkley Trimsworth <barkley@groombook.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
Each CI build now produces an immutable tag (pr-N-sha7 or
YYYY.MM.DD-sha7) so that docker/build-push-action cache-from
type=gha cannot cross-contaminate between commits.
Previously the shared pr-N tag caused GHA layer cache to reuse
stale JS bundles from earlier builds of the same PR.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
GitHub App token pushes do not trigger pull_request workflow events,
blocking CI on bot-authored PRs. Add workflow_dispatch to allow manual
CI runs via: gh workflow run ci.yml --ref <branch>
Co-Authored-By: Paperclip <noreply@paperclip.ing>
* feat: add cd job to update groombook/infra image tags on main merge (GRO-178)
- Adds `cd` job that runs after `docker` on main branch pushes only
- Uses tibdex/github-app-token to get infra repo push token
- Updates image tags in apps/groombook/base/{api,web,migrate-job,seed-job}.yaml
- Opens auto-merge PR on groombook/infra
Trade-off: deploy-dev continues using kubectl set image directly for PR
previews (speed over full GitOps auditability for short-lived previews).
Co-Authored-By: Paperclip <noreply@paperclip.ing>
* fix: correct --head branch format and use --enable-auto-merge (GRO-178)
CTO review fixes:
- Remove bogus "groombook-engineer[bot]:" prefix from --head — gh pr
create does not use owner:branch syntax when pushing from a cloned
repo; just the branch name is needed
- Replace invalid --auto-merges-branch=main flag with
--enable-auto-merge (valid gh flag that activates repo auto-merge)
Co-Authored-By: Paperclip <noreply@paperclip.ing>
* fix: broaden annotation sed pattern, fix PR body link, remove error swallowing (GRO-178)
CTO review remaining fixes:
- Annotation sed pattern: broaden [a-f0-9]* to [a-zA-Z0-9-]* since
migrate-job and seed-job use "groXXX" suffixes (e.g. "2026.03.28-gro177")
which contain non-hex letters
- PR body link: fix /d50d9792/issues/GRO-178 → /GRO/issues/GRO-178
- Remove error swallowing: "|| echo" was hiding PR creation failures;
let the step fail naturally so CI catches it
Co-Authored-By: Paperclip <noreply@paperclip.ing>
* fix(cd): split --enable-auto-merge into separate merge command
CTO review fix: gh pr create does not support --enable-auto-merge flag.
Split into two commands: create PR, then gh pr merge with --auto --merge.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
---------
Co-authored-by: groombook-engineer[bot] <3141748+groombook-engineer[bot]@users.noreply.github.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Flea Flicker <flea-flicker@groombook.io>
Co-authored-by: groombook-engineer[bot] <269742240+groombook-engineer[bot]@users.noreply.github.com>
Extend CI to build PR-tagged Docker images and auto-deploy them to
groombook-dev when all checks pass. This unblocks Flea Flicker UAT
validation for open PRs.
Changes:
- Docker build job now runs on PRs (tagged as pr-{number}) and main
- New deploy-dev job uses self-hosted runners with kubectl access
- Runs migration, updates api/web deployments, comments on PR
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The deploy job required INFRA_DEPLOY_TOKEN (a GitHub PAT) stored as a
repo secret, which violates the board directive against storing tokens
in repo secrets. Flux Image Automation will handle image tag updates
in the infra repo instead.
Fixes#72
Co-authored-by: Groom Book CTO <cto@groombook.dev>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Replace raw 40-char git SHA tags with CalVer format (e.g. 2026.03.19-19e0f5e)
for better readability and proper release date versioning. The deploy job now
consumes a version output from the docker job instead of using raw SHA.
Co-authored-by: Groom Book CTO <cto@groombook.dev>
Co-authored-by: Paperclip <noreply@paperclip.ing>
Adds a deploy job that runs after Docker images are pushed to GHCR.
It checks out groombook/infra, updates all image SHA tags in the
Kubernetes manifests, and commits directly to main.
This ensures Flux always picks up new images after a successful build,
preventing the previous issue where :latest tags caused no manifest
diff and pods weren't updated.
Requires INFRA_DEPLOY_TOKEN secret with push access to groombook/infra.
Co-authored-by: Groom Book CTO <cto@groombook.dev>
Co-authored-by: Paperclip <noreply@paperclip.ing>
- New apps/e2e workspace with @playwright/test
- playwright.config.ts targeting Docker Compose stack (http://localhost:8080)
- navigation.spec.ts: smoke tests for all pages
- book.spec.ts: full booking wizard happy-path with API mocking
- clients.spec.ts: client list and detail panel tests
- CI job: spins up docker compose, installs Playwright chromium, runs tests
- Playwright report uploaded as artifact on failure
- README docs for running E2E tests locally
Closes#40
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Add seed stage to API Dockerfile (FROM builder, runs pnpm db:seed)
- Add explicit target: runner to API image build (prevents building wrong stage)
- Add CI steps to push ghcr.io/groombook/migrate and ghcr.io/groombook/seed images
Co-authored-by: Groom Book CEO <ceo@groombook.dev>
Co-authored-by: Paperclip <noreply@paperclip.ing>
Enable image pushing to GitHub Container Registry on main branch
merges. Tags images with both commit SHA and latest.
Co-authored-by: Groom Book CTO <cto@groombook.app>
Co-authored-by: Paperclip <noreply@paperclip.ing>
pnpm-lock.yaml landed with PR #15, so setup-node can cache pnpm deps
again. This speeds up CI by avoiding full re-installs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Paperclip <noreply@paperclip.ing>
setup-node's cache: pnpm requires pnpm-lock.yaml to exist. The lockfile
is coming in PR #15 but isn't on main yet. Remove caching for now —
it'll be re-enabled once the lockfile lands.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
pnpm/action-setup@v4 now errors when both the action's `version` input
and package.json's `packageManager` field specify a version. Remove the
action input — package.json's `pnpm@9.15.4` is authoritative.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All CI runs are stuck in queued — zero self-hosted runners are registered
for the groombook-runners label. Switch to ubuntu-latest to unblock PRs.
Tracked in groombook/infra#2 — will revert once self-hosted runners are
deployed to the cluster.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sets up the initial project structure for groombook/groombook:
- pnpm monorepo with apps/api (Hono + TypeScript), apps/web (React + Vite + PWA), packages/db (Drizzle ORM), packages/types (shared types)
- Core DB schema: clients, pets, services, appointments, staff with CNPG-compatible Postgres
- REST API routes for clients, pets, services, appointments with Zod validation
- OIDC auth middleware for Authentik integration
- React PWA with vite-plugin-pwa, service worker, offline caching, installable manifest
- GitHub Actions CI: lint, typecheck, test, build, Docker image build (groombook-runners)
- Dockerfiles for API (Node.js) and Web (nginx)
- docker-compose.yml for local development
Co-Authored-By: Paperclip <noreply@paperclip.ing>