Skip to content

tx3stn/vrsn

Repository files navigation

vrsn

A single tool for all of your semantic versioning needs.

vrsn-demo

Contents

Why?

Language agnostic

You can run vrsn in a project in any (supported) language and it will work.

Currently supported version files:

File Languages
BUILD.bazel, MODULE.bazel Bazel
build.gradle, build.gradle.kts Java Kotlin
Cargo.toml Rust
CMakeLists.txt C++
package.json TypeScript JavaScript
pyproject.toml Python
setup.py Python
VERSION Go + more
git tags Git

Using a version file that isn't in the list? If you pass it explicitly with the --file flag, vrsn will attempt best effort matching: it looks for a string like version = X line, with single, double or no quotes. So a file like version.ts containing:

export const version = '0.0.10';

will work without any extra configuration.

Don't see your favourite version file type in that list? See the CONTRIBUTING guide for how to (easily) add support!

If you're the type of person that jumps between projects in different languages you don't need to remember the yarn or poetry commands for each different project, just use vrsn and get on with the important stuff.

Simple CI checks

Ensuring you properly version releases is important.

I've had to write semantic version checks in CI pipelines in different ways for different languages in different jobs. Now I can just use vrsn and not have to worry about solving the same problems again.

Install

Download from GitHub

Find the latest version for your system on the GitHub releases page.

Build it locally

If you have go installed, you can clone this repo and run:

make install

This will build the binary and then copy it to /usr/local/bin/vrsn so it will be available on your path. Nothing more to it.

Run the Docker container

Get the Docker container from the GitHub container registry.

docker pull ghcr.io/tx3stn/vrsn:latest

See Running in Docker for more details.

Use the CircleCI Orb

For ease of running checks in your CI this repo includes a CircleCI orb. Just import the orb:

orbs:
  vrsn: tx3stn/vrsn@volatile

Then use the check-version job in your workflow like:

workflows:
  build:
    jobs:
      - vrsn/check-version:
            filters:
              branches:
                ignore:
                  - main

For an example you can look at this repo's CircleCI config which uses the orb.

See the CircleCI orb docs for more specifics on how to customise the orb jobs to best suite your needs.

The orb is semantically versioned using the same number as the vrsn binary and Docker container, so you can pin a specific version in your CI config or use the volatile tag to always get the latest version of vrsn.

Commands

--help

Run vrsn --help for a full up to date usage guide to get started or vrsn [command] --help if you want help with a specific command.

check

Run vrsn check to automatically check versions on an existing git branch.

By default the check command can tell if you are on a branch that is not the base branch (i.e. main) and will compare the version file on your current branch with the version file on the base branch.

This command is super useful for running in CI, just run vrsn check, in your pull request CI and vrsn will tell you if the version has been properly bumped or not.

Name your base branch something other than main? You can use the --base-branch flag to specify the name you use.

Want to run it from somewhere other than the root of your git repo? You can use the --was and --now flags to pass in values from wherever you need to grab them:

vrsn check --was $(<function to get previous value>) --now $(<function to get current value>)

You can use the --file flag to point at a file that is not in the root of the git repo (like in a monorepo with independantly versioned services), e.g.:

vrsn check --file './services/service-name/VERSION'

bump

Run vrsn bump to increment the current version file. It will prompt you to select the bump type and then write the new valid semver version in your version file.

If you want to avoid the interactive picker you can pass the increment level as an argument to the bump command, e.g.:

vrsn bump patch

Want to automatically commit the version bump? Just use the --commit flag. 🙌

Don't like the default commit message? Provide your own custom one with --commit-msg.

vrsn bump minor --commit --commit-msg 'custom bump version commit message'

Want the new version in your message? The --commit-msg and --tag-msg options support Go template syntax with a {{.Version}} variable that resolves to the version being bumped to, e.g.:

vrsn bump minor --commit --commit-msg 'bump version to {{.Version}}'

You can use the --file flag to point at a file that is not in the root of the git repo (like in a monorepo with independantly versioned services), e.g.:

vrsn bump --file './services/service-name/VERSION'

This approach allows you to easily increment multiple versions in bulk, just write a script to iterate over each service that needs bumping and use the vrsn bump command. e.g.:

