rlsy
v0.4.0
Published
CLI tool for streamlining the release process with automated changelog generation and version management
Readme
Features
- Automated Changelog Generation - Generate Keep a Changelog formatted changelogs from git commits with smart categorization
- Hand-Written Entries - Entries kept under
## [Unreleased]during development become the release notes, and the commits that wrote them drop out of the generated list - Interactive Version Management - Semantic versioning with guided prompts and cursor key navigation for patch, minor, major, or custom versions
- Changelog Linting - Checks the changelog against Keep a Changelog with
rlsy lint, and optionally before every release writes it - Multi-File Version Updates - Automatically update version numbers across multiple files (package.json, Chart.yaml, Dockerfile, source code, documentation, and more)
- NPM Publishing - Opt-in package publishing to npm with support for npm, yarn, and pnpm (auto-detected from lock files); without it, releases still check that publishing would work
- Helm Chart Support - Built-in support for Helm charts with independent versioning for charts and applications
- Dry-Run Mode - Preview all changes before execution with comprehensive diffs and operation summaries
- GitLab & GitHub Integration - Seamlessly create releases on GitLab (via glab) or GitHub (via gh) with curated changelog as release notes
- Stable Branch Protection - Prevent accidental breaking changes on stable branches
- Zero Configuration - Works out of the box with sensible defaults, configure only what you need
- Git-First Approach - Leverages your existing git history and commit conventions
Installation
Prerequisites
rlsy requires the following tools to be installed:
- Node.js >= 18.0.0
- git (for version control operations)
- glab (GitLab CLI) - Installation instructions
Install rlsy
# Install globally via npm
npm install -g rlsy
# Or use directly with npx
npx rlsySet up your editor
rlsy uses your preferred text editor to curate changelogs. Set the $EDITOR environment variable:
# Add to your shell profile (~/.bashrc, ~/.zshrc, etc.)
export EDITOR=vim # or nano, emacsGUI editors return immediately unless told to wait, which makes rlsy read the changelog back unedited. Always add the wait flag:
export EDITOR="code -w" # VS Code; also "codium -w", "subl -w"Authenticate with GitLab
If you haven't already, authenticate glab with your GitLab instance:
glab auth loginQuick Start
Initialize Configuration (Optional)
First time using rlsy? Run the interactive setup wizard:
# Interactive configuration setup
rlsy init
# Or use auto-detected defaults
rlsy init --yesThis creates a .rlsyrc.yaml file with smart defaults based on your project structure.
Create Your First Release
Here's how to create your first release with rlsy:
# 1. Make sure your working directory is clean
git status
# 2. Run rlsy
rlsy
# 3. Follow the interactive prompts:
# - Select version type (patch/minor/major)
# - Review and edit the generated changelog in your editor
# - Confirm the releaseThat's it! rlsy will:
- Update all version files
- Create an annotated git tag
- Push changes to remote
- Create a GitLab release
Preview changes first (recommended)
# Preview what rlsy will do without making any changes
rlsy --dry-runUsage
Basic Commands
# Initialize configuration (first time setup)
rlsy init
# Initialize with auto-detected defaults
rlsy init --yes
# Create a release (interactive)
rlsy
rlsy release
# Preview changes without executing
rlsy --dry-run
# Check the changelog, e.g. before committing or in CI
rlsy lint
rlsy lint docs/CHANGELOG.md
# Use custom configuration file
rlsy --config .rlsy/production.yaml
# Release with notes prepared beforehand (by you or an assistant)
rlsy --notes-file release-notes.md
# Enable verbose logging for debugging
rlsy --verbose
# Combine options
rlsy --dry-run --verboseCommand-Line Options
| Option | Alias | Description |
|--------|-------|-------------|
| --dry-run | -d | Preview all changes without executing them |
| --verbose | -v | Enable verbose logging for debugging |
| --config <path> | -c | Specify custom config file path |
| --notes-file <path> | | Use release notes from a file instead of generating them and opening the editor |
| --yes | -y | Use defaults without prompts (init command) |
| --force | -f | Force overwrite existing config (init command); write the changelog despite lint errors (release) |
| --help | -h | Show help information |
| --version | | Show rlsy version |
Init Command
The rlsy init command helps you set up rlsy configuration interactively:
# Interactive setup with prompts
rlsy init
# Auto-accept detected defaults
rlsy init --yes
# Overwrite existing config without confirmation
rlsy init --force
# Preview configuration without writing
rlsy init --dry-runWhat it does:
- Detects your project structure (git repository, Helm charts, package.json)
- Identifies version files automatically
- Prompts for configuration preferences
- Creates
.rlsyrc.yamlwith smart defaults - Validates configuration before writing
Auto-detected settings:
- Git repository and remote URL
- Helm charts in
helm/directory package.jsonversion field- Current branch and version
- Potential version files (README.md, Dockerfile, etc.)
The init command is optional - rlsy works without configuration using intelligent defaults. Use it when you want to customize behavior or version file updates.
Configuration
Configuration File
rlsy looks for configuration in the following locations (in order):
.rlsyrc.yaml(repository root).rlsy/config.yaml
Configuration is optional - rlsy works with zero configuration using intelligent defaults.
Basic Configuration Example
# Project configuration
project:
enabled: true
tagFormat: v{version}
# Changelog configuration
changelog:
file: CHANGELOG.md
# Git configuration
git:
pushTags: true
pushCommits: true
# GitLab configuration
gitlab:
createRelease: true
releaseBranch: mainComplete Configuration Example
See .rlsyrc.example.yaml for a complete configuration example with all available options.
Configuration Options
Project Configuration
project:
enabled: true
tagFormat: v{version}
versionFiles:
- file: package.json
jsonPath: version
- file: VERSION
type: plain
- file: README.md
pattern: 'Version\s+v([0-9.]+)'
replacement: Version v{version}enabled- Enable/disable project versioning (default:true)tagFormat- Git tag format template (default:v{version})versionFiles- Array of files to update with the project version
Helm Configuration
helm:
enabled: true
autoDetect: true
directory: helm
charts:
- name: my-app
path: helm/my-app
tagFormat: "{name}-{version}"
versionFiles:
- file: helm/my-app/values.yaml
yamlPath: image.tagenabled- Enable/disable Helm chart support (default:true)autoDetect- Automatically detect Helm charts (default:true)directory- Base directory to scan for charts (default:helm)charts- Array of explicit chart configurations
Changelog Configuration
changelog:
file: CHANGELOG.md
lint: false
includeMergeCommits: false
smartMergeDetection: true
commitTypes:
add: Added
fix: Fixed
change: Changed
remove: Removed
security: Securityfile- Changelog file path (default:CHANGELOG.md)lint- Lint the changelog before a release writes it (default:false, see Changelog Linting)includeMergeCommits- Include merge commits in changelog (default:false)smartMergeDetection- Filter out generic merge commits (default:true)commitTypes- Map commit prefixes to changelog sections (commits that don't match are filtered out)
Branch Configuration
branches:
stable:
pattern: stable-*
allowNonPatch: false
confirmOverride: truestable.pattern- Glob pattern for stable branchesstable.allowNonPatch- Allow minor/major versions on stable branchesstable.confirmOverride- Prompt before allowing non-patch versions
Git Configuration
git:
pushTags: true
pushCommits: truepushTags- Automatically push tags after creationpushCommits- Automatically push commits after creation
Note: A clean working directory is always required (not configurable).
GitLab Configuration
gitlab:
createRelease: true
releaseBranch: maincreateRelease- Create GitLab release via glab (default:true)releaseBranch- Branch to create release from (default:main)
Workflow
rlsy follows a structured 5-phase workflow:
Phase 1: Environment Validation
- Verify git repository exists and has remote configured
- Check working directory is clean (no uncommitted changes)
- Verify
$EDITORis set (normal mode only)
Phase 2: Configuration & Discovery
- Load configuration file (if exists)
- Auto-detect or configure Helm charts
- Determine last release version from git tags
- Interactive tag selection if needed (multiple tags, ambiguous versions)
Phase 3: Version Selection
- Prompt for new version with options:
- Patch (e.g., 1.2.3 → 1.2.4) - Bug fixes
- Minor (e.g., 1.2.3 → 1.3.0) - New features, backward compatible
- Major (e.g., 1.2.3 → 2.0.0) - Breaking changes
- Pre-release (e.g., 1.2.3 → 1.3.0-alpha.1) - Alpha, beta, rc versions
- Custom - Enter any valid semver version
- Validate semver format
- Apply stable branch restrictions if applicable
Phase 4: Changelog Curation
- Generate changelog draft from git commits since last version
- If
## [Unreleased]has entries, start the draft from them (see Hand-Written Entries) - Categorize commits into Keep a Changelog sections:
- Added - New features
- Changed - Changes to existing functionality
- Deprecated - Soon-to-be removed features
- Removed - Removed features
- Fixed - Bug fixes
- Security - Security fixes
- Open changelog in
$EDITORfor manual curation - User edits, reorganizes, and enhances the changelog
- Save and close editor to continue
- If the edit removed the
## [x.y.z] - dateheading, rlsy puts it back - With
changelog.lint: true, lint the changelog as the release would write it; problems the release introduces stop it until you edit the notes again, commit anyway, or cancel
In dry-run mode: Display generated changelog to stdout (no editor)
Phase 5: Release Execution
In normal mode:
- Update version files (package.json, Chart.yaml, etc.)
- Update CHANGELOG.md with curated changelog: the new version takes the place of the
[Unreleased]entries, leaving an empty## [Unreleased]heading above it - Create git commit with message:
chore: release v{version} - Create annotated git tags with release notes
- Publish to npm (if enabled and package.json exists, with confirmation)
- Push commits and tags to remote (with confirmation)
- Create GitLab/GitHub release with curated changelog
Note: The post-commit hook runs between steps 3 and 4 and may rewrite the release commit (for example git commit --amend to fold in generated files). rlsy announces the commit before the hook runs, then re-reads HEAD afterwards and announces the new sha if the hook changed it. The tag and the returned commit are the post-hook ones.
In dry-run mode:
- Display file changes as unified diffs
- Show git operations (commit message, tags)
- Show npm publishing preview (package name, version, files)
- Display remote operations (push commands)
- Show GitLab/GitHub release details
- No actual changes made
Version File Updates
rlsy can automatically update version numbers in multiple files across your project.
Automatic Updates
Without any configuration, rlsy automatically detects and updates:
package.json- Updates theversionfieldChart.yaml(Helm) - UpdatesversionandappVersionfields
Update Strategies
rlsy supports four strategies for updating version files:
1. JSON Path Updates
Update specific fields in JSON files:
- file: package.json
jsonPath: version2. YAML Path Updates
Update specific fields in YAML files:
- file: config.yaml
yamlPath: app.versionSupports nested paths with dot notation (e.g., metadata.version).
3. Pattern-Based Updates (Regex)
Use regex to find and replace version strings in any file:
- file: README.md
pattern: 'Version\s+v([0-9.]+)'
replacement: Version v{version}pattern- Regex with capture group 1 for the versionreplacement- Template with{version}placeholder
4. Plain Text Updates
Replace entire file content with version string:
- file: VERSION
type: plainCommon Use Cases
Update version in README badge
- file: README.md
pattern: 'badge\/version-([0-9.]+)-'
replacement: badge/version-{version}-Update Dockerfile version label
- file: Dockerfile
pattern: 'LABEL version="([^"]+)"'
replacement: 'LABEL version="{version}"'Update version constant in source code
- file: src/version.js
pattern: 'export const VERSION = ["'']([^"'']+)["'']'
replacement: "export const VERSION = '{version}'"Update Helm values.yaml image tag
- file: helm/my-app/values.yaml
yamlPath: image.tagUpdate multiple version references in same file
Configure multiple entries for the same file:
- file: README.md
pattern: 'Version:\s*v([0-9.]+)'
replacement: 'Version: v{version}'
- file: README.md
pattern: 'download\/v([0-9.]+)\/'
replacement: download/v{version}/Changelog Generation
rlsy generates changelogs following the Keep a Changelog format.
Commit Message Conventions
rlsy recognizes multiple commit message formats:
Keep a Changelog Style (Recommended)
Add: user authentication with OAuth2
Added rate limiting middleware
Fix: memory leak in connection pool
Fixed race condition in cache
Change: database pooling strategy
Remove deprecated APINote: Commits with colons (Add:, Fix:) have the prefix removed in the changelog. Commits without colons keep the full message.
Commit Categorization
Commits are automatically categorized into changelog sections:
| Commit Prefix | Changelog Section | Examples |
|--------------|------------------|----------|
| add, added | Added | New features |
| fix, fixed | Fixed | Bug fixes |
| change, changed | Changed | Modifications |
| remove, removed, delete, deleted | Removed | Removed features |
| deprecate, deprecated | Deprecated | Deprecations |
| security, sec | Security | Security fixes |
| breaking, break | Changed | Breaking changes |
| Everything else | Filtered out | Not in changelog |
Features:
- Case-insensitive matching
- Works with or without colons (
Fix:orFix) - Handles present and past tense (
AddorAdded) - Automatically capitalizes changelog entries
- Unrecognized commits are filtered out (e.g.,
feat:,chore:,Update,refactor:)
Hand-Written [Unreleased] Entries
Some changes deserve more than a commit subject. Write them under ## [Unreleased] while you
develop, in the usual Keep a Changelog sections:
## [Unreleased]
### Added
- **Booking pages carry an accent colour.** An owner picks one colour, and the page derives
its highlights and buttons from it.At release time rlsy builds the draft from these entries, kept exactly as written, and:
- drops the generated line of every commit since the last tag that changed the
[Unreleased]section, since the hand-written entry already describes it; - appends a commit's short hash to an entry when that one commit wrote all of it;
- lists the remaining commits below the entries, inside an
rlsy:commitscomment block. Move a line above the block to keep it; the block itself is dropped when you save.
rlsy also warns when commits since the last tag edited an already released version: those lines
reach no release's notes. Without [Unreleased] entries, the draft is generated from commits
alone, as before.
Release Notes Prepared Outside rlsy
--notes-file <path> skips generation and the editor and releases the file's notes as they
are. This suits notes written beforehand, for example by an AI assistant running next to rlsy:
rlsy --dry-run --notes-file release-notes.md # preview exactly what would be written
rlsy --notes-file release-notes.mdThe ## [x.y.z] - date heading is optional; if the file has one, its version must match the
version being released, so a file left over from an earlier release fails instead of being
reused. An rlsy:commits block copied from a draft is dropped. $EDITOR is not needed.
Merge Commit Handling
By default, merge commits are excluded from changelogs. Enable them with:
changelog:
includeMergeCommits: true
smartMergeDetection: trueWith smartMergeDetection: true, generic merge commits are filtered out:
- ✗ Skip:
Merge branch 'main' - ✓ Include:
Merge pull request #123: Add user authentication
Customizing Commit Types
Add your own commit type mappings:
changelog:
commitTypes:
docs: Documentation
style: Changed
test: Testing
build: ChangedChangelog Linting
Run the checks at any time with rlsy lint [file]; it exits 1 when it finds errors, so it also
fits a CI job or a pre-commit hook. To have every release lint CHANGELOG.md as it would be
written, before anything is committed, switch it on:
changelog:
lint: true| Rule | Severity | Finds |
|------|----------|-------|
| release-heading | error | A ## heading that is neither [Unreleased] nor [x.y.z] - YYYY-MM-DD |
| duplicate-release | error | The same version, or [Unreleased], twice |
| unreleased-position | error | [Unreleased] below a release |
| duplicate-section | error | The same ### section twice in one release |
| unknown-section | error | A ### section Keep a Changelog does not define |
| conflict-marker | error | Leftover <<<<<<<, ======= or >>>>>>> lines |
| commit-block | error | A leftover rlsy:commits block |
| keep-a-changelog | error | Anything else the keep-a-changelog parser rejects |
| unreleased-not-empty | error | Entries still under [Unreleased] (release only) |
| empty-section | warning | A ### section without entries |
| release-order, date-order | warning | Releases or dates out of order |
| missing-link | warning | A release without a link definition, once the file uses them |
| released-edited | warning | Commits since the last tag that edited a released version (rlsy lint only) |
During a release only the errors the release introduces stop it; problems the file already had
are counted and left for rlsy lint. rlsy then asks whether to edit the notes again (or re-read
the --notes-file), commit anyway, or cancel. --force writes the changelog without asking,
and dry-run reports without asking.
Helm Chart Support
rlsy has first-class support for Helm charts with independent versioning.
Auto-Detection
rlsy automatically detects Helm charts by scanning for:
helm/directory (configurable)Chart.yamlfiles
Independent Versioning
Helm charts and projects can have independent versions:
- Chart version - Helm chart release version (
Chart.yaml→version) - App version - Application version being deployed (
Chart.yaml→appVersion)
During release, you'll be prompted for:
- Helm chart version (e.g.,
2.1.0) - Project version (e.g.,
1.5.3)
The Chart.yaml is updated with both:
apiVersion: v2
name: my-app
version: 2.1.0 # Chart version (user-selected)
appVersion: "1.5.3" # Project version (tracks app)Multiple Helm Charts
rlsy supports multiple Helm charts in a single repository:
helm:
charts:
- name: frontend
path: helm/frontend
tagFormat: "{name}-{version}"
- name: backend
path: helm/backend
tagFormat: "{name}-{version}"Each chart is versioned independently with its own git tag.
Helm-Only Projects
For projects that only contain Helm charts (no separate application):
project:
enabled: false
helm:
enabled: trueIn this mode, Chart.yaml appVersion will match the chart version.
Chart-Specific Version Files
Update additional files with the Helm chart version:
helm:
charts:
- name: my-app
path: helm/my-app
versionFiles:
- file: helm/my-app/README.md
pattern: 'Chart Version:\s*`([^`]+)`'
replacement: 'Chart Version: `{version}`'
- file: helm/my-app/values.yaml
yamlPath: image.tagThese files are updated with the Helm chart version (not project version).
NPM Publishing
rlsy can publish your package to npm as part of the release workflow. Two switches control it:
npm.enabled(defaulttrue) runs the npm step at all. A release checks authentication, write access and whether the version is already on npm, and reports what it finds.npm.publish(defaultfalse) lets the release actually publish, after asking.
So by default a release only checks, and a failed check is a warning, never a reason to stop the release. To publish from rlsy:
npm:
publish: trueAuto-Detection
rlsy looks for package.json in your repository root. With npm.publish: true it asks
whether to publish during the release.
Package Manager Support
rlsy supports npm, yarn, and pnpm with automatic detection from lock files:
pnpm-lock.yaml→ uses pnpmyarn.lock→ uses yarn (handles both 1.x and 2+ versions)package-lock.json→ uses npm- No lock file → defaults to npm
All publishing operations use the detected package manager automatically.
Smart Publishing Decision
rlsy intelligently decides when to prompt for publishing:
- Private packages (
"private": truein package.json) → Skip publishing - Package exists on npm AND user has write access → Prompt to publish
- Package doesn't exist → Ask if you want to publish (first release)
- No write access → Skip publishing with clear message
Pre-Publish Validation
Before publishing, rlsy validates:
- ✓ Authentication via
npm whoami(oryarn whoami,pnpm whoami) - ✓ Version doesn't already exist on registry
- ✓ Package name is valid (including scoped packages like
@scope/package) - ✓ User has write access to the package
Publishing Workflow
When you run rlsy, the publishing happens in this order:
- Update version files (package.json, etc.)
- Create git commit and tags
- Publish to npm (if enabled and confirmed)
- Push to git remote
- Create GitLab/GitHub release
Why publish before push? This order makes error recovery easier. If publishing fails, you can fix the issue and retry without having already pushed tags to git.
Configuration
npm:
enabled: true # Run the npm checks during releases (default: true)
publish: true # Publish after the checks, when confirmed (default: false)
validateAuth: true # Check authentication early (default: true)
checkExisting: true # Check if package exists on registry (default: true)
previewContents: true # Show files in dry-run (default: true)
continueOnError: false # Abort on publish failure (default: false)
tag: latest # npm dist-tag (default: 'latest')Distribution Tags
Use npm distribution tags to publish pre-releases:
npm:
tag: next # For pre-releaseslatest- Stable releases (default)next- Pre-releases, beta versionsbeta- Beta releases- Custom tags for your workflow
Authentication
rlsy uses your existing package manager authentication:
# npm
npm login
# yarn
yarn login
# pnpm
pnpm loginFor CI/CD, use the NPM_TOKEN environment variable:
# .gitlab-ci.yml or GitHub Actions
export NPM_TOKEN=your-token-hereDry-Run Preview
In dry-run mode, rlsy shows what would be published:
rlsy --dry-runOutput includes:
- Package name and version
- Registry URL
- Files that would be published (from
npm pack --dry-run) - Publish command that would run
- Any warnings or restrictions
Scoped Packages
rlsy automatically handles scoped packages (@scope/package-name) and sets the correct access level based on your publishConfig in package.json:
{
"name": "@myorg/my-package",
"publishConfig": {
"access": "public"
}
}Skipping Publishing
Leave npm.publish unset and a release only runs the checks. Set npm.enabled: false, or
mark the package "private": true, and rlsy does not touch npm at all. With publishing on,
answer "No" when prompted to skip it for one release.
Publishing from CI
To publish from a pipeline instead, for example with npm trusted publishing, leave
npm.publish off and let a job run on the tag rlsy pushes. rlsy itself works that way: the
publish component of openxchange/ci/nodejs
publishes when a x.y.z tag arrives. package.json already carries the new version at that point, since rlsy writes
it into the release commit.
Error Handling
If publishing fails, rlsy provides clear, actionable error messages:
- Not authenticated: "Run
npm loginto authenticate" - Version already exists: "Version 1.2.3 already published. Use a different version."
- No permissions: "You don't have write access to this package"
- Network errors: "Failed to reach npm registry. Check your connection."
GitLab Integration
rlsy uses the GitLab CLI (glab) to create releases.
Setup
- Install glab:
# macOS
brew install glab
# Linux
# See: https://gitlab.com/gitlab-org/cli#installation- Authenticate:
glab auth loginRelease Creation
When you run rlsy, it will automatically:
- Create annotated git tags
- Push tags to remote
- Create a GitLab release with:
- Release title:
Release v{version} - Release notes: Your curated changelog
- Associated tag: Project version tag
- Branch: Configured release branch (default:
main)
- Release title:
Configuration
gitlab:
createRelease: true
releaseBranch: mainDisable GitLab release creation:
gitlab:
createRelease: falseDry-Run Mode
Dry-run mode lets you preview all changes before executing them. This is perfect for:
- Verifying changes before release
- Testing configuration
- CI/CD pipeline validation
- Learning how rlsy works
Usage
rlsy --dry-runWhat Gets Displayed
1. Configuration Summary
📋 Configuration
Config: .rlsyrc.yaml
Branch: main
Current Version: v1.2.32. Proposed Versions
🎯 Proposed Versions
Project: v1.3.0 (minor)
Helm Chart (my-app): 1.3.03. Generated Changelog
📝 Generated Changelog
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
## [1.3.0] - 2025-10-07
### Added
- User authentication with OAuth2
- Rate limiting middleware
### Fixed
- Memory leak in connection pool
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━When the draft starts from [Unreleased] entries, a summary before it lists how many entries
were taken over and which commits were dropped as covered.
4. File Changes (Unified Diffs)
📄 File Changes
--- package.json
+++ package.json
@@ -1,5 +1,5 @@
{
"name": "my-app",
- "version": "1.2.3",
+ "version": "1.3.0",
"description": "..."
}5. Git Operations
🏷️ Git Operations
Commit:
Message: "chore: release v1.3.0"
Files:
- package.json
- CHANGELOG.md
Annotated Tags:
- v1.3.0 (project)
Message: "Release v1.3.0..."6. Remote Operations
🚀 Remote Operations
Push:
Branch: main
Tags: v1.3.0
Remote: origin
GitLab Release:
Title: "Release v1.3.0"
Tag: v1.3.0Dry-Run Behavior
In dry-run mode:
- ✓ All validation checks are performed
- ✓ Changelog is generated and displayed (no editor)
- ✓ File diffs are shown
- ✗ No files are modified
- ✗ No git commits or tags are created
- ✗ Nothing is pushed to remote
- ✗ No GitLab releases are created
Examples
Example 1: Node.js Project
A typical Node.js project with automated releases:
Project Structure:
my-app/
├── package.json
├── CHANGELOG.md
├── src/
└── .rlsyrc.yamlConfiguration (.rlsyrc.yaml):
project:
enabled: true
tagFormat: v{version}
versionFiles:
- file: package.json
jsonPath: version
changelog:
file: CHANGELOG.mdUsage:
# Create a release
rlsy
# Preview first
rlsy --dry-runExample 2: Helm Chart Only
A project containing only Helm charts:
Project Structure:
helm-charts/
├── helm/
│ └── my-app/
│ ├── Chart.yaml
│ └── values.yaml
├── CHANGELOG.md
└── .rlsyrc.yamlConfiguration (.rlsyrc.yaml):
project:
enabled: false
helm:
enabled: true
autoDetect: true
directory: helmExample 3: Combined Project with Helm Charts
A Node.js application with Helm chart deployment:
Project Structure:
full-stack-app/
├── package.json
├── src/
├── helm/
│ └── my-app/
│ ├── Chart.yaml
│ └── values.yaml
├── Dockerfile
├── CHANGELOG.md
└── .rlsyrc.yamlConfiguration (.rlsyrc.yaml):
project:
enabled: true
versionFiles:
- file: package.json
jsonPath: version
- file: Dockerfile
pattern: 'LABEL version="([^"]+)"'
replacement: 'LABEL version="{version}"'
helm:
enabled: true
charts:
- name: my-app
path: helm/my-app
versionFiles:
- file: helm/my-app/values.yaml
yamlPath: image.tagWorkflow:
- Run
rlsy - Select Helm chart version (e.g.,
2.1.0) - Select project version (e.g.,
1.5.3) - Edit changelog in your editor
- Confirm and release
Result:
Chart.yaml→version: 2.1.0,appVersion: "1.5.3"package.json→version: "1.5.3"values.yaml→image.tag: "1.5.3"(chart version used)Dockerfile→LABEL version="1.5.3"- Git tags:
v1.5.3andmy-app-2.1.0
Example 4: NPM Package Publishing
Publish a Node.js package to npm with automated versioning:
Project Structure:
my-npm-package/
├── package.json
├── src/
├── tests/
├── CHANGELOG.md
└── .rlsyrc.yamlConfiguration (.rlsyrc.yaml):
project:
enabled: true
tagFormat: v{version}
versionFiles:
- file: package.json
jsonPath: version
npm:
enabled: true
publish: true
tag: latest
git:
pushTags: true
pushCommits: true
gitlab:
createRelease: trueWorkflow:
# Preview the release (including what would be published)
rlsy --dry-run
# Create release and publish
rlsyWhat happens:
- Prompts for version (e.g., 1.2.3 → 1.3.0)
- Generates and opens changelog in editor
- Updates
package.jsonversion - Creates git commit:
Release 1.3.0 - Creates git tag:
v1.3.0 - Publishes to npm using detected package manager
- Pushes commits and tags to remote
- Creates GitLab release
Package managers:
- With
pnpm-lock.yaml→ runspnpm publish - With
yarn.lock→ runsyarn publish(ornpm publishfor yarn 2+) - With
package-lock.json→ runsnpm publish
Example 5: Multiple Version Files
Update version across multiple files:
Configuration (.rlsyrc.yaml):
project:
versionFiles:
- file: package.json
jsonPath: version
- file: VERSION
type: plain
- file: README.md
pattern: 'Version\s+v([0-9.]+)'
replacement: Version v{version}
- file: src/version.ts
pattern: 'export const VERSION = ["'']([^"'']+)["'']'
replacement: "export const VERSION = '{version}'"
- file: docs/installation.md
pattern: 'download\/v([0-9.]+)\/'
replacement: download/v{version}/Troubleshooting
Working Directory Not Clean
Error:
Error: Working directory has uncommitted changesSolution: Commit or stash your changes before running rlsy:
# Commit changes
git add .
git commit -m "Your commit message"
# Or stash changes
git stash$EDITOR Not Set
Error:
Error: $EDITOR environment variable is not setSolution:
Set your preferred editor, or pass the notes with --notes-file so no editor is needed:
# Temporarily
export EDITOR=vim
# Permanently (add to ~/.bashrc or ~/.zshrc)
echo 'export EDITOR=vim' >> ~/.bashrcChangelog Has Problems
Error:
🔎 Changelog Lint
✖ error CHANGELOG.md:14 "### Added" appears twice in [1.3.0] (first on line 10) (duplicate-section)Solution:
Choose Edit the notes again and merge the sections. Line numbers refer to CHANGELOG.md as
the release would write it. To release anyway, choose Commit anyway or pass --force.
glab Not Authenticated
Error:
Error: glab authentication requiredSolution: Authenticate with GitLab:
glab auth loginNo Git Tags Found
Warning:
Warning: No previous version tags found, defaulting to 0.0.0Solution: This is normal for first release. rlsy will create the first tag.
Pattern Not Found in File
Error:
Error: Pattern not found in file: README.mdSolution: Check your regex pattern matches the actual file content:
# Test pattern (dry-run shows what will match)
rlsy --dry-run --verboseInvalid Semver Version
Error:
Error: Invalid semantic version: 1.2Solution:
Use valid semver format: MAJOR.MINOR.PATCH (e.g., 1.2.0)
FAQ
Can I use rlsy with GitHub?
Yes! rlsy supports both GitHub (via gh CLI) and GitLab (via glab CLI). The tool automatically detects your remote and uses the appropriate CLI tool. Both platforms can be enabled simultaneously if you have multiple remotes.
Does rlsy support yarn and pnpm for publishing?
Yes! rlsy automatically detects your package manager from lock files (pnpm-lock.yaml, yarn.lock, or package-lock.json) and uses the appropriate command for all operations including publishing. It supports npm, yarn (both 1.x and 2+), and pnpm.
Does rlsy work with monorepos?
Not yet. Monorepo support is planned for a future version.
Can I customize the changelog format?
The changelog follows Keep a Changelog format. You can customize commit type mappings, but the overall structure is fixed.
How do I skip the GitLab release?
Set gitlab.createRelease: false in your config:
gitlab:
createRelease: falseCan I automate rlsy in CI/CD?
Yes! Use dry-run mode for validation and pass responses via stdin for automation (note: CI/CD automation support is still experimental). rlsy exits non-zero when a release fails or is cancelled, so scripts can tell the outcome.
What happens if I abort during changelog editing?
If you exit the editor without saving, rlsy will prompt you to:
- Use the changelog as-is
- Edit again
- Cancel the release
Can I use a different changelog file location?
Yes, configure it:
changelog:
file: docs/CHANGELOG.mdHow do I version Helm charts independently from the app?
rlsy automatically prompts for both versions. The Helm chart version goes to Chart.yaml → version, and the app version goes to Chart.yaml → appVersion.
Development
Running Tests
# Run all tests
npm test
# Run with coverage
npm run test:coverage
# Watch mode
npm test -- --watchCode Quality
# Lint code
npm run lint
# Format code
npm run format
# Check formatting
npm run format:checkProject Structure
rlsy/
├── src/
│ ├── cli.js # Entry point, argument parsing
│ ├── commands/
│ │ ├── release.js # Main release command
│ │ └── lint.js # rlsy lint
│ ├── core/
│ │ ├── config.js # Configuration loading/validation
│ │ ├── git.js # Git operations wrapper
│ │ ├── gitlab.js # GitLab/glab operations
│ │ ├── helm.js # Helm chart detection/parsing
│ │ ├── version.js # Version detection/validation
│ │ ├── versionFiles.js # Version file updates
│ │ ├── changelog.js # Changelog generation/parsing
│ │ ├── changelogLint.js # Changelog lint rules
│ │ └── unreleased.js # [Unreleased] entries as the release draft
│ ├── utils/
│ │ ├── editor.js # Editor invocation
│ │ ├── prompts.js # User interaction
│ │ ├── validation.js # Input validation
│ │ └── display.js # Dry-run output formatting
│ └── templates/
│ └── changelog.js # Changelog template generation
├── tests/ # Test files
├── .rlsyrc.yaml # Example config
└── package.jsonContributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
License
MIT License - see LICENSE file for details
Credits
Created and maintained by the rlsy team.
Inspired by:
Support
- Issues: GitLab Issues
- Documentation: Full Documentation
Made with ❤️ by developers, for developers. Release made real easy.
