Automated release notes generator for GitLab and GitHub. Collects closed issues (or merged pull requests) between Git tags, categorizes them by label, and publishes formatted release notes.
- GitLab and GitHub support — works with both providers out of the box
- Issues or Pull Requests — generate notes from closed issues (default) or merged PRs (GitHub)
- Multi-client repos — filter by client label (e.g.,
mobile-v1.0.0,web-v2.0.0) - Single-client repos — just use
v<semver>tags - Configurable categories — map labels to sections (features, bugs, improvements, etc.)
- CI/CD integration — runs automatically on tag push via GitLab CI or GitHub Actions
- Strict/lenient modes — enforce labeling or allow uncategorized issues under "Other"
- Milestone detection — automatically links the most common milestone in release notes
npm install -g releasejet
# Interactive setup (detects provider from git remote)
releasejet init
# Preview release notes
releasejet generate --tag v1.0.0
# Generate and publish
releasejet generate --tag v1.0.0 --publishCreate .releasejet.yml in your project root (or run releasejet init):
provider:
type: github # 'gitlab' or 'github'
url: https://github.com
# GitHub-only: generate notes from issues or pull requests
source: issues # 'issues' (default) or 'pull_requests'
# For multi-client repos (omit for single-client)
clients:
- prefix: mobile
label: MOBILE
- prefix: web
label: WEB
categories:
feature: "New Features"
bug: "Bug Fixes"
improvement: "Improvements"
breaking-change: "Breaking Changes"
uncategorized: lenient # or "strict" to enforce labelingRun releasejet init and select CI setup, or add .github/workflows/release-notes.yml:
name: Release Notes
on:
push:
tags:
- '**'
jobs:
release-notes:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm install -g releasejet
- run: releasejet generate --tag "${{ github.ref_name }}" --publish
env:
RELEASEJET_TOKEN: ${{ secrets.RELEASEJET_TOKEN }}Set RELEASEJET_TOKEN as a repository secret (Settings > Secrets > Actions).
Add to your .gitlab-ci.yml (or run releasejet ci enable):
release-notes:
stage: deploy
image: node:20-alpine
rules:
- if: $CI_COMMIT_TAG
before_script:
- npm install -g releasejet
script:
- releasejet generate --tag "$CI_COMMIT_TAG" --publishSet GITLAB_API_TOKEN (or RELEASEJET_TOKEN) as a CI/CD variable with api scope.
Token resolution order:
RELEASEJET_TOKENenv var (works for both providers)- Provider-specific env var:
GITLAB_API_TOKENorGITHUB_TOKEN - Stored credentials from
~/.releasejet/credentials.yml
| Repo type | Format | Example |
|---|---|---|
| Multi-client | <prefix>-v<semver> |
mobile-v1.2.0 |
| Single-client | v<semver> |
v1.2.0 |
| Command | Description |
|---|---|
releasejet init |
Interactive setup wizard |
releasejet generate --tag <tag> |
Generate release notes |
releasejet generate --tag <tag> --publish |
Generate and publish release |
releasejet validate |
Check issues for proper labeling |
releasejet ci enable |
Add CI configuration to .gitlab-ci.yml |
releasejet ci disable |
Remove CI configuration |
| Flag | Description |
|---|---|
--publish |
Publish as a release on the provider |
--dry-run |
Preview without publishing |
--format <format> |
Output format: markdown (default) or json |
--config <path> |
Custom config file path |
--debug |
Show debug information |
ReleaseJet checks three sources in order: RELEASEJET_TOKEN env var, provider-specific env var (GITLAB_API_TOKEN or GITHUB_TOKEN), and ~/.releasejet/credentials.yml. Verify your token is set:
echo $RELEASEJET_TOKENTo reconfigure, run releasejet init.
The tag exists locally but hasn't been pushed. Push it first:
git push origin <tag>Tags must match v<semver> (e.g., v1.2.0) or <prefix>-v<semver> (e.g., mobile-v1.2.0). Suffixes like v1.2.0-beta are supported but the core version must be valid semver.
ReleaseJet includes issues closed between the previous tag and the current tag (by closedAt timestamp, not updatedAt). Check that:
- The issue is closed (not just merged)
- The close date falls within the tag window
- The issue has the correct client label (multi-client repos)
Use --debug to see the date range and which issues were filtered.
The API token doesn't have the required permissions. GitLab tokens need api scope. GitHub tokens need repo scope. Regenerate the token with the correct scope and update it via releasejet init or the RELEASEJET_TOKEN env var.
Pull request source is only supported for GitHub. GitLab projects must use source: issues (the default).
Run with --debug to see the loaded config:
releasejet generate --tag <tag> --debugInvalid values (e.g., uncategorized: "strictt") now produce clear error messages instead of being silently ignored.
MIT