Skip to content

RFC: Replace intuit/auto with release-please across all library repositories #1

@NiccoloOlivieriAchille

Description

@NiccoloOlivieriAchille

Summary

  1. Replace intuit/auto and @bepower/auto-config with release-please as the standard release tool for all ~30 library repositories publishing to GitHub Packages.
  2. Adopt the develop/main locked-branch model (already our standard for AWS project repos) for library repos as well.
  3. Use develop for prerelease publishes (@next dist-tag) and main for stable releases (@latest dist-tag).
  4. Deprecate @bepower/auto-config.

Motivation

intuit/auto is effectively abandoned

  • Last release: v11.3.6 (no new releases in over a year)
  • 122 open issues, 38 open PRs, near-zero development activity
  • Not formally archived, but no maintainer is actively triaging or merging
  • Our @auto-it/* dependencies (^11.0.5) will never receive security patches or compatibility fixes
  • Staying on auto across ~30 repos means accumulating risk with every Node.js and npm update

Inconsistent branching model

Our AWS project repos already use a locked main + develop branch model. Our library repos don't. This creates cognitive overhead when switching between project types. Aligning the two means one workflow to learn, one model to enforce.

No prerelease channel

With auto, we have no way to publish a prerelease version for testing before promoting to stable. Teams that want to test a library change in a downstream project have to either publish a full release or use npm link / local paths.

Why release-please

Active maintenance

  • Current version: v17.6.0 (released April 13, 2026)
  • Multiple releases per month, actively maintained by Google
  • 6.7k GitHub stars, 539 forks

Fit for our workflow

Requirement release-please
Conventional Commits ✅ Native (we already use them everywhere)
Changelog generation ✅ Automatic, from commit history
GitHub Releases + tags ✅ Built-in
Publish to GitHub Packages ✅ Decoupled — we handle npm publish ourselves
Prerelease versions ✅ Native support for non-default branches
Review before release ✅ Creates a Release PR the team can review
Monorepo (independent versions) ✅ Manifest-based, per-package versioning

Why not the alternatives?

Tool Why not
semantic-release No Release PR review step. Every merge publishes immediately. Monorepo support is community-plugin only.
Changesets Requires manual changeset files per PR. More ceremony than we need. JS-only.

Proposed branching model (all library repos)

Flow

feature-branch → PR → develop
                         │
              release-please opens Release PR (v2.1.0-beta.1)
                         │
              merge Release PR → publish @next to GitHub Packages
                         │
              develop → PR → main
                               │
                    release-please opens Release PR (v2.1.0)
                               │
                    merge Release PR → publish @latest to GitHub Packages

Branch rules

Branch Push Purpose
main 🔒 PR only Stable releases (@latest)
develop 🔒 PR only Prerelease versions (@next)
feature/*, fix/*, etc. ✅ Free push Day-to-day work

Merge strategy

When merging developmain, use merge commit (no squash, no rebase). release-please traverses merge commits and reads the individual conventional commits inside. Squash merging would collapse all commits into one, losing changelog granularity.

Default branch

Keep main as the default branch in GitHub. This is important because release-please treats the default branch as the stable release branch. If develop were the default, release-please would generate stable versions there instead of prereleases.

Developers target develop for feature PRs by convention, enforced by branch protection rules.

How release-please works

Configuration

Each repo needs exactly 2 config files + 1 workflow.

release-please-config.json (repo root)

{
  "release-type": "node",
  "prerelease": true,
  "packages": {
    ".": {}
  }
}
  • "release-type": "node" — updates package.json version fields
  • "prerelease": true — on non-default branches (develop), generates versions like 2.1.0-beta.1; on main, this flag is ignored and stable versions are generated
  • "packages" — for single-package repos use ".", for monorepos list each package path

.release-please-manifest.json (repo root)

{
  ".": "1.5.3"
}

Set this once to match the current published version. After the first release, release-please maintains it automatically.

Where is what configured

What Where
Which packages to release release-please-config.json
Current version per package .release-please-manifest.json
Enable prerelease on non-default branches "prerelease": true in config JSON
Which branches trigger release-please Workflow YAML (on.push.branches)
Which branch is stable vs prerelease Automatic: repo's default branch = stable, all others = prerelease

No CLI commands to run manually after setup. Everything is file-driven.

Pilot: bep-cdk

We'll use bep-cdk as the pilot repo. It's a good candidate because:

  • It's a monorepo with 2 independently versioned packages (@bepower/bep-cdk at v7.124.4, @bepower/bep-cdk-lib at v10.99.4)
  • It already uses @bepower/auto-config, lerna, conventional commits, and publishes to GitHub Packages
  • It has a CI workflow + a release workflow — representative of all our library repos

Current setup (before)

auto.config.ts:

import base, { coverage, packages } from '@bepower/auto-config';

export default function config(): AutoRc {
  base.plugins?.push(packages);
  base.plugins?.push([coverage, coverageOptions]);
  return base;
}

npm.yaml (release workflow): runs auto shipit on push to main.

ci.yaml: tests on Node 20, 22, 24.

Dependencies: @bepower/auto-config, auto, @auto-it/* (5+ packages), lerna.

Proposed setup (after)

release-please-config.json:

{
  "release-type": "node",
  "prerelease": true,
  "packages": {
    "packages/bep-cdk": {},
    "packages/bep-cdk-lib": {}
  }
}

.release-please-manifest.json:

{
  "packages/bep-cdk": "7.124.4",
  "packages/bep-cdk-lib": "10.99.4"
}

ci.yaml (replaces both ci.yaml and npm.yaml):

name: CI

on:
  push:
    branches:
      - main
      - develop
  pull_request:
    branches:
      - main
      - develop

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node: [22, 24]
    steps:
      - uses: actions/checkout@v6

      - uses: actions/setup-node@v6
        with:
          node-version: ${{ matrix.node }}
          registry-url: 'https://npm.pkg.github.com'
          scope: '@bepower'
          cache: npm

      - run: npm ci
        env:
          GITHUB_TOKEN: ${{ github.token }}

      - run: npm test

  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      - uses: actions/setup-node@v6
        with:
          node-version: 'lts/*'
          registry-url: 'https://npm.pkg.github.com'
          scope: '@bepower'
          cache: npm

      - run: npm ci
        env:
          GITHUB_TOKEN: ${{ github.token }}

      - run: npm run lint

      - name: Check if nothing changed
        run: git diff --name-only --exit-code

  release-please:
    if: github.event_name == 'push'
    needs: [test, lint]
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
    outputs:
      releases_created: ${{ steps.release.outputs['packages/bep-cdk--release_created'] == 'true' || steps.release.outputs['packages/bep-cdk-lib--release_created'] == 'true' }}
    steps:
      - uses: googleapis/release-please-action@v4
        id: release
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          target-branch: ${{ github.ref_name }}

  publish:
    if: needs.release-please.outputs.releases_created == 'true'
    needs: release-please
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v6

      - uses: actions/setup-node@v6
        with:
          node-version: 'lts/*'
          registry-url: 'https://npm.pkg.github.com'
          scope: '@bepower'
          cache: npm

      - run: npm ci
        env:
          GITHUB_TOKEN: ${{ github.token }}

      - run: npm run build

      - name: Publish packages with appropriate dist-tag
        run: |
          TAG="latest"
          if [ "${{ github.ref_name }}" != "main" ]; then
            TAG="next"
          fi
          npm publish -w packages/bep-cdk --tag "$TAG" || true
          npm publish -w packages/bep-cdk-lib --tag "$TAG" || true
        env:
          NODE_AUTH_TOKEN: ${{ github.token }}

Note: || true on publish commands prevents failure if only one of the two packages has a new version. npm publish will fail with "already published" for the unchanged package — this is expected.

Note on the Action vs CLI: the workflow uses googleapis/release-please-action@v4. For monorepos, use the per-package output <path>--release_created (not the global releases_created). If the team prefers the CLI approach:

- run: npx release-please release-pr --token=${{ secrets.GITHUB_TOKEN }} --repo-url=BePower/bep-cdk --target-branch=${{ github.ref_name }}
- run: npx release-please github-release --token=${{ secrets.GITHUB_TOKEN }} --repo-url=BePower/bep-cdk --target-branch=${{ github.ref_name }}

What gets removed from bep-cdk

File/dependency Action
auto.config.ts Delete
lerna.json Delete
@bepower/auto-config npm uninstall
"release" script in package.json Remove
.github/workflows/npm.yaml Delete (merged into ci.yaml)

What gets added

File Purpose
release-please-config.json Package + release config
.release-please-manifest.json Current versions
Updated .github/workflows/ci.yaml CI + release-please + publish

Migration playbook (per repo)

After the pilot is validated, each repo follows these steps:

1. Create develop branch

git checkout main && git pull
git checkout -b develop
git push -u origin develop

2. Add release-please config files

release-please-config.json — adapt packages to your repo:

{
  "release-type": "node",
  "prerelease": true,
  "packages": {
    ".": {}
  }
}

.release-please-manifest.json — set current published version:

{
  ".": "1.2.3"
}

3. Replace the GitHub Actions workflow

Use the template from the pilot section above. Adapt test/lint jobs to match your repo.

4. Remove auto configuration and dependencies

rm -f .autorc .autorc.js .autorc.ts .autorc.json auto.config.ts lerna.json
npm uninstall auto @auto-it/core @auto-it/conventional-commits @auto-it/all-contributors \
  @auto-it/first-time-contributor @auto-it/magic-zero @bepower/auto-config lerna

Remove the "release" script from package.json.

5. Lock branches in GitHub repo settings

  • Settings → Branches → Branch protection rules
  • main: require PR, require status checks, no direct push
  • develop: require PR, require status checks, no direct push

6. Commit and push

git add release-please-config.json .release-please-manifest.json .github/workflows/
git commit -m "feat: migrate from auto to release-please"
git push

Checklist

[ ] Create develop branch from main
[ ] Add release-please-config.json
[ ] Add .release-please-manifest.json (with current version)
[ ] Replace/update GitHub Actions workflow
[ ] Delete auto config file (.autorc* / auto.config.ts)
[ ] Delete lerna.json
[ ] Remove auto / @auto-it/* / @bepower/auto-config / lerna dependencies
[ ] Remove "release" script from package.json
[ ] Lock main branch (require PR)
[ ] Lock develop branch (require PR)
[ ] Verify first Release PR is created correctly

Rollout plan

Phase Timeline Scope
Pilot Week 1 Migrate bep-cdk. Validate end-to-end: Release PR creation, changelog, tag, GitHub Release, publish to GitHub Packages.
Early adopters Week 2-3 Migrate 3-5 repos volunteered by team members. Collect feedback, refine the playbook.
Full rollout Week 4+ Migrate remaining repos. Can be done gradually — auto and release-please don't conflict.

What changes for developers day-to-day

Before After
Push/merge to main Push to feature branch, PR to develop
Release happens automatically on merge Release PR appears, team reviews, then merges
No prerelease testing Install @next to test before stable release
npx auto shipit in CI No release command — release-please handles it
Commit conventions: same Commit conventions: same (conventional commits)

@bepower/auto-config deprecation

Once all repos are migrated:

  1. Publish a final version of @bepower/auto-config with npm deprecate message pointing to this RFC
  2. Archive the package in dev-configs repo

Open questions

  • GitHub Action vs CLI: use the Action wrapper (simpler) or direct CLI calls (more control)?
  • Prerelease channel: do we need @next from day one, or add it later? (Easy to add — just add develop to workflow triggers and set "prerelease": true.)
  • Merge strategy: merge commit for developmain (recommended) or another preference?
  • Rollout pace: pilot + gradual, or migrate everything at once?
  • Node.js test matrix: standardize on 22 + 24? (Node.js 20 EOL: April 30, 2026)

References

Metadata

Metadata

Labels

questionFurther information is requested

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions