Publish GitHub releases from the command line or Node.js. Reads defaults from package.json and CHANGELOG.md (keepachangelog format) so you rarely need to pass any flags. Ships two bins: releasearoni uses the GitHub API directly via @octokit/rest, and releasearoni-gh is a thin wrapper around the gh CLI.
npm install releasearoniBoth bins share the same flags and read the same defaults. Run either from a directory that contains package.json and CHANGELOG.md.
Uses @octokit/rest + ghauth for authentication. No gh CLI required.
Usage: releasearoni [options]
Example: releasearoni
--tag-name, -t Tag for this release
--target-commitish, -c Commitish value for tag
--name, -n Release title
--body, -b Release body text
--owner, -o Repo owner
--repo, -r Repo name
--draft, -d Publish as draft (default: false)
--prerelease, -p Publish as prerelease (default: false)
--workpath, -w Path to working directory (default: cwd)
--endpoint, -e GitHub API endpoint URL (default: https://api.github.com)
--assets, -a Comma-delimited list of assets to upload
--dry-run Preview release without creating it (default: false)
--no-upsert Fail if a release for this tag already exists (default: false)
--prompt Prompt for confirmation before publishing (default: false)
--no-npm-check Skip npm auth check before publishing (default: false)
--no-push Skip git push --follow-tags before publishing (default: false)
--no-build Skip npm run build even if a build script is present (default: false)
--major-branch After release, create or force-update the major version branch ref (e.g. v1) and push it — required for GitHub Actions consumers that pin to a major version (default: false)
--help, -h Show help
--version, -v Show version
releasearoni (v0.0.0)Delegates to gh release create. Requires the gh CLI to be installed and authenticated.
Usage: releasearoni-gh [options]
Example: releasearoni-gh
--tag-name, -t Tag for this release
--target-commitish, -c Commitish value for tag
--name, -n Release title
--body, -b Release body text
--owner, -o Repo owner
--repo, -r Repo name
--draft, -d Publish as draft (default: false)
--prerelease, -p Publish as prerelease (default: false)
--workpath, -w Path to working directory (default: cwd)
--endpoint, -e GitHub API endpoint URL (default: https://api.github.com)
--assets, -a Comma-delimited list of assets to upload
--dry-run Preview release without creating it (default: false)
--no-upsert Fail if a release for this tag already exists (default: false)
--prompt Prompt for confirmation before publishing (default: false)
--no-npm-check Skip npm auth check before publishing (default: false)
--no-push Skip git push --follow-tags before publishing (default: false)
--no-build Skip npm run build even if a build script is present (default: false)
--major-branch After release, create or force-update the major version branch ref (e.g. v1) and push it — required for GitHub Actions consumers that pin to a major version (default: false)
--help, -h Show help
--version, -v Show version
releasearoni-gh (v0.0.0)Both bins derive release defaults automatically:
| Field | Default source |
|---|---|
tag_name |
v + version from package.json |
name |
Same as tag_name |
body |
Latest versioned entry from CHANGELOG.md |
target_commitish |
Current HEAD commit SHA (git rev-parse HEAD) |
owner / repo |
Parsed from repository field in package.json |
draft |
false |
prerelease |
false |
endpoint |
https://api.github.com |
The CHANGELOG.md must be in keepachangelog format. Releases are blocked if an [Unreleased] section contains content.
If a release for the tag already exists (e.g. when re-running a failed publish), both bins will update the existing release in place rather than failing. Pass --no-upsert to get a hard failure instead, which is useful for enforcing that a tag is never accidentally re-released.
When publishing a GitHub Action, consumers typically pin to a major version ref rather than a specific tag:
- uses: my-org/my-action@v1 # receives v1.x.x updates automaticallyPass --major-branch to have releasearoni maintain that ref automatically after each release. After the GitHub release is created, it:
- Resolves the release tag to its exact commit SHA (
git rev-parse <tag>^{commit}) - Creates or hard-resets the major version branch (e.g.
v1) to that commit - Force-pushes the branch to origin
The major version is parsed from the release tag — v1.2.3 and 1.2.3 both produce v1.
{
"scripts": {
"prepublishOnly": "releasearoni --major-branch"
}
}This flag is a no-op for regular npm packages. It's only meaningful when the repository is consumed as a GitHub Action.
Checks whether you are logged in to npm. If not logged in and the CI environment variable is not set, runs npm login interactively. In CI, exits non-zero with an actionable error if not authenticated. Designed to run at the top of a prepublishOnly script so login issues are caught before any build, push, or release work has started.
Usage: releasearoni npm-checkTypical package.json setup:
{
"scripts": {
"prepublishOnly": "releasearoni"
}
}Generates CHANGELOG.md via auto-changelog and stages it with git add. Designed for use as the npm version lifecycle script.
Usage: releasearoni version [options]
--changelog, -c Changelog file to generate and stage (default: CHANGELOG.md)
--add, -a Additional files to stage after changelog (repeatable)
--breaking-pattern Regex for breaking changes (default: 'BREAKING CHANGE:')
--template auto-changelog template (default: keepachangelog)
--workpath, -w Working directory (default: cwd)
--help, -h Show helpTypical package.json setup — no separate auto-changelog install needed:
{
"scripts": {
"version": "releasearoni version",
"prepublishOnly": "releasearoni"
}
}Run npm version patch (or minor/major) and npm will:
- Bump the version in
package.json - Run
releasearoni version→ regeneratesCHANGELOG.mdand stages it - Commit and tag
Then npm publish triggers prepublishOnly, which checks npm auth, pushes the tag, and creates the GitHub release.
To stage extra files (e.g. a lock file your project manages separately):
"version": "releasearoni version --add package-lock.json"A complete package.json wired up for versioning and publishing via GitHub Actions:
releasearoni and releasearoni-gh are interchangeable in the scripts above — swap in releasearoni-gh if you prefer to delegate to the gh CLI.
A matching GitHub Actions workflow that triggers on manual dispatch:
# .github/workflows/release.yml
name: npm bump
on:
workflow_dispatch:
inputs:
version_type:
description: 'Version type'
type: choice
options: [major, minor, patch]
default: patch
required: true
permissions:
contents: write # required to push the version commit, tag, and create the GitHub release
id-token: write # required for OIDC publishing to npm (provenance)
jobs:
version_and_release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0 # fetch full history so things like auto-changelog work properly
- uses: actions/setup-node@v6
with:
node-version-file: package.json
- run: npm install
- run: npm test
- name: Configure git author
run: |
git config user.name "${{ github.actor }}"
git config user.email "${{ github.actor }}@users.noreply.github.com"
- name: npm version
run: npm version "${{ github.event.inputs.version_type }}"
- name: npm publish
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} # used by releasearoni to create the GitHub release
run: npm publishnpm version runs the version lifecycle script (changelog + commit + tag), then npm publish triggers prepublishOnly which pushes the tag and creates the GitHub release.
Authentication for the direct API bin is resolved in this order:
GH_TOKENGITHUB_TOKEN- Interactive GitHub device flow via
ghauth— opens a browser prompt, stores the token in the OS keychain for future runs. Press Enter at the device flow prompt to fall back to pasting a personal access token instead.
Programmatic release creation using @octokit/rest.
Create a GitHub release. Reads package.json and CHANGELOG.md from workpath to fill in defaults, then calls the GitHub Releases API.
import { createRelease } from 'releasearoni'
const release = await createRelease({
auth: { token: process.env.GITHUB_TOKEN },
workpath: process.cwd(), // optional, defaults to cwd
})
console.log(release.html_url)Options:
| Option | Type | Description |
|---|---|---|
auth |
{ token: string } |
Required. GitHub API token. |
workpath |
string |
Path to directory with package.json and CHANGELOG.md. Default: cwd. |
owner |
string |
Repo owner. Default: parsed from package.json. |
repo |
string |
Repo name. Default: parsed from package.json. |
tag_name |
string |
Tag to create. Default: v + package version. |
target_commitish |
string |
Branch or SHA for the tag. Default: current HEAD. |
name |
string |
Release title. Default: same as tag_name. |
body |
string |
Release body. Default: latest CHANGELOG entry. |
draft |
boolean |
Publish as draft. Default: false. |
prerelease |
boolean |
Mark as prerelease. Default: false. |
endpoint |
string |
GitHub API base URL. Default: https://api.github.com. |
assets |
string[] | {name, path}[] |
Files to upload as release assets. |
upsert |
boolean |
Update existing release if tag already exists. Default: true. Pass false to fail instead. |
Returns the GitHub release object from the API response.
- gh-release — the original CLI this was forked from
- gh CLI — official GitHub CLI used by
releasearoni-gh - keepachangelog — CHANGELOG format expected by releasearoni
- ghauth — OAuth token management used by
releasearoni
MIT
{ "name": "my-package", "version": "1.0.0", "repository": { "type": "git", "url": "git+https://github.com/my-org/my-package.git" }, "scripts": { // Runs during `npm version`: regenerates CHANGELOG.md and stages it // Use --add to stage additional files that should be part of the version commit "version": "releasearoni version --add dist/manifest.json --add src/generated/version.js", // Runs before `npm publish`: // 1. checks npm login / OIDC status // 2. runs `npm run build` if a build script is present // 3. pushes the version commit + tag to GitHub // 4. creates the GitHub release // Use releasearoni-gh instead if you prefer the gh CLI. "prepublishOnly": "releasearoni", // Clean up build artifacts after npm has published them "postpublish": "npm run clean" }, "devDependencies": { "releasearoni": "^0.1.0" } }