This document describes the CI/CD pipeline architecture for the Wallarm Design System monorepo, implemented using GitHub Actions, Docker, and modern DevOps practices.
- Node.js: v24+
- pnpm: 10.33.2
- Docker: Latest stable version
- GitHub Actions: Ubuntu latest runner
check-pr-title runs in a separate workflow (pr-title.yml), triggered on pull_request. Everything below runs in main.yml, triggered on push to any branch:
flowchart LR
A[Push to any branch] --> C[Setup & Dependencies]
C --> D[Quality Checks]
D --> E[Build]
E --> F[E2E Tests]
F --> R{On main?}
R -->|yes| G[Deploy Storybook]
R -->|yes| S[Release: semantic-release]
D --> D1[Lint]
D --> D2[TypeCheck]
D --> D3[Unit Tests]
F --> F1[Shard 1]
F --> F2[Shard 2]
F --> F3[Shard 3]
F --> F4[unit-test-report / e2e-report]
G --> G1[Storybook static artifact to GitHub Pages]
Validates that PR titles follow conventional commit format. Lives in its own workflow file, pr-title.yml β it is not a job inside main.yml and does not gate or block the jobs below.
Triggers: Pull request creation/update (opened, edited, synchronize, reopened) targeting main
Requirements: Conventional commit format
Tools: thehanimo/pr-title-checker
Manages dependencies and caching for optimal performance.
Key Features:
- Node.js v24 setup
- pnpm v10.33.2 with caching
- Dependency installation with frozen lockfile
- Screenshot update detection
Cache Strategy:
- Cache key:
pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} - Restore keys for fallback
- Turbo cache optimization
Parallel execution of code quality validations.
Parallel Jobs:
- Lint: ESLint validation across all packages
- TypeCheck: TypeScript strict mode checking
- Unit Tests: Vitest test execution with coverage
Performance: ~2-3 minutes total (parallel execution)
Builds all workspace packages and the Storybook static site. No Docker image is built or pushed here β output is uploaded as plain GitHub Actions artifacts (storybook-static, built-packages) for downstream jobs to consume.
Build Steps:
pnpm buildβ builds all packagespnpm --filter=@wallarm-org/design-system build-storybookβ builds the static Storybook site- Uploads both as
actions/upload-artifact
The Dockerfiles under packages/design-system/ and apps/playground/ exist for manual/local builds (see the root README.md's Docker section) and are unrelated to this job.
Sharded testing for optimal performance.
Configuration:
shard: [1, 2, 3]
browser: chromiumTotal Jobs: 3 parallel E2E test shards
Features:
- Runs inside the public
mcr.microsoft.com/playwrightcontainer (not a project-built image) so Playwright's browser binaries are pre-installed - Readiness check: a plain
curlretry loop polls the Storybook static server until it responds β not a GitHub Actionsservices:-based Docker health check - Artifact upload for test results
- Screenshot comparison
Publishes JUnit test results from the quality and e2e jobs as GitHub Actions check annotations (via dorny/test-reporter).
Automated visual regression baseline updates, split across two jobs.
Triggers:
- Push to main branch with
[update-screenshots]in commit message - Manual workflow dispatch
Process:
e2e-update-screenshots(sharded 3-way) runs tests with--update-snapshotscommit-screenshotsmerges the shard outputs, commits updated screenshots, and pushes back to the branch
Production deployment to GitHub Pages.
- Target: GitHub Pages
- URL: https://wallarm.github.io/wallarm-design-system/
- Triggers: Push to main branch
- Process:
- Download the
storybook-staticartifact produced by thebuildjob (no Docker image involved) - Upload to GitHub Pages artifact
- Deploy using
actions/deploy-pages
- Download the
Runs semantic-release for @wallarm-org/design-system and, conditionally, @wallarm-org/mcp β analyzes commits since the last release, publishes to npm with NPM_TOKEN, creates a GitHub release, and (on feature/*/fix/* branches) publishes an RC-tagged prerelease. See RELEASE.md for the full branch strategy.
name: CI/CD Pipeline
on:
push:
branches: ['**']
workflow_dispatch:
env:
NODE_VERSION: '24'
PNPM_VERSION: '10.33.2'main.yml has no pull_request trigger β that belongs to the separate pr-title.yml workflow (see job 1 above).
packages/design-system/Dockerfile and apps/playground/Dockerfile exist for manual/local builds and docker-compose.local.yml β CI does not build, run, or push either image. See the root README.md's Docker section for local usage.
FROM node:24-alpine AS base
# Multi-stage build:
# 1. deps: Install dependencies
# 2. builder: Build Storybook
# 3. production: Serve with nginx- pnpm Store: Cached based on lockfile hash, via both
actions/setup-node's built-incache: 'pnpm'and a separate hand-rollednode_modulescache in each job that installs dependencies β these overlap and are a known consolidation opportunity - Turbo Cache: Incremental build caching
- Browser Binary Cache: Playwright browsers pre-installed in the
mcr.microsoft.com/playwrightcontainer image used bye2e/e2e-update-screenshots
- Quality checks run in parallel (lint, typecheck, test)
- E2E tests use sharding (3 parallel shards)
- Optimized for single service focus
- E2E skip for merge commits to main
[skip-e2e]flag support- Deploy only on main branch
- Docker multi-stage builds
- Minimal production images
- Selective workspace installation
- Frozen lockfile for reproducibility
| Stage | Target | Current |
|---|---|---|
| PR Check | < 30s | β 20s |
| Setup | < 2min | β 1.5min |
| Quality | < 3min | β 2.5min |
| Build | < 5min | β 4min |
| E2E Tests | < 10min | β 8min |
| Total Pipeline | < 15min | β 12min |
- Build Success Rate: > 95%
- Test Flakiness: < 2%
- Cache Hit Rate: > 80%
- Deployment Success: > 99%
Required GitHub Secrets:
GITHUB_TOKEN: Auto-provided by GitHub ActionsNPM_TOKEN: Required by thereleasejob to publish@wallarm-org/design-systemand@wallarm-org/mcpto npm
There is no container registry push in this pipeline, so no registry credential is needed.
No automated security scanning currently runs in CI β no dependency-vulnerability check (e.g. pnpm audit), no CodeQL/SAST, no Docker image scanning, and no secret-detection step are configured in main.yml or pr-title.yml. pnpm audit --prod can be run manually/locally in the meantime. This is a gap worth closing (e.g. a scheduled pnpm audit job or Dependabot), not a currently-implemented feature.
# Clear cache by updating cache key version
CACHE_VERSION: "v2" # Increment this# Run locally with same config
pnpm e2e:docker
# Debug specific browser
pnpm e2e:docker --project=chromium# Build locally to debug
docker build -f packages/design-system/Dockerfile .# View workflow logs
gh run list --limit 5
gh run view <run-id>
# Download artifacts
gh run download <run-id>
# Re-run failed jobs
gh run rerun <run-id> --failed- Pipeline Duration: Track trends over time
- Failure Rate: Identify problematic stages
- Resource Usage: Optimize runner specifications
- Cache Effectiveness: Monitor hit rates
- GitHub Actions Analytics
- Third-party monitoring (Datadog, New Relic)
- Custom dashboards with GitHub API
- Slack/Discord notifications
- Weekly: Review failed builds
- Monthly: Analyze performance metrics
- Quarterly: Optimize pipeline architecture
- Dynamic Test Splitting: Distribute tests based on duration
- Incremental Builds: Build only changed packages
- Smart E2E Selection: Run relevant tests based on changes
- Progressive Deployment: Canary releases for production
- Consolidate caching: Drop the redundant hand-rolled
node_modulescache in favor ofactions/setup-node's built-inpnpmcache alone - Add
timeout-minutes: No job currently has an explicit timeout, so a hung step can run to GitHub's 360-minute default cap
- GitHub Actions Documentation
- Docker Best Practices
- pnpm Workspace Configuration
- Turborepo Documentation
For CI/CD issues:
- Check this documentation
- Review recent workflow runs
- Consult team leads
- Create issue with
ci/cdlabel
Last Updated: 2026-07 Version: 1.1.0