Awesome
<div align="center">cliff-jumper
A small CLI tool to create a semantic release and git-cliff powered Changelog
</div>Description
When managing a collection of projects you often want to follow a standard CHANGELOG template for all of them, but you also do not want to have to setup the release flow for every package. This is where cliff-jumper comes in.
How this works
cliff-jumper uses a combination of conventional-recommended-bump and git-cliff to bump your package using semantic versioning (following a variation of the Angular preset (seen here)). It will:
-
Perform preflight checks to verify that the tool can run
-
Resolve which bump strategy should be used by using conventional-recommended-bump
- If the CLI tool is ran inside a mono repo then only commits that affect the nested package will be considered!
-
Bump the version in your
package.json
usingnpm version
with the resolved strategy -
Validate that
-t
,--skip-tag
(CLI flags) weren't provided orskipTag
wasn't set totrue
in the config file -
Update the
CHANGELOG.md
(or a different file if configured through--changelog-prepend-file
) file using git-cliff -
If
--install
was provided (orinstall: true
set in the config file) then run theinstall
command of the package manager (npm install
,yarn install
, orpnpm install
) you used to call this CLI.- Important: when you install
@favware/cliff-jumper
globally this will always default tonpm
because of how NodeJS works. Therefore, if you wish for it to beyarn
ornpm
make sure to add it as dev dependency to your project and call it locally.
- Important: when you install
-
Stage the
package.json
andCHANGELOG.md
(or a different file if configured through--changelog-prepend-file
) files -
Commit the release
-
Tag the release
Installation
You can use the following command to install this package, or replace
npm install -D
with your package manager of choice.
npm install -D @favware/cliff-jumper
Or install it globally:
npm install -g @favware/cliff-jumper
Then call the script with cliff-jumper
or cj
:
cliff-jumper --name "my-package" --package-path "." # Add any other flags or use --help
cj --name "my-package" --package-path "." # Add any other flags or use --help
Alternatively you can call the CLI directly with npx
:
npx @favware/cliff-jumper --name "my-package" --package-path "." # Add any other flags or use --help
Usage
You can provide all options through CLI flags:
Usage: cliff-jumper [options]
Options:
-V, --version output the version number
-n, --name <string> The package name to release
-p, --package-path <string> The path to the current package. For non-monorepos this is just "."
--dry-run Whether the package should be bumped or not. When this is set no actions will be taken and only the release strategy will be logged
-sab, --skip-automatic-bump Whether to skip bumping the version (useful if this is the first version, or if you have manually set the version)
--mono-repo Whether the package to be bumped resides in a mono repo,
which enables Lerna-like scanning for what kind of version bump should be applied
Defaults to "true" when "org" is set, false otherwise
--no-mono-repo Whether the package to be bumped resides in a mono repo,
which enables Lerna-like scanning for what kind of version bump should be applied
Defaults to "true" when "org" is set, false otherwise
-o, --org <string> The NPM org scope that should be used WITHOUT "@" sign or trailing "/"
--preid [string] The "prerelease identifier" to use as a prefix for the "prerelease" part of a semver
--identifier-base <number> The base number (0 or 1) to be used for the prerelease identifier.
--no-identifier-base Do not use a base number for the prerelease identifier.
-c, --commit-message-template [string] A custom commit message template to use.
Defaults to "chore({{name}}): release {{full-name}}@{{new-version}}"
You can use "{{new-version}}" in your template which will be dynamically replaced with whatever the new version is that will be published.
You can use "{{name}}" in your template, this will be replaced with the name provided through "-n", "--name" or the same value set in your config file.
You can use "{{full-name}}" in your template, this will be replaced "{{name}}" (when "org" is not provided), or "@{{org}}/{{name}}" (when "org" is provided).
--tag-template [string] A custom tag template to use.
When "org" is provided this will default to "@{{org}}/{{name}}@{{new-version}}", for example "@favware/cliff-jumper@1.0.0"
When "org" is not provided this will default to "v{{new-version}}", for example "v1.0.0"
You can use "{{new-version}}" in your template which will be dynamically replaced with whatever the new version is that will be published.
You can use "{{org}}" in your template, this will be replaced with the org provided through "-o", "--org" or the same value set in your config file.
You can use "{{name}}" in your template, this will be replaced with the name provided through "-n", "--name" or the same value set in your config file.
You can use "{{full-name}}" in your template, this will be replaced "{{name}}" (when "org" is not provided), or "@{{org}}/{{name}}" (when "org" is provided).
-i, --install Whether to run npm install after bumping the version but before committing and creating a git tag. This is useful when you have a mono repo where bumping one package
would then cause the lockfile to be out of date.
--skip-changelog Whether to skip updating your changelog file
default "true" when CI=true, "false" otherwise
--no-skip-changelog Whether to skip updating your changelog file
default "true" when CI=true, "false" otherwise
-t, --skip-tag Whether to skip creating a git tag
default "true" when CI=true, "false" otherwise
--no-skip-tag Whether to skip creating a git tag
default "true" when CI=true, "false" otherwise
-cpf, --changelog-prepend-file [string] The file that git-cliff should use for the --prepend flag, defaults to ./CHANGELOG.md. This should be relative to the current working directory.
--github-repo The GitHub repository to use for linking to issues and PRs in the changelog.
You can pass the unique string "auto" to automatically set this value as {{org}}/{{name}} as provided from --org and --name
This should be in the format "owner/repo"
You can use the "GITHUB_REPO" environment variable to automatically set this value
--github-token A token to authenticate requests to the GitHub API. This is required when using the "--github-repo" option.
You can also set the one of the following environment variables.
- GITHUB_TOKEN
- GH_TOKEN
- TOKEN_GITHUB
- TOKEN_GH
The multiple options for the name of the environment are to aim to not conflict with other tooling that use similar tokens in case you want to use a unique token for
release management.
-pt, --push-tag Whether to push the tag to the remote repository.
This will simply execute "git push && git push --tags" so make sure you have configured git for pushing properly beforehand.
-npt, --no-push-tag Whether to push the tag to the remote repository.
This will simply execute "git push && git push --tags" so make sure you have configured git for pushing properly beforehand.
-ghr, --github-release Whether to create a release on GitHub, requires "--push-tag" to be enabled, otherwise there will be no tag to create a release from
For the repository the release is created on the value from "--github-repo" will be used
If the changelog section from git-cliff is empty, the release notes will be auto-generated by GitHub.
-nghr, --no-github-release Whether to create a release on GitHub, requires "--push-tag" to be enabled, otherwise there will be no tag to create a release from
For the repository the release is created on the value from "--github-repo" will be used
If the changelog section from git-cliff is empty, the release notes will be auto-generated by GitHub.
-ghrd, --github-release-draft Whether the release should be a draft
-ghrpr, --github-release-pre-release Whether the release should be a pre-release
-ghrl, --github-release-latest Whether the release should be marked as the latest release, will try to read this value, then the value of --github-release, and then default to false. Please note that
when setting --github-release-pre-release to `true` GitHub will prevent the release to be marked as latest an this option will essentially be ignored.
-ghrnt, --github-release-name-template [string] A GitHub release name template to use. Defaults to an empty string, which means GitHub will use the tag name as the release name.
You can use "{{new-version}}" in your template which will be dynamically replaced with whatever the new version is that will be published.
You can use "{{org}}" in your template, this will be replaced with the org provided through "-o", "--org" or the same value set in your config file.
You can use "{{name}}" in your template, this will be replaced with the name provided through "-n", "--name" or the same value set in your config file.
You can use "{{full-name}}" in your template, this will be replaced "{{name}}" (when "org" is not provided), or "@{{org}}/{{name}}" (when "org" is provided).
-v, --verbose Whether to print verbose information (default: false)
-h, --help display help for command
Or, you can set most of these options through a configuration file. This file
should be located at your current working directory (where you're calling this
package). It should be named .cliff-jumperrc
, optionally suffixed with
.json
, .yaml
, or .yml
.
Config file fields
--name
maps toname
--package-path
maps topackagePath
--dry-run
maps todryRun
--skip-automatic-bump
maps toskipAutomaticBump
--mono-repo
and--no-mono-repo
map tomonoRepo
--org
maps toorg
--preid
maps topreid
--identifier-base
and--no-identifier-base
map toidentifierBase
--commit-message-template
maps tocommitMessageTemplate
--tag-template
maps totagTemplate
--install
map toinstall
--skip-changelog
and--no-skip-changelog
map toskipChangelog
--skip-tag
and--no-skip-tag
map toskipTag
--changelog-prepend-file
maps tochangelogPrependFile
--github-repo
maps togithubRepo
--github-token
maps togithubToken
--push-tag
and--no-push-tag
map topushTag
--github-release
and--no-github-release
map togithubRelease
--github-release-draft
maps togithubReleaseDraft
--github-release-pre-release
maps togithubReleasePrerelease
--github-release-latest
maps togithubReleaseLatest
--github-release-name-template
maps togithubReleaseNameTemplate
--verbose
maps toverbose
When using .cliff-jumperrc
or .cliff-jumperrc.json
as your config file you
can also use the JSON schema to get schema validation. To do so, add the
following to your config file:
{
"$schema": "https://raw.githubusercontent.com/favware/cliff-jumper/main/assets/cliff-jumper.schema.json"
}
Alternatively you can reference the local schema in node_modules:
{
"$schema": "./node_modules/@favware/cliff-jumper/assets/cliff-jumper.schema.json"
}
Example JSON file:
{
"$schema": "https://raw.githubusercontent.com/favware/cliff-jumper/main/assets/cliff-jumper.schema.json",
"name": "my-package",
"packagePath": ".",
"verbose": true
}
Example YAML file:
name: my-package
packagePath: .
verbose: true
Default values
This library has opinionated defaults for its options. These are as follows:
--dry-run
will default toundefined
.--skipAutomaticBump
will default toundefined
.--org
will default toundefined
.--preid
will default toundefined
.--identifier-base
will default toundefined
. Alternatively, you can force this tofalse
by providing--no-identifier-base
.--install
will default toundefined
.--skip-changelog
will default tofalse
(true
whenCI
environment variable is'true'
). Alternatively you can force this to false by providing--no-skip-changelog
.--skip-tag
will default tofalse
(true
whenCI
environment variable is'true'
). Alternatively you can force this to false by providing--no-skip-tag
.--mono-repo
will default totrue
whenorg
is set, orfalse
when it's not. Alternatively you can force this to false by providing--no-mono-repo
.--commit-message-template
will default tochore({{name}}): release {{full-name}}@{{new-version}}
{{new-version}}
will be replaced with the new version that will be published{{name}}
will be replaced with the name provided through-n
,--name
or the same value set in your config file{{full-name}}
will be replaced with{{name}}
(whenorg
is not provided), or@{{org}}/{{name}}
(whenorg
is provided).
--tag-template
will default to{{full-name}}@{{new-version}}
(whenorg
is provided) orv{{new-version}}
(whenorg
is not provided){{new-version}}
will be replaced with the new version that will be published{{name}}
will be replaced with the name provided through-n
,--name
or the same value set in your config file{{org}}
will be replaced with the org provided through-o
,--org
or the same value set in your config file{{full-name}}
will be replaced with{{name}}
(whenorg
is not provided), or@{{org}}/{{name}}
(whenorg
is provided).
--changelog-prepend-file
will default to./CHANGELOG.md
.--github-repo
will default toundefined
.--github-token
will default toundefined
.--push-tag
will default tofalse
. Alternatively you can force this to false by providing--no-push-tag
.--github-release
will default tofalse
. Alternatively you can force this to false by providing--no-github-release
.--github-release-draft
will default tofalse
.--github-release-pre-release
will default tofalse
.--github-release-latest
will default totrue
.--github-release-name-template
will default to an empty string.--verbose
will default tofalse
.
Merging of config file, defaults and CLI provided flags
When you have a config file the options in the file are merged with the default options and with any other provided CLI flags. Which source takes highest priority depends on the type of the option. The priority is as follows (lower means it gets lower priority):
- CLI flags
- Default values
- Config file
This means that the CLI flags will always have the highest priority. This way you can have a config file for base options, then overwrite that with CLI flags, such as in a CI environment.
Creating a GitHub release
This package provides the options --push-tag
and --github-release
to
automatically create a release on GitHub using the output from git-cliff
as
the release notes. In order to use this feature you have to provide
--github-repo
and --github-token
(or set their respective environment
variables). Alternatively, if you want to run this step from a GitHub workflow
you can base your step on the following example.
It is very important that if your main branch is protected by branch protection
you have to provide a Personal Access Token (this can be both a classic or a
fine-grained one) for a user who can bypass branch protections as
token: ${{ secrets.YOUR_TOKEN_VAR }}
to actions/checkout
!
- name: Checkout Project
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: main
- name: Use Node.js v20
uses: actions/setup-node@v4
with:
node-version: 20
cache: yarn
- name: Configure Git
run: |
git remote set-url origin "https://${GITHUB_TOKEN}:x-oauth-basic@github.com/${GITHUB_REPOSITORY}.git"
git config --local user.email "${GITHUB_EMAIL}"
git config --local user.name "${GITHUB_USER}"
env:
GITHUB_USER: github-actions[bot]
GITHUB_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Bump Versions & Publish
run: npx @favware/cliff-jumper
env:
GITHUB_TOKEN: ${{ secrets.BOT_TOKEN }}
This will create a GitHub commit, release, and tag using the GitHub Actions bot
account. This ensures that you do not need a
Personal Access Token
to create a release. The GITHUB_TOKEN
secret is provided by GitHub Actions and
is a token that has the necessary permissions to create a release. It also be
noted that classic Personal Access Tokens will not even work for this, you will
at least need a
Fine-Grained Personal Access Token
which is at time of writing (2024-06-03) a beta feature. You can find more
information about there
here.
Lastly, the example above assumes a cliff-jumper config file similar to the one
in this repository (.cliff-jumperrc). As an alternative
example for a package that is not scoped by an npm/github org here is another
example. Replace the values in between <>
with your desired values.
name: <package-name>
packagePath: .
pushTag: true
githubRepo: <repo-owner>/<repo-name>
githubRelease: true
githubReleaseLatest: true
Example Configuration setups
Following are JSON examples of how you can configure this package based on different situations.
Scoped packages in a non-mono repo
This is for versioning @my-org/my-package
that does not reside in a mono
repo, for example sapphiredev/shapeshift
{
"name": "package-name",
"packagePath": ".",
"org": "my-org",
"monoRepo": false,
"commitMessageTemplate": "chore(release): release {{new-version}}",
"tagTemplate": "v{{new-version}}"
}
Scoped packages in a mono repo
This is for versioning @my-org/my-package
that resides in a mono repo, for
example sapphiredev/utilities
{
"name": "package-name",
"org": "my-org",
"packagePath": "packages/decorators"
}
Non-scoped packages in a non-mono repo
This is for versioning my-package
that does not reside in a mono repo, for
example
favware/esbuild-plugin-version-injector
{
"name": "my-package",
"packagePath": ".",
"commitMessageTemplate": "chore(release): release {{new-version}}",
"tagTemplate": "v{{new-version}}"
}
Non-scoped packages in a mono repo
This is for versioning my-package
that resides in a mono repo, for example
discord.js/discordjs
{
"name": "my-package",
"packagePath": "packages/discord.js",
"tagTemplate": "{{new-version}}"
}
Git Cliff commands executed
The following commands are executed by git-cliff after options are parsed, depending on the scenario:
In a regular repository
git cliff --tag "TAG_TEMPLATE_OPTION" --prepend ./CHANGELOG.md --unreleased --config ./cliff.toml
For example this could be:
git cliff --tag "@favware/cliff-jumper@1.0.0" --prepend ./CHANGELOG.md --unreleased --config ./cliff.toml
In a mono repository
git cliff --tag "TAG_TEMPLATE_OPTION" --prepend ./CHANGELOG.md --unreleased --config ./cliff.toml --repository RELATIVE_PATH_TO_REPOSITORY_ROOT --include-path "PACKAGE_PATH_OPTIONS/*"
For example this could be:
git cliff --tag "@sapphire/utilities@1.0.0" --prepend ./CHANGELOG.md --unreleased --config ./cliff.toml --repository ../../ --include-path "packages/utilities/*"
Buy us some doughnuts
Favware projects are and always will be open source, even if we don't get donations. That being said, we know there are amazing people who may still want to donate just to show their appreciation. Thank you very much in advance!
We accept donations through Ko-fi, Paypal, Patreon, GitHub Sponsorships, and various cryptocurrencies. You can use the buttons below to donate through your method of choice.
Donate With | Address |
---|---|
Ko-fi | Click Here |
Patreon | Click Here |
PayPal | Click Here |
GitHub Sponsors | Click Here |
Bitcoin | 1E643TNif2MTh75rugepmXuq35Tck4TnE5 |
Ethereum | 0xF653F666903cd8739030D2721bF01095896F5D6E |
LiteCoin | LZHvBkaJqKJRa8N7Dyu41Jd1PDBAofCik6 |
Contributors
Please make sure to read the Contributing Guide before making a pull request.
Thank you to all the people who already contributed to Sapphire!
<a href="https://github.com/favware/cliff-jumper/graphs/contributors"> <img alt="contributors" src="https://contrib.rocks/image?repo=favware/cliff-jumper" /> </a>