Skip to content

ci: PR-event-driven deploys with automatic preview cleanup#7

Merged
Lef-F merged 5 commits intomainfrom
ci-pr-previews
Apr 22, 2026
Merged

ci: PR-event-driven deploys with automatic preview cleanup#7
Lef-F merged 5 commits intomainfrom
ci-pr-previews

Conversation

@Lef-F
Copy link
Copy Markdown
Owner

@Lef-F Lef-F commented Apr 22, 2026

What

Rebuild .github/workflows/cicd.yml around the pull-request lifecycle. Preview subdomains are now created when a PR opens, updated on every push, and torn down when the PR closes or merges. Pushes to non-main branches no longer spawn subdomains on their own.

Why

The old workflow had no cleanup path: every push to any branch created (or silently re-created) a {branch}.lef.fyi preview, and nothing ever removed them. Over time this left orphaned S3 buckets and Cloudflare CNAMEs behind. Tying the preview lifecycle to PR events closes that loop and stops new drift.

How

Two jobs, both in the same file, gated by if: on the event type:

  • deploy — runs for push to main or pull_request opened / synchronize / reopened. Creates the bucket if needed, syncs src/, and upserts the CNAME (query → PUT existing or POST new) so repeated runs no longer silently fail on duplicate DNS.
  • cleanup — runs for pull_request closed (merged or not). Empties + deletes the preview bucket and removes the CNAME. Best-effort: both steps check for existence first and skip if already gone.

Other changes:

  • on: push is now restricted to branches: [main]. Pushes to other branches no longer deploy anything by themselves — open a PR if you want a preview.
  • Added a concurrency group deploy-${PR_NUMBER || ref} with cancel-in-progress: false so a deploy and its matching cleanup serialize instead of racing on the same bucket.
  • Fork-PR guard on both jobs (head.repo.full_name == github.repository), since secrets are unavailable to fork PRs anyway.
  • On PR events, checks out the PR head SHA (not the auto-generated merge commit) so the preview reflects exactly what the author pushed.
  • Cloudflare zone name is now resolved dynamically via the zone API instead of requiring a new secret.

Not handled in this PR

Existing orphaned previews from before this change (claude-scaffold, gatsby-init, hugo, this-is-cool, plus ci-pr-previews from this very push) still need a one-time manual cleanup. Going forward, the new workflow will keep the house in order.

Test plan

  • Merge this PR. Watch the Actions tab to confirm the cleanup job fires on the closed event and tears down ci-pr-previews.lef.fyi (if GitHub runs the new workflow from main at close time).
  • Open a new scratch PR with any src/** change to confirm the preview subdomain appears on the opened event.
  • Push another commit to the scratch PR branch to confirm the subdomain updates on synchronize.
  • Close the scratch PR to confirm the preview bucket + CNAME get cleaned up.

@Lef-F Lef-F merged commit 041d2f2 into main Apr 22, 2026
2 checks passed
@Lef-F Lef-F deleted the ci-pr-previews branch April 22, 2026 09:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant