Automate preview environment for new PRs #5945
Conversation
Preview image ready (ephemeral)Built from 16cef60 and pushed to ttl.sh — expires after 1h: cd docker && OB_IMAGE=ttl.sh/openboxes-preview-pr-5945-16cef60:1h docker compose upThen open http://localhost:8080/openboxes No login required (ttl.sh is anonymous). Each run publishes a fresh image and the previous one expires on its own. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #5945 +/- ##
=============================================
+ Coverage 9.93% 10.57% +0.63%
- Complexity 1395 1615 +220
=============================================
Files 745 808 +63
Lines 46466 47595 +1129
Branches 11045 11248 +203
=============================================
+ Hits 4617 5031 +414
- Misses 41114 41752 +638
- Partials 735 812 +77 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Preview environment deployedURL: https://pr-5945.preview.openboxes.com/openboxes Per-PR preview on the VPS, routed through Traefik with HTTPS. Tears down when this PR closes. First boot runs Liquibase migrations, so give it a minute (and the TLS cert a few seconds to issue). |
Build the per-PR image (ttl.sh, anonymous + auto-expiring) and deploy it to a VPS over SSH behind a Traefik reverse proxy with per-host HTTPS via Let's Encrypt. Each PR runs as an isolated docker-compose project (pr-<n>) routed at pr-<n>.<base-domain>/openboxes; teardown happens on PR close, and old preview images are pruned after each deploy. Opt-in policy: claude/* branches get a preview automatically; any other PR can opt in via the "preview" label; workflow_dispatch builds the image only. The render/deploy/teardown jobs for Uffizzi are kept but disabled (Uffizzi Cloud shut down in 2024) for possible Uffizzi Enterprise/self-hosted use. https://claude.ai/code/session_01Jb6WBAcSZoXkmo23uesbCZ
c2665c8 to
62f3b02
Compare
|
@ewaterman @awalkowiak I don't know when I'm going to get back to this, but just wanted you guys to see the Draft PR. If/when it gets merged (I'll start with the VVG branch), we should use this sparingly because I don't have the resources on the current VPS to handle more than a few instances at a time without causing OOM errors. NOT URGENT |
There was a problem hiding this comment.
Pull request overview
Automates per-PR preview environments by building an ephemeral Docker image for a PR and deploying it to a VPS behind a long-running Traefik reverse proxy (with HTTPS), plus retaining a disabled Uffizzi-based preview path for reference.
Changes:
- Adds a new GitHub Actions workflow to build/push a ttl.sh “preview image” and deploy/teardown a per-PR stack on a VPS, commenting the preview URL on the PR.
- Adds VPS-side deployment helper script and new Docker Compose definitions for Traefik + per-PR preview stacks.
- Updates the base compose image interpolation to allow overriding the image via an environment variable.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
docker/preview-deploy.sh |
New VPS-side script to (idempotently) start Traefik, enforce a concurrency cap, and deploy a per-PR compose stack. |
docker/docker-compose.preview.yml |
New per-PR compose stack (app + MariaDB) with Traefik labels and external network wiring. |
docker/docker-compose.traefik.yml |
New long-running Traefik compose definition to route preview hosts and obtain ACME certs. |
docker/docker-compose.uffizzi.yml |
New (disabled path) Uffizzi compose template for legacy/self-hosted Uffizzi usage. |
docker/docker-compose-base.yml |
Updates base app image interpolation to support an OB_IMAGE override. |
.github/workflows/preview-image.yml |
New workflow to build/push ttl.sh preview images and deploy/teardown previews on a VPS via SSH. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| services: | ||
| app: | ||
| image: ${OB_IMAGE_REPOSITORY-ghcr.io/}openboxes/openboxes:${OB_VERSION:-latest} | ||
| image: ${OB_IMAGE:-${OB_IMAGE_REPOSITORY-ghcr.io/}openboxes/openboxes:${OB_VERSION:-latest}} |
| else | ||
| slug="branch-${REF_NAME//\//-}" | ||
| fi | ||
| echo "image=ttl.sh/openboxes-preview-${slug}-${SHA::7}:${PREVIEW_TTL}" >> "$GITHUB_OUTPUT" |
| if: >- | ||
| github.event.action != 'closed' && | ||
| ( github.event_name == 'workflow_dispatch' || | ||
| startsWith(github.head_ref, 'claude/') || | ||
| contains(github.event.pull_request.labels.*.name, 'preview') ) |
| if: >- | ||
| github.event_name == 'pull_request' && github.event.action != 'closed' && | ||
| ( startsWith(github.head_ref, 'claude/') || | ||
| contains(github.event.pull_request.labels.*.name, 'preview') ) |
| if: >- | ||
| github.event_name == 'pull_request' && github.event.action == 'closed' && | ||
| ( startsWith(github.head_ref, 'claude/') || | ||
| contains(github.event.pull_request.labels.*.name, 'preview') ) |
| install -m 700 -d ~/.ssh | ||
| printf '%s\n' "$SSH_KEY" > ~/.ssh/deploy_key | ||
| chmod 600 ~/.ssh/deploy_key | ||
| ssh-keyscan -H "$SSH_HOST" >> ~/.ssh/known_hosts 2>/dev/null |
| ssh -i ~/.ssh/deploy_key "$SSH_USER@$SSH_HOST" \ | ||
| "docker compose -p '$project' -f ~/openboxes-preview/docker-compose.preview.yml down --remove-orphans || true" |
Adds automated per-PR preview environments for OpenBoxes. When a PR opts in (
previewlabel,claudeprefix in branch name), GHA builds the branch image, stores it in a temporary repo (ttl.sh), ship it to a VPS (rimuhosting for now), and Traefik exposes it at a per-PR HTTPS URL. The preview is torn down when the PR closes. GitHubNote: I used ghcr.io for the first few runs of this GHA (those images can be purged), but realized we probably want to use a temporary image repo which is when I discovered ttl.sh.
Here's the first preview environment I created via this GHA
https://pr-5945.preview.openboxes.com/openboxes/auth/login
The main idea behind this is that sometimes we need to quickly preview PRs before they get merged to develop and CI/CD'd to the dev environments. While it works, I hate the process we currently adopt of manually pushing branches to obdev5 or whatever. In addition, I needed a way to auto-deploy PRs while using Claude Code locally or via a web Claude Code session. I'm struggling to find time to sit in front of an IDE, so this was the next best thing.
Future Enhancements