npm package: @sylphx/bump
Description: Modern changelog and release management
Author: SylphxAI
Latest version: 1.6.1

# @sylphx/bump

Fully semantic release automation. Conventional commits in, semantic versions out.

## Features

- **Fully semantic** - Conventional commits → semantic versions, automatically
- **Zero config** - Works out of the box, no setup required
- **Automatic Release PRs** - Preview changes before publishing
- **Monorepo native** - File-based detection, independent versioning, cascade bumps
- **Workspace protocol** - Auto-resolves `workspace:*` dependencies at publish time
- **Pre-releases** - Alpha, beta, RC via bump files
- **Graduate to 1.0** - Bump file to go from 0.x → 1.0.0
- **Cross-platform** - Works with npm, yarn, pnpm, and bun
- **GitHub integration** - Auto-creates releases and changelogs
- **Bump files** - Optional manual control with custom changelogs

## Why bump?

| | bump | changesets |
|---|---|---|
| **Setup** | 1 workflow file | Multiple config files + bot |
| **Workflow** | Just commit | Create changeset file per change |
| **Version control** | Automatic from commits | Manual per-changeset |
| **Learning curve** | Know conventional commits? Done | New syntax + tooling |
| **PR noise** | 1 release PR | 1 changeset file per change |
| **Fine-grained control** | Via commit message or bump file | Via changeset file |
| **Workspace protocol** | Auto-resolved | Manual handling required |
| **Cascade bumps** | Automatic | Manual configuration |

Both tools support fine-grained version control - the difference is **where** you express it:

- **bump**: Control versions through commit messages (`feat:` = minor, `fix:` = patch, `feat!:` = major), or optionally via bump files for custom changelog entries
- **changesets**: Control versions through separate changeset files

Choose **bump** if you prefer keeping version intent in your git history.
Choose **changesets** if you prefer separate files for release notes.

## How It Works

1. You write commits like `feat: add login` or `fix: resolve bug`
2. Bump creates a Release PR automatically
3. You merge the PR when ready
4. Bump publishes to npm

```
git commit -m "feat: add dark mode"
git push
        ↓
   [Release PR created automatically]
        ↓
   [You merge when ready]
        ↓
   [Published to npm!]
```

## Setup (2 minutes)

### Step 1: Add the workflow

Create `.github/workflows/release.yml`:

```yaml
name: Release

on:
  push:
    branches: [main]

permissions:
  contents: write
  pull-requests: write

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: SylphxAI/bump@v0
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          npm-token: ${{ secrets.NPM_TOKEN }}
```

### Step 2: Add NPM_TOKEN secret

1. Go to [npmjs.com](https://www.npmjs.com) → Access Tokens → Generate New Token
2. Go to your repo → Settings → Secrets → Actions → New repository secret
3. Name: `NPM_TOKEN`, Value: your token

### Step 3: Done!

Push a commit and watch the magic happen.

## Commit Format

Use these prefixes in your commits:

| Commit | Version Bump | Example |
|--------|--------------|---------|
| `feat:` | Minor (1.0.0 → 1.1.0) | `feat: add dark mode` |
| `fix:` | Patch (1.0.0 → 1.0.1) | `fix: resolve login bug` |
| `feat!:` | Major (1.0.0 → 2.0.0) | `feat!: redesign API` |

Other prefixes like `docs:`, `chore:`, `test:`, `ci:` don't trigger releases.

### Semver 0.x Behavior

During 0.x development, breaking changes bump minor instead of major (per semver spec):
- `feat!:` on 0.1.0 → 0.2.0 (not 1.0.0)

When ready for stable release, create a bump file:
```markdown
# .bump/graduate.md
---
release: "1.0.0"
---

First stable release!
```

## What Happens

When you push to main:

```
┌─────────────────────────────────────────────────────────┐
│  Your commits:                                          │
│  - feat: add user profile                               │
│  - fix: resolve logout issue                            │
│  - docs: update readme                                  │
└─────────────────────────────────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────┐
│  PR #42: chore(release): 1.2.0                          │
├─────────────────────────────────────────────────────────┤
│  ## 🚀 Release                                          │
│                                                         │
│  This PR will release **my-package** version **1.2.0**  │
│                                                         │
│  ### ✨ Features                                        │
│  - add user profile (abc1234)                           │
│                                                         │
│  ### 🐛 Bug Fixes                                       │
│  - resolve logout issue (def5678)                       │
│                                                         │
│  > Merging this PR will publish to npm                  │
└─────────────────────────────────────────────────────────┘
                            ↓
                    [You merge the PR]
                            ↓
                  [Published to npm! 🚀]
```

## FAQ

### When should I merge the Release PR?

Whenever you want to publish. The PR stays open and updates automatically with each push. Merge it when you're ready to release.

### What if I don't want to release yet?

Just don't merge the PR. It will keep updating as you push more commits.

### Can I release without a PR?

Yes! Use `mode: release` to publish directly:

```yaml
- uses: SylphxAI/bump@v0
  with:
    mode: release
    github-token: ${{ secrets.GITHUB_TOKEN }}
    npm-token: ${{ secrets.NPM_TOKEN }}
```

### Can I trigger releases manually?

Yes! Add `workflow_dispatch`:

```yaml
on:
  workflow_dispatch:  # Manual trigger
  push:
    branches: [main]
```

Then go to Actions → Release → Run workflow.

## CLI Usage

The CLI is for local development - checking status and creating bump files:

```bash
# Install
npm add -D @sylphx/bump

# Check release status (also runs with just `bump`)
bump status

# Create bump files
bump add                      # Interactive mode
bump add minor                # Minor release
bump add patch --beta         # Patch with beta prerelease
bump add minor -p @scope/core # Target specific package
bump add "1.0.0"              # Explicit version

# Initialize config (optional)
bump init
```

> **Note**: Releases are handled automatically by GitHub Actions. The CLI is only for local development.

## Monorepo Support

Bump automatically detects monorepos (via `workspaces` in package.json) and handles them intelligently:

### How It Works

1. **File-based detection**: Commits are mapped to packages by analyzing which files changed
2. **Per-package versioning**: Each package gets its own version based on its relevant commits
3. **Per-package tags**: Tags follow `@scope/pkg@1.0.0` format for independent tracking
4. **Smart PR body**: Shows all packages being released in a summary table

```
┌────────────────────────────────────────────────────────────┐
│  PR #42: chore(release): @scope/foo@1.2.0, @scope/bar@2.0.0│
├────────────────────────────────────────────────────────────┤
│  ## 🚀 Release                                             │
│                                                            │
│  | Package     | Current | New   | Type  |                 │
│  |-------------|---------|-------|-------|                 │
│  | @scope/foo  | 1.1.0   | 1.2.0 | minor |                 │
│  | @scope/bar  | 1.9.0   | 2.0.0 | major |                 │
│                                                            │
│  ### 📦 @scope/foo `1.1.0` → `1.2.0`                       │
│  - feat: add new feature (abc1234)                         │
│                                                            │
│  ### 📦 @scope/bar `1.9.0` → `2.0.0` ⚠️                    │
│  - feat!: breaking change (def5678)                        │
└────────────────────────────────────────────────────────────┘
```

### Monorepo Setup

Same workflow as single packages - just make sure you have `workspaces` in your root package.json:

```json
{
  "workspaces": ["packages/*"]
}
```

No additional configuration needed!

## Configuration (Optional)

Create `bump.config.ts` for custom settings:

```typescript
import { defineConfig } from '@sylphx/bump'

export default defineConfig({
  // Customize commit types
  conventional: {
    types: {
      feat: 'minor',
      fix: 'patch',
      perf: 'patch',
      // Add your own
      improvement: 'minor',
    },
  },

  // Changelog options
  changelog: {
    file: 'CHANGELOG.md',
    groupBy: 'type', // or 'scope' or 'none'
  },

  // Publishing options
  publish: {
    access: 'public',
    tag: 'latest', // or 'next', 'beta', etc.
  },
})
```

## Pre-releases

Use bump files for pre-release versions:

```markdown
# .bump/beta.md
---
release: minor
prerelease: beta
---

New beta feature.
```

→ `1.0.0` → `1.1.0-beta.0`

Workflow:
1. Create `.bump/beta.md` with `prerelease: beta`
2. Push → PR created for `v1.1.0-beta.0`
3. Merge → publish beta
4. For stable release, create `.bump/stable.md` without `prerelease`
5. Push → PR created for `v1.1.0`


## Bump Files

While bump works automatically from commits, you can use **bump files** for:
- Custom changelog entries with hand-written release notes
- Manual version specification (e.g., recovery from blocked npm versions)
- Triggering releases without conventional commits
- Pre-release versions (alpha, beta, rc)

### Creating Bump Files

Use the `bump add` command:

```bash
# Interactive mode - prompts for all options
bump add

# Quick creation
bump add patch                    # Patch release
bump add minor                    # Minor release
bump add major                    # Major release

# With prerelease
bump add minor --alpha            # 1.0.0 → 1.1.0-alpha.0
bump add minor --beta             # 1.0.0 → 1.1.0-beta.0
bump add minor --rc               # 1.0.0 → 1.1.0-rc.0
bump add patch --prerelease next  # Custom prerelease tag

# Target specific package (monorepo)
bump add patch -p @scope/core
bump add minor --package @scope/utils

# With changelog message
bump add minor -m "Added new dashboard feature"

# Explicit version (recovery)
bump add "1.2.3"                  # Set exact version
```

Or create a markdown file in `.bump/` directory manually:

```markdown
# .bump/feature.md
---
release: minor
---

### New Dashboard

Completely redesigned the analytics dashboard with:
- Real-time data updates
- Customizable widgets
- Export to PDF/CSV
```

**Fields:**
- `release` - `patch`, `minor`, `major`, or explicit version `"1.2.3"`
- `prerelease` - (optional) `alpha`, `beta`, `rc`
- `package` / `packages` - (optional) target package(s)

### Prerelease Versions

```markdown
# .bump/beta-feature.md
---
release: minor
prerelease: beta
---

New feature in beta testing.
```
→ `1.0.0` → `1.1.0-beta.0`

```markdown
# .bump/rc.md
---
release: patch
prerelease: rc
packages:
  - @scope/core
  - @scope/utils
---

Release candidate.
```
→ `1.0.0` → `1.0.1-rc.0`

### Monorepo Support

**Single package:**
```markdown
---
release: patch
package: @scope/core
---

Bug fix for core module.
```

**Multiple packages:**
```markdown
---
release: minor
packages:
  - @scope/core
  - @scope/utils
---

Shared feature across packages.
```

**All packages** (omit package field):
```markdown
---
release: patch
---

Security fix for all packages.
```

### How It Works

1. Create `.bump/*.md` file with frontmatter
2. Push to main → Release PR includes your custom changelog
3. Merge PR → Bump files are automatically removed

### Recovery Example

If npm publish fails due to a blocked version:

```markdown
# .bump/recovery.md
---
release: "1.2.1"
package: @scope/mypackage
---

Recovery release after npm publish failure.
```

Push this file, and bump will create a new PR with version `1.2.1`.

## Action Inputs

| Input | Description | Default |
|-------|-------------|---------|
| `mode` | `auto`, `release`, `version`, or `pr` | `auto` |
| `github-token` | GitHub token | required |
| `npm-token` | NPM token for publishing | - |
| `dry-run` | Preview without publishing | `false` |
| `base-branch` | Base branch for PR mode | `main` |
| `tag` | Create git tags | `true` |
| `changelog` | Update CHANGELOG.md | `true` |
| `github-release` | Create GitHub release | `true` |

## Permissions

The workflow requires these permissions:

```yaml
permissions:
  contents: write      # For creating tags and releases
  pull-requests: write # For creating/updating release PRs
```

## License

MIT