Examples
Real-world configurations and usage patterns for different team workflows.
Team Configurations
Small Startup Team
Simple, flexible setup with optional ticket IDs:
import { defineConfig } from '@branchwright/cli';
export default defineConfig({
branchTypes: [
{ name: 'feat', label: '✨ Feature' },
{ name: 'fix', label: '🐛 Bug Fix' },
{ name: 'chore', label: '🔧 Chore' },
],
template: '{{type}}/{{desc}}',
maxDescriptionLength: 40,
// No ticket requirements
rules: {
ticketId: 'off',
},
// Streamlined workflow
extraQuestions: {
baseBranch: false,
checkout: false,
pushToRemote: false,
},
});
Enterprise Team with Jira
Strict naming with required Jira tickets:
import { defineConfig } from '@branchwright/cli';
export default defineConfig({
branchTypes: [
{ name: 'feature', label: 'Feature' },
{ name: 'bugfix', label: 'Bug Fix' },
{ name: 'hotfix', label: 'Hotfix' },
{ name: 'release', label: 'Release' },
],
template: '{{type}}/{{ticket}}-{{desc}}',
maxDescriptionLength: 50,
descriptionStyle: 'kebab-case',
rules: {
ticketId: ['required', {
prefix: 'PROJ-',
pattern: /^PROJ-\d+$/,
message: 'Ticket must be format: PROJ-123'
}],
},
ignoredBranches: [
'main',
'master',
'develop',
'staging',
'production'
],
questions: {
branchType: 'Select work type:',
ticketIdRequired: 'Enter Jira ticket (PROJ-###):',
description: 'Brief description (kebab-case):',
},
});
GitHub Flow Team
Optimized for GitHub issues and pull requests:
import { defineConfig } from '@branchwright/cli';
export default defineConfig({
branchTypes: [
{ name: 'feat', label: 'Feature' },
{ name: 'fix', label: 'Fix' },
{ name: 'docs', label: 'Documentation' },
{ name: 'refactor', label: 'Refactor' },
],
template: '{{type}}/{{ticket}}-{{desc}}',
rules: {
ticketId: ['optional', {
prefix: 'gh-',
pattern: /^gh-\d+$/
}],
},
questions: {
ticketId: 'GitHub issue number (optional):',
description: 'PR description:',
},
});
Monorepo Configuration
Include package/workspace names in branches:
import { defineConfig } from '@branchwright/cli';
export default defineConfig({
branchTypes: [
{ name: 'feat', label: 'Feature' },
{ name: 'fix', label: 'Fix' },
{ name: 'chore', label: 'Chore' },
],
// Custom template with package name
template: '{{type}}/{{package}}-{{desc}}',
// In practice, you might prompt for package
// or detect it from the current directory
});
CI/CD Integration
GitHub Actions Validation
# .github/workflows/validate-branch.yml
name: Validate Branch Name
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Branchwright
run: npm install -g @branchwright/cli
- name: Validate Branch Name
run: brw lint ${{ github.head_ref }}
env:
BRANCH_NAME: ${{ github.head_ref }}
GitLab CI Validation
# .gitlab-ci.yml
validate-branch:
stage: validate
image: node:20
script:
- npm install -g @branchwright/cli
- brw lint $CI_COMMIT_REF_NAME
only:
- merge_requests
Husky Pre-push Hook
# Install husky
npm install --save-dev husky
npx husky init
# .husky/pre-push
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# Validate branch name before push
npx @branchwright/cli lint || {
echo ""
echo "❌ Branch name validation failed"
echo "Fix your branch name or use:"
echo " brw create"
exit 1
}
Scripting Examples
Batch Branch Creation
#!/bin/bash
# Create multiple feature branches from a list
features=(
"user-authentication"
"payment-integration"
"email-notifications"
"admin-dashboard"
)
for feature in "${features[@]}"; do
brw create -t feat -d "$feature" -y
echo "Created feat/$feature"
done
Ticket-Based Branch Creation
#!/bin/bash
# Create branch from Jira ticket
TICKET=$1
DESCRIPTION=$2
if [ -z "$TICKET" ] || [ -z "$DESCRIPTION" ]; then
echo "Usage: ./create-jira-branch.sh PROJ-123 'description'"
exit 1
fi
brw create -t feat --ticket "$TICKET" -d "$description" -y --push
Integration with gh (GitHub CLI)
#!/bin/bash
# Create branch from GitHub issue
ISSUE_NUMBER=$(gh issue view --json number -q .number)
ISSUE_TITLE=$(gh issue view --json title -q .title | tr '[:upper:]' '[:lower:]' | tr ' ' '-')
brw create -t feat --ticket "gh-$ISSUE_NUMBER" -d "$ISSUE_TITLE" -y
# Create PR
gh pr create --title "feat: $ISSUE_TITLE" --body "Closes #$ISSUE_NUMBER"
Custom Rule Examples
Enforce Team Prefix
import { defineRule, defineConfig } from '@branchwright/cli';
const teamPrefixRule = defineRule(
{
id: 'team-prefix',
meta: {
title: 'Team prefix required',
description: 'Branch must include team identifier',
},
defaultSeverity: 'required',
},
(context) => {
const { teams } = context.options;
const hasTeamPrefix = teams.some(team =>
context.branchName.includes(`-${team}-`)
);
if (!hasTeamPrefix) {
return {
message: `Branch must include team: ${teams.join(', ')}`,
suggestions: teams.map(t =>
context.branchName.replace('-', `-${t}-`)
),
};
}
return null;
}
);
export default defineConfig({
rules: {
'team-prefix': ['required', {
teams: ['frontend', 'backend', 'mobile']
}],
},
});
Prevent WIP Branches
import { defineRule, defineConfig } from '@branchwright/cli';
const noWipRule = defineRule(
{
id: 'no-wip',
meta: {
title: 'No WIP branches',
description: 'Work-in-progress markers not allowed',
},
defaultSeverity: 'required',
},
(context) => {
const wipPatterns = ['wip', 'tmp', 'temp', 'test'];
const hasWip = wipPatterns.some(pattern =>
context.branchName.toLowerCase().includes(pattern)
);
if (hasWip) {
return {
message: 'Remove work-in-progress markers from branch name',
suggestions: [
wipPatterns.reduce(
(name, pattern) => name.replace(pattern, ''),
context.branchName
),
],
};
}
return null;
}
);
export default defineConfig({
rules: {
'no-wip': 'required',
},
});
Maximum Branch Age
import { defineRule, defineConfig } from '@branchwright/cli';
import { execSync } from 'child_process';
const maxAgeRule = defineRule(
{
id: 'max-age',
meta: {
title: 'Branch age limit',
description: 'Branches older than X days should be cleaned up',
},
defaultSeverity: 'optional',
},
(context) => {
const { maxDays } = context.options;
// Get branch creation date
const timestamp = execSync(
`git log --format=%ct ${context.branchName} | tail -1`
).toString();
const ageInDays = (Date.now() - parseInt(timestamp) * 1000) / (1000 * 60 * 60 * 24);
if (ageInDays > maxDays) {
return {
message: `Branch is ${Math.floor(ageInDays)} days old (max: ${maxDays})`,
};
}
return null;
}
);
export default defineConfig({
rules: {
'max-age': ['optional', { maxDays: 30 }],
},
});
Advanced Workflows
Multi-Environment Setup
import { defineConfig } from '@branchwright/cli';
export default defineConfig({
branchTypes: [
{ name: 'feat', label: 'Feature' },
{ name: 'fix', label: 'Fix' },
{ name: 'release', label: 'Release' },
{ name: 'hotfix', label: 'Hotfix' },
],
template: '{{type}}/{{env}}-{{desc}}',
ignoredBranches: [
'main',
'develop',
'staging',
'production',
],
// Custom prompts for environment
questions: {
environment: 'Target environment:',
},
});
Semantic Release Integration
import { defineConfig } from '@branchwright/cli';
export default defineConfig({
// Match semantic-release branch types
branchTypes: [
{ name: 'feat', label: 'Feature (minor)' },
{ name: 'fix', label: 'Fix (patch)' },
{ name: 'perf', label: 'Performance (patch)' },
{ name: 'revert', label: 'Revert (patch)' },
],
template: '{{type}}/{{desc}}',
// Enforce conventional commit style
descriptionStyle: 'kebab-case',
maxDescriptionLength: 50,
});
Release Train Workflow
import { defineConfig } from '@branchwright/cli';
export default defineConfig({
branchTypes: [
{ name: 'feat', label: 'Feature' },
{ name: 'fix', label: 'Fix' },
{ name: 'release', label: 'Release Branch' },
],
template: '{{type}}/{{version}}-{{desc}}',
ignoredBranches: [
'main',
'develop',
/^release\/v\d+\.\d+$/, // release/v1.2
],
});