Skip to content

fix(ci): separate CI and CD into distinct pipelines#26

Merged
nsheaps merged 5 commits intomainfrom
claude/fix-ci-release-loop-IU11y
Mar 11, 2026
Merged

fix(ci): separate CI and CD into distinct pipelines#26
nsheaps merged 5 commits intomainfrom
claude/fix-ci-release-loop-IU11y

Conversation

@nsheaps
Copy link
Copy Markdown
Owner

@nsheaps nsheaps commented Mar 9, 2026

Summary

Fixes the infinite CI loop on main (release→screenshots→release→..., up to v0.1.31) by restructuring into clean, separated CI and CD pipelines with reusable workflows.

CI (ci.yml) — push to main + PRs

├── _lint.yml           (lint + typecheck)
├── _test-unit.yml      (unit tests)
├── _test-integration.yml (integration tests)
├── _test-e2e.yml       (e2e tests)          ← all parallel
├── _build.yml          (after lint + unit)
└── _update-screenshots.yml (pixel-level comparison)
        │
        ▼
  _tag-release.yml (after ALL above, push to main only)
    ├── commit screenshots locally (only if pixels changed)
    ├── release-it: bump + CHANGELOG + commit [skip ci] + tag + push
    └── or: push screenshot commit [skip ci] only (if no bump needed)

CD (cd.yml) — triggered by create event on v* tags

├── create GitHub release (from CHANGELOG.md)
├── deploy web → GitHub Pages
├── build macOS / Windows / Linux     ← all parallel
├── build iOS / Android
        │
        ▼
  upload-release-assets (after all builds + release)

Why there's no loop

  • Release commit includes [skip ci] → GitHub skips CI entirely
  • CD uses on: create event (not on: push: tags) which is not affected by [skip ci]
  • Screenshot commits include [skip ci] → no re-trigger
  • No should-run gate needed — [skip ci] handles it natively

Key changes

File Change
ci.yml Slim orchestrator (~40 lines) calling reusable workflows
_lint.yml Reusable: lint + typecheck
_test-unit.yml Reusable: unit tests
_test-integration.yml Reusable: integration tests
_test-e2e.yml Reusable: e2e tests
_build.yml Reusable: production build
_update-screenshots.yml Reusable: capture + pixel-level compare (ImageMagick)
_tag-release.yml Reusable: commit screenshots + release-it (no GitHub release)
cd.yml New: consolidated CD (was release-web/desktop/mobile.yml)
.release-it.json github.release: false, commit message adds [skip ci]
release.yml Simplified to manual bump+tag+push (CD handles the rest)
auto-release.yml Deleted (merged into CI tag-release)
update-screenshots.yml Deleted (merged into CI screenshots)
release-web.yml Deleted (merged into CD)
release-desktop.yml Deleted (merged into CD)
release-mobile.yml Deleted (merged into CD)

Screenshot metadata fix

Screenshots compared pixel-by-pixel with ImageMagick compare -metric AE. If 0 pixels differ (metadata-only change), the original file is restored — no commit generated.

Test plan

  • Push a feat: commit to main → CI runs all jobs in parallel → tags release → CD deploys
  • Verify [skip ci] in release commit prevents CI re-trigger
  • Verify on: create tag event triggers CD despite [skip ci]
  • Verify screenshot metadata-only changes don't produce commits
  • Verify PR pushes run CI but skip tag-release
  • Verify manual release workflow still works (workflow_dispatch)
  • Verify reusable workflows are correctly called from CI orchestrator

https://claude.ai/code/session_01S7y4A9bjckeJui8aGW3Xeq

The auto-release and update-screenshots workflows were triggering each
other in a loop: screenshot commit → release → screenshot → release...

Fix by making each workflow skip the other's commits:
- auto-release now skips docs(screenshots): commits
- update-screenshots now skips chore: release commits

https://claude.ai/code/session_01S7y4A9bjckeJui8aGW3Xeq
@nsheaps nsheaps self-assigned this Mar 9, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 9, 2026

Release Version Check

🟢 PATCH version bump

Version
Current 0.1.31
Next 0.1.32

This version will be released automatically when this PR is merged to main.

Changelog preview

0.1.32 (2026-03-11)

Bug Fixes

  • ci: break release/screenshot infinite loop (54a1340)
  • ci: consolidate CI/screenshots/release into single pipeline (3074bb0)
  • ci: separate CI and CD into distinct pipelines (0485051)

Refactoring

  • ci: extract reusable workflows, use [skip ci] for releases (d34cfd1)

github-actions Bot added a commit that referenced this pull request Mar 9, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 9, 2026

Preview Deployment

The web app for this PR has been deployed:

Open Preview

Use this to verify the app works correctly, especially for dependency updates.

Eliminates the infinite release loop by merging three separate workflows
(ci.yml, update-screenshots.yml, auto-release.yml) into a single pipeline.

Key changes:
- Screenshots run in parallel with other CI jobs, not as a separate workflow
- Pixel-level comparison (ImageMagick) prevents metadata-only diffs from
  triggering commits — only actual visual changes are committed
- Release job depends on ALL CI + screenshot jobs passing first
- No duplicate validation: release job reuses CI results instead of
  re-running `bun run validate`
- Screenshot commit + release commit are pushed together in a single push
- Automated commits (releases, screenshot updates) skip the entire pipeline
  via a `should-run` gate job

https://claude.ai/code/session_01S7y4A9bjckeJui8aGW3Xeq
@nsheaps nsheaps changed the title fix(ci): break release/screenshot infinite loop fix(ci): consolidate CI/screenshots/release into single pipeline Mar 9, 2026
github-actions Bot added a commit that referenced this pull request Mar 9, 2026
@nsheaps nsheaps marked this pull request as ready for review March 10, 2026 02:07
Restructure the CI/CD pipeline to eliminate the infinite release loop:

CI (ci.yml) — push to main + PRs:
  - lint, test, build, screenshots run in parallel
  - Pixel-level screenshot comparison (ImageMagick) prevents metadata-only commits
  - tag-release job depends on all CI passing, commits screenshots + version
    bump + tag, pushes once
  - should-run gate skips pipeline for automated commits

CD (cd.yml) — triggered by v* tag push:
  - Creates GitHub release from CHANGELOG.md
  - Deploys web app to GitHub Pages
  - Builds desktop (macOS/Windows/Linux) and mobile (iOS/Android) in parallel
  - Uploads all build artifacts to the GitHub release

Other changes:
  - .release-it.json: github.release set to false (CD creates releases now)
  - release.yml: simplified to manual bump+tag+push (CD handles the rest)
  - Deleted release-web.yml, release-desktop.yml, release-mobile.yml
    (consolidated into cd.yml)

https://claude.ai/code/session_01S7y4A9bjckeJui8aGW3Xeq
@nsheaps nsheaps changed the title fix(ci): consolidate CI/screenshots/release into single pipeline fix(ci): separate CI and CD into distinct pipelines Mar 10, 2026
github-actions Bot added a commit that referenced this pull request Mar 10, 2026
Comment thread .github/workflows/ci.yml Outdated
Comment thread .github/workflows/ci.yml Outdated
Comment thread .github/workflows/ci.yml
Comment thread .github/workflows/ci.yml Outdated
Comment thread .github/workflows/ci.yml Outdated
claude and others added 2 commits March 10, 2026 18:07
Address PR review feedback:

1. Remove should-run gate — use [skip ci] in release and screenshot
   commit messages instead
2. Extract every CI job into a reusable workflow (_lint.yml, _test-unit.yml,
   _test-integration.yml, _test-e2e.yml, _build.yml, _update-screenshots.yml,
   _tag-release.yml) for readability
3. CI orchestrator (ci.yml) is now ~40 lines calling reusable workflows
4. Remove --project='Desktop Chrome' hardcode — run all CI-configured
   Playwright projects for screenshots
5. CD triggers on 'create' event (not 'push: tags') since [skip ci]
   in the release commit would suppress push-triggered workflows
6. Screenshot commits only happen when pixels actually change (pixel
   comparison was already in place, removed the unnecessary commit
   message skip condition)

https://claude.ai/code/session_01S7y4A9bjckeJui8aGW3Xeq
github-actions Bot added a commit that referenced this pull request Mar 11, 2026
@nsheaps nsheaps merged commit 9aba34a into main Mar 11, 2026
10 checks passed
@nsheaps nsheaps deleted the claude/fix-ci-release-loop-IU11y branch March 11, 2026 01:09
github-actions Bot added a commit that referenced this pull request Mar 11, 2026
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.

2 participants