| title | CI/CD Pipeline |
|---|---|
| description | Overview of the ObjectUI continuous integration and deployment workflows. |
ObjectUI uses 11 GitHub Actions workflows to automate testing, quality checks, security scanning, releases, and repository maintenance. All workflow files live in .github/workflows/.
┌─────────────────────────────────────────────────────────────────┐
│ Push / PR to main/develop │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────────┐ │
│ │ ci.yml │ │ performance- │ │
│ │ (test, │ │ budget.yml │ │
│ │ lint, │ │ (bundle size)│ │
│ │ build) │ │ │ │
│ └──────────┘ └──────────────┘ │
│ │
│ ┌──────────────┐ │
│ │ labeler.yml │ │
│ │ │ │
│ └──────────────┘ │
│ │
├─────────────────────────────────────────────────────────────────┤
│ Push to main │
│ ┌───────────────────┐ │
│ │ changeset-release │ → npm publish via changesets │
│ │ .yml │ │
│ └───────────────────┘ │
│ │
├─────────────────────────────────────────────────────────────────┤
│ Tag push (v*) │
│ ┌──────────┐ ┌───────────────┐ │
│ │ release │ │ changelog.yml │ │
│ │ .yml │ │ (git-cliff) │ │
│ └──────────┘ └───────────────┘ │
│ │
├─────────────────────────────────────────────────────────────────┤
│ Scheduled │
│ ┌──────────┐ ┌───────────────────┐ ┌──────────────────┐ │
│ │ stale │ │ shadcn-check.yml │ │ dependabot- │ │
│ │ .yml │ │ (weekly Mon 9AM) │ │ auto-merge.yml │ │
│ └──────────┘ └───────────────────┘ └──────────────────┘ │
│ │
├─────────────────────────────────────────────────────────────────┤
│ Manual dispatch │
│ ┌──────────────┐ │
│ │ check-links │ → Lychee link validation │
│ │ .yml │ │
│ └──────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Triggers: Push and PR to main and develop branches.
Runs five parallel jobs:
| Job | Description |
|---|---|
| Test | Runs vitest across all packages with Turbo caching. Uploads coverage to Codecov. |
| Lint | Runs ESLint via eslint.config.js (flat config) and TypeScript type-checking. |
| Build Core | Builds all packages using turbo run build. |
| E2E Tests | Runs Playwright end-to-end tests from the e2e/ directory. |
| Build Docs | Builds the documentation site (apps/site). |
Uses: Node 22, pnpm (via corepack), Turbo remote caching.
Triggers: Push and PR when changes touch packages/, apps/console/, or pnpm-lock.yaml.
Its display name in the checks list is Bundle Analysis.
Exactly one bundle-size number in this repository is enforced — this one:
| Bundle | Max gzip size | Enforced |
|---|---|---|
Console main entry (apps/console/dist/assets/index-*.js) |
350 KB (MAX_ENTRY_GZIP_KB) |
Yes — the step exits non-zero when the entry chunk exceeds it |
The 350 KB above is pinned to the workflow, not retyped from memory:
scripts/__tests__/ci-cd-pipeline-doc.test.tsreadsMAX_ENTRY_GZIP_KBout of.github/workflows/performance-budget.ymland failspnpm testif this page disagrees with it. Change one and you must change the other — the number cannot drift silently again (#3197).
- Builds the console app and measures bundle sizes.
- Posts a PR comment with the budget report and pass/fail status — but only when the bundle was actually measured. A run that was cancelled (a second push supersedes the first via
cancel-in-progress) posts nothing, and a run whose build never produced a bundle posts a neutral "not measured" note instead of a verdict. AFAILverdict therefore always carries the measured size that exceeded the budget. - The comment is rendered by
scripts/render-budget-comment.mjs(unit-tested), not by logic inlined in YAML.
The same workflow's Generate package size report step writes a markdown table of every
packages/*/dist/*.js file with its raw and gzipped size, and that table is appended to the
PR comment. The report is generated only from a complete package build, so it is never a
truncated table that looks complete.
The step never compares a measured size against a limit and never exits non-zero — it
echos the three tiers below into the report as explanatory text. They are guidance for
reviewers; exceeding any of them turns no check red and blocks no merge:
| Package category | Advisory target (gzip) | Enforced |
|---|---|---|
| Core packages | < 50 KB | No — advisory only |
| Component packages | < 100 KB | No — advisory only |
| Plugin packages | < 150 KB | No — advisory only |
There is no separate size-check workflow, and there never has been one in this repository — the package size report has always been a step inside
performance-budget.yml. This page used to document one as its own workflow file, enforcing the three tiers above; both claims were false, which is worse than no documentation because it advertises a guardrail that does not exist. If you want these tiers enforced, add the comparison to the workflow — do not describe it as enforced here.
Trigger: Manual workflow dispatch (workflow_dispatch).
Uses Lychee with configuration from lychee.toml:
- Scans markdown files in
docs/andREADME.md - Max concurrency: 10, timeout: 20s, retries: 3
- Excludes: localhost, example.com, Twitter/X, GitHub compare/commit URLs
- Remaps internal
/docs/*paths tofile://./docs/*for local resolution
Trigger: Push of version tags matching v*.
- Runs the full test suite.
- Builds all packages.
- Creates a GitHub Release with auto-generated release notes.
Note: npm publish is currently handled by
changeset-release.ymlinstead.
Trigger: Push to main.
Uses Changesets for automated versioning and npm publishing:
- Detects pending changesets.
- Bumps package versions.
- Publishes to npm.
- Configures a pnpm-lock.yaml merge driver to prevent lock file conflicts.
Trigger: PR to main/develop, and push to main, when .changeset/** changes — the
inverse of every other workflow's filter. ci.yml and lint.yml both list '**/*.md' and
.changeset/** under paths-ignore, so a PR that adds only a changeset starts nothing else.
Runs scripts/check-changeset-no-major.mjs, which fails if any pending changeset declares a
major bump. Every publishable package is in one fixed group (39 packages), so a single
major publishes all of them as the next major — and objectui's major is pinned to the
@objectstack major it is compatible with, not to its own count of breaking changes. Score
breaking changes of our own as minor and describe the break in the changeset body.
The one release that legitimately bumps the major is the one following @objectstack across
its major; it sets OBJECTUI_ALLOW_MAJOR=1. pnpm test asserts the same repository state, so
the rule survives this workflow being skipped.
Trigger: release event (when a GitHub Release is published), or manual dispatch.
Uses git-cliff with cliff.toml configuration to auto-generate CHANGELOG.md and commit it to the repository.
Trigger: PR opened, synchronized, or reopened.
Automatically labels PRs based on file path patterns defined in .github/labeler.yml. Syncs labels on each push to the PR.
Trigger: Daily at 00:00 UTC (cron), or manual dispatch.
| Resource | Stale after | Close after |
|---|---|---|
| Issues | 60 days | 7 days |
| Pull Requests | 45 days | 14 days |
Exempt labels: pinned, security, critical, in-progress.
Trigger: PRs on main/develop authored by dependabot[bot].
- Patch/minor updates: Auto-approved and squash-merged.
- Major updates: Approved with a comment for manual review.
- Configures a pnpm-lock.yaml merge driver for conflict resolution.
Trigger: Weekly on Monday at 9:00 AM UTC, or manual dispatch.
- Runs offline and online analysis of shadcn/ui components.
- Creates or updates a GitHub issue if components need review or updating.
- Uploads analysis artifacts for reference.
- Create a new
.ymlfile in.github/workflows/. - Follow the existing pattern for pnpm + Turbo setup:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- run: pnpm install --frozen-lockfile- Use Turbo for any build/test/lint steps to leverage caching:
- run: pnpm turbo run build --filter=@object-ui/core- For PR workflows, consider adding path filters to avoid unnecessary runs:
on:
pull_request:
paths:
- 'packages/**'
- 'pnpm-lock.yaml'| Secret / Variable | Used By | Purpose |
|---|---|---|
GITHUB_TOKEN |
All workflows | GitHub API access (automatic) |
NPM_TOKEN |
changeset-release.yml |
npm package publishing |
CODECOV_TOKEN |
ci.yml |
Coverage upload to Codecov |
TURBO_TOKEN |
Build workflows | Turbo remote cache authentication |
TURBO_TEAM |
Build workflows | Turbo remote cache team identifier |
Secrets are configured in the repository settings under Settings → Secrets and variables → Actions.