find ./services -type f -name 'VERSION' -exec vrsn bump patch --file {} \

Use git tags rather than a version file? Pass the --git-tag flag to read from the existing tags and write a new tag. e.g.:

vrsn bump --git-tag --tag-msg 'custom tag message'

Need a version file and a git tag? Combine the --git-tag flag with --file and --commit to bump the version in the file, commit it, and then tag that commit. e.g.:

vrsn bump patch --git-tag --file VERSION --commit

In this mode the version file is the source of truth for the current version, and the new version is used for both the file and the tag. The --commit option is required so the tag has a version bump commit to point at, you'll get an error without it.

get

Run vrsn get to print the current version. The version is printed on its own so it's easy to use in scripts, e.g.:

version=$(vrsn get)

By default the version is read using the same automatic version file detection as the other commands, and the usual flags let you read it from wherever you keep it.

Use the --file flag to read the version from a specific file:

vrsn get --file './services/service-name/VERSION'

Use git tags rather than a version file? Pass the --git-tag flag to get the latest tag (setting git-tag = true in the [bump] section of your config file works too):

vrsn get --git-tag

If you have multiple files configured in your config file, the version found in each file is printed on a separate line:

VERSION: 0.1.0
package.json: 0.1.0

Unlike check and bump, mismatched versions are printed as-is without erroring, so you can use vrsn get to see what's in each file. Use vrsn check if you want to validate them.

Accessible mode

The vrsn bump command with no arguments will spawn an interactive picker. You can set an ACCESSIBLE environment variable which will drop the TUI interactive selection in favour of a standard prompt that should work better with screen reader tools, e.g.:

ACCESSIBLE='true' vrsn bump

accessible mode

Setting defaults in a config file

If you always want vrsn to use specific flags, you can set default values for them in a config file. The following locations are checked in order of precedence, and the first config file found is used:

  1. The file passed with the --config flag
  2. vrsn.toml in the current directory (project level config)
  3. $XDG_CONFIG_HOME/vrsn.toml ($XDG_CONFIG_DIR is also still supported)
  4. $HOME/.config/vrsn.toml

Note: config files are not merged, so a project level vrsn.toml replaces your global config entirely rather than overriding individual options.

Flags passed on the command line always take precedence over the values in the config file, and any options missing from the config file fall back to the flag defaults.

An example config file can be found at ./.schema/vrsn.toml.

Use this file to always --commit by default or to always use your own custom --commit-msg.

The config file also supports a files option which works like the --file flag but accepts a list, so bump and check can operate on multiple version files that are kept in lockstep, e.g.:

files = ['VERSION', 'package.json']

All of the files must contain the same version, if they don't vrsn will error, and running with --verbose will log the version found in each file. When files is set in the config file it takes precedence over the --file flag.

The files option is optional and best suited to a project level vrsn.toml, since the list of version files is specific to each repository.

Running in Docker

To run vrsn in a docker container you just need to mount the repo as a volume, and vrsn can do it's thing, however git's safe.directory settings would prevent vrsn from being able to use it's git based smarts 🧠.

To deal with this a directory called /repo is set as a safe directory as part of the Docker build process, and is configured as the container's working directory so it's recommended you use that as the destination of the volume mount. e.g.:

docker run --rm -it -v $PWD:/repo vrsn:latest check

CI usage examples

To auto increment a version in a dependabot pull request so you don't need to manually do it:

  1. Configure a write access deploy key in CircleCI, as the bump version command will commit the version bump to the branch. You will need to pass the key fingerprint as a paramter to the bump-version job.
  2. Add a workflow job, filtered on branches that begin with dependabot, e.g.:
workflows:
  pull-request-build:
   jobs:
    - vrsn/bump-version:
       bump-type: patch
       ssh-key-fingerprint: fingerprint-of-your-key
       filters:
         branches:
           only:
             - /^dependabot\/.*/

Limitations

  • Pre-release and build metadata versions (e.g. 1.2.3-rc.1, 1.2.3+build.4) are not currently supported, versions must be plain major.minor.patch (with an optional v prefix).
  • When bumping multiple files in lockstep there is no rollback if updating one of the later files fails, any files already bumped stay bumped.