We love your input! We want to make contributing to this project as easy and transparent as possible, whether it's:
- Reporting a bug
- Discussing the current state of the code
- Submitting a fix
- Proposing new features
- Becoming a maintainer
We use GitHub to host code, to track issues and feature requests, as well as accept pull requests.
# Fork the repository on GitHub, then:
git clone https://github.com/YOUR_USERNAME/ui.git
cd ui
pnpm install# Start development servers
pnpm dev
# Run validation
pnpm validate
# Build the project
pnpm build-
Create a branch from
dev(our default branch):git checkout dev git pull origin dev git checkout -b feature/my-new-feature
-
Make your changes following our coding standards
-
Write or update tests for your changes
-
Run the validation pipeline:
pnpm validate
-
Commit your changes using conventional commits:
git commit -m "feat: add amazing new component"
- Push your branch to your fork
- Create a Pull Request against the
devbranch (not main!) - Fill out the PR template completely
- Ensure all checks pass
- Request review from maintainers
This project uses GitHub Actions for continuous integration and deployment, ensuring code quality, security, and reliability across all supported branches. The CI pipeline is designed following industry best practices for scaled open source projects.
The CI workflow automatically runs on:
- Push events to branches:
dev,alpha,beta,rc,main - Pull request events targeting these branches
To optimize resource usage and prevent redundant runs, the pipeline uses concurrency groups that cancel in-progress runs when new commits are pushed to the same branch.
The pipeline consists of the following jobs, running conditionally based on file changes:
-
Changes Detection (
changes)- Analyzes modified files to determine which subsequent jobs should run
- Uses path filtering to skip unnecessary checks for documentation-only changes
-
Setup (
setup)- Installs dependencies using pnpm with frozen lockfile
- Configures Node.js 20 and caching for pnpm store, Nx cache, and node_modules
- Initializes Nx Cloud for distributed task execution
-
Linting (
lint)- Runs ESLint across the codebase
- Ensures consistent code style and catches potential issues
-
Type Checking (
typecheck)- Performs TypeScript compilation checks
- Validates type safety across all projects
-
Security Scanning (
security)- Runs
pnpm auditfor dependency vulnerabilities - Performs dependency review on pull requests to detect security issues
- Continues on error to avoid blocking development for non-critical issues
- Runs
-
Testing (
test)- Executes unit tests using Jest/Vitest
- Runs across all affected projects in the monorepo
-
Build (
build)- Builds all affected projects
- Generates documentation
- Performs bundle size checks
- Applies Nx Cloud CI optimizations and fixes
-
Failure Notification (
notify-failure)- Creates GitHub issues when CI fails
- Includes details about which jobs failed and links to workflow runs
All release branches have required status checks:
- Linting must pass
- Type checking must pass
- Security scans must complete
- Tests must pass
- Build must succeed
Pull requests cannot be merged until all required checks pass.
The pipeline implements multi-layer caching for performance:
- pnpm Store Cache: Caches downloaded packages
- Nx Cache: Speeds up task execution through computation caching
- Node Modules Cache: Avoids reinstallation when lockfile hasn't changed
We use Nx Cloud for enhanced CI performance:
- Remote Caching: Shares computation results across runs
- Distributed Execution: Parallelizes tasks across multiple agents
- Performance Insights: Provides detailed build analytics
If CI fails on your pull request:
-
Check the Actions Tab: Review the detailed logs for each failed job
-
Run Locally First: Reproduce issues locally before pushing fixes:
pnpm validate # Runs lint, typecheck, test, build -
Common Issues:
- Lint Errors: Run
pnpm run lintand fix code style issues - Type Errors: Run
pnpm run typecheckand resolve TypeScript issues - Test Failures: Run
pnpm run testand debug failing tests - Build Failures: Run
pnpm run buildand check for compilation errors - Security Issues: Review dependency vulnerabilities and update packages
- Lint Errors: Run
-
Push Fixes: Commit and push your changes to trigger a new CI run
-
Request Help: If issues persist, mention maintainers in your PR
The pipeline is optimized for speed and cost-efficiency:
- Conditional Execution: Jobs only run when relevant files change
- Intelligent Caching: Minimizes redundant work
- Parallel Execution: Multiple jobs run simultaneously where possible
- Early Failure Detection: Fast feedback on linting and type errors
When making changes that affect CI:
- Update
.github/workflows/ci.ymlfor workflow changes - Test workflow changes on a feature branch first
- Ensure new jobs follow the established patterns
- Update this documentation if adding new checks or processes
We use a 5-branch release strategy combining Changesets for version management and Semantic Release for automated publishing:
dev (default) → alpha → beta → rc → main
| Branch | Purpose | Release Type | NPM Tag | Release Tool |
|---|---|---|---|---|
dev |
Active development | No release | - | Changesets (versioning) |
alpha |
Experimental features | Pre-release | @alpha |
Semantic Release |
beta |
Feature-complete testing | Pre-release | @beta |
Semantic Release |
rc |
Release candidates | Pre-release | @rc |
Changesets |
main |
Stable production | Stable | @latest |
Changesets |
- Development: All feature branches merge into
dev - Versioning: Changesets automatically create version PRs when changes are pushed to
dev - Alpha Release: Merge version PR to
alphabranch triggers automatic semantic-release prerelease (0.1.0-alpha.1) - Beta Release: Merge
alpha→betatriggers automatic semantic-release prerelease (0.1.0-beta.1) - Release Candidate: Merge
beta→rctriggers changesets stable release (0.1.0-rc.1) - Stable Release: Merge
rc→maintriggers changesets stable release (0.1.0)
The release process is fully automated using GitHub Actions:
- Version Management: Changesets create version bump PRs on
devbranch pushes - Branch Merging: Use the "Branch Merge Pipeline" workflow to merge between release branches
- Prereleases: Semantic Release automatically publishes alpha/beta versions and updates changelog
- Stable Releases: Changesets handle versioning and publishing for rc/main branches
The following branches are protected with comprehensive rules:
- Protected Branches:
main,rc,alpha,beta,dev
Protection Rules Applied to All Protected Branches:
- Deletion Protection: Branch deletion is not allowed
- Force Push Protection: Force pushes are not allowed (non-fast-forward only)
- Pull Request Requirements:
- Pull requests are required for all changes
- Code owner review is required
- Review thread resolution is required
- Allowed merge methods: merge, squash, rebase
- Required Status Checks:
lint,typecheck,security,test,build - Code Scanning: CodeQL security alerts must be resolved (high or higher severity)
Additional Notes:
- No minimum number of approving reviews required beyond code owner approval
- No bypass actors configured - all contributors must follow the rules
- Branch protection ensures code quality and security across all release branches
Complete Branch Protection Ruleset (JSON):
{
"id": 8101922,
"name": "Protect All Branches",
"target": "branch",
"source_type": "Repository",
"source": "ruma-ui/ui",
"enforcement": "active",
"conditions": {
"ref_name": {
"exclude": [],
"include": [
"refs/heads/main",
"refs/heads/rc",
"refs/heads/beta",
"refs/heads/dev",
"refs/heads/alpha"
]
}
},
"rules": [
{
"type": "deletion"
},
{
"type": "code_scanning",
"parameters": {
"code_scanning_tools": [
{
"tool": "CodeQL",
"security_alerts_threshold": "high_or_higher",
"alerts_threshold": "errors"
}
]
}
},
{
"type": "required_status_checks",
"parameters": {
"strict_required_status_checks_policy": true,
"do_not_enforce_on_create": false,
"required_status_checks": [
{
"context": "lint",
"integration_id": 15368
},
{
"context": "typecheck",
"integration_id": 15368
},
{
"context": "security",
"integration_id": 15368
},
{
"context": "test",
"integration_id": 15368
},
{
"context": "build",
"integration_id": 15368
}
]
}
},
{
"type": "non_fast_forward"
},
{
"type": "pull_request",
"parameters": {
"required_approving_review_count": 0,
"dismiss_stale_reviews_on_push": false,
"require_code_owner_review": true,
"require_last_push_approval": false,
"required_review_thread_resolution": true,
"automatic_copilot_code_review_enabled": false,
"allowed_merge_methods": ["merge", "squash", "rebase"]
}
}
],
"bypass_actors": []
}- Development:
0.1.0-dev.X(not published) - Alpha:
0.1.0-alpha.X(experimental, may have breaking changes) - Beta:
0.1.0-beta.X(feature-complete, API stable) - RC:
0.1.0-rc.X(production-ready, final testing) - Stable:
0.1.0(production release)
- Use TypeScript for all code
- Prefer interfaces over types for object shapes
- Use strict typing, avoid
any - Export types alongside components
- Use functional components with hooks
- Prefer composition over inheritance
- Follow the compound component pattern when appropriate
- Use forwardRef for components that should accept refs
- Use Tailwind CSS for styling
- Follow the utility-first approach
- Use CSS variables for theme customization
- Ensure responsive design
- Write tests for all components
- Test user interactions, not implementation details
- Use Testing Library best practices
- Aim for high test coverage
- Document all props with JSDoc comments
- Include usage examples in Storybook
- Update README.md for new features
- Write clear commit messages
This project uses Conventional Commits for automated versioning and changelog generation.
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
feat: A new featurefix: A bug fixdocs: Documentation only changesstyle: Changes that do not affect the meaning of the coderefactor: A code change that neither fixes a bug nor adds a featureperf: A code change that improves performancetest: Adding missing tests or correcting existing testsbuild: Changes that affect the build system or external dependenciesci: Changes to our CI configuration files and scriptschore: Other changes that don't modify src or test filesrevert: Reverts a previous commit
# Feature
git commit -m "feat: add Button component with variants"
git commit -m "feat(button): add loading state"
# Bug fix
git commit -m "fix: resolve hover state issue in Button"
git commit -m "fix(modal): prevent scroll when modal is open"
# Breaking change
git commit -m "feat!: redesign Button API for better customization"
# With body and footer
git commit -m "feat: add new theming system
This introduces a comprehensive theming system that allows
for complete customization of component appearance.
BREAKING CHANGE: The old \`color\` prop has been replaced with \`variant\`"// ComponentName.tsx
import React from "react";
import { cn } from "@ruma-kit/ui";
export interface ComponentNameProps {
/**
* Description of the prop
*/
variant?: "primary" | "secondary";
/**
* Description of the prop
*/
children: React.ReactNode;
/**
* Additional CSS classes
*/
className?: string;
}
export const ComponentName = React.forwardRef<HTMLElement, ComponentNameProps>(
({ variant = "primary", children, className, ...props }, ref) => {
return (
<element
ref={ref}
className={cn(
"base-classes",
{
"variant-primary-classes": variant === "primary",
"variant-secondary-classes": variant === "secondary",
},
className
)}
{...props}
>
{children}
</element>
);
}
);
ComponentName.displayName = "ComponentName";// ComponentName.test.tsx
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { ComponentName } from "./ComponentName";
describe("ComponentName", () => {
it("renders children correctly", () => {
render(<ComponentName>Test content</ComponentName>);
expect(screen.getByText("Test content")).toBeInTheDocument();
});
it("applies variant classes correctly", () => {
render(<ComponentName variant="secondary">Test</ComponentName>);
expect(screen.getByText("Test")).toHaveClass("variant-secondary-classes");
});
it("handles user interactions", async () => {
const user = userEvent.setup();
const handleClick = jest.fn();
render(<ComponentName onClick={handleClick}>Test</ComponentName>);
await user.click(screen.getByText("Test"));
expect(handleClick).toHaveBeenCalledTimes(1);
});
});// ComponentName.stories.tsx
import type { Meta, StoryObj } from "@storybook/react";
import { ComponentName } from "./ComponentName";
const meta: Meta<typeof ComponentName> = {
title: "Components/ComponentName",
component: ComponentName,
parameters: {
layout: "centered",
},
tags: ["autodocs"],
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Primary: Story = {
args: {
variant: "primary",
children: "Primary Component",
},
};
export const Secondary: Story = {
args: {
variant: "secondary",
children: "Secondary Component",
},
};We use a 5-branch release strategy with Changesets for version management:
Changesets automate version management and changelog generation:
- Commit your changes to feature branches using conventional commits
- Changesets will automatically analyze commits and create version bump PRs on the
devbranch - No manual changeset creation required for most changes
- Version PRs: Automatically created when pushing to
devbranch - Stable Releases: Changesets create release PRs that bump versions and update changelogs
- Manual Changesets: For complex changes, use
pnpm changesetto create custom changeset files
- Push commits to
devbranch - Changesets workflow creates a version PR with updated package versions
- Review and merge the version PR to alpha/beta/rc/main branches using the Branch Merge workflow
- Automated publishing occurs based on the target branch (semantic-release for alpha/beta, changesets for rc/main)
- Documentation: Check our documentation site
- Issues: Search existing GitHub issues
- Discussions: Join our GitHub Discussions
This project and everyone participating in it is governed by our Code of Conduct. By participating, you are expected to uphold this code.
By contributing, you agree that your contributions will be licensed under the MIT License.