#version #semver #monorepo #git-version #yaml #command-line-tool #regex

app monoverse

A CLI tool for managing version numbers in monorepos

8 releases

0.1.7 Sep 10, 2024
0.1.6 May 23, 2024
0.1.5 Mar 28, 2024
0.1.2 Feb 28, 2024
0.1.0 Jan 29, 2024

#706 in Development tools

Download history 168/week @ 2024-09-09 24/week @ 2024-09-16 20/week @ 2024-09-23 7/week @ 2024-09-30

369 downloads per month

Apache-2.0

67KB
1.5K SLoC

monoverse

Crates.io Version Crates.io Total Downloads GitHub License

Introduction

Monoverse is a tool for managing application version numbering using the CalVer versioning scheme. It is designed to be used with monorepos, but it can also be used with single projects.

The reality for many projects is that they don't actually need to follow semantic versioning. For example, if you are building a web application with lots of microservices, you're generally not going to be publishing them as libraries. Instead, they'll be deployed as individual APIs that each have their own lifecycle.

CalVer is a simple versioning scheme that is based on the calendar. The monoverse implementation of CalVer follows the YY.MM.MICRO format, where YY is the current year, MM is the current month, and MICRO is a monotonically increasing number that is reset to 0 at the beginning of each month.

Ubuntu is a famous example of a project that uses (a variation of) CalVer. Just remember that it is not a replacement for semantic versioning. If you're building a library, you should probably stick to semantic versioning as going back from CalVer is not easy.

Installation

Cargo

Monoverse is written in Rust and as such it currently requires the Rust toolchain to be installed. The easiest way to install Rust is by using rustup.

Once you have Rust installed, you can install the latest published release of monoverse by running the following command:

cargo install monoverse

This will build the monoverse binary and install it in your ~/.cargo/bin directory, after which it can be used from anywhere.

You can also clone the repository and build the binary yourself with the following command:

cargo install --path .

Docker

Monoverse can also be used as a Docker container. The image is available on GitHub Container Registry.

docker pull ghcr.io/jannekem/monoverse:latest

You can run the container against a local repository by mounting it as a volume to the /repo directory in the container. Add the appropriate arguments to the monoverse command to run the desired subcommand. For example:

docker run --rm -v /path/to/repository:/repo ghcr.io/jannekem/monoverse:latest release <project-name>

The container includes git which makes it possible to run custom scripts that interact with the repository. This makes it easier to integrate monoverse into CI/CD pipelines when using tools like Tekton that support running Docker containers as build steps.

Configuration

Monoverse can be configured by defining a configuration file at the root of the project. The supported file formats are json, yaml and toml. The configuration file must be named monoverse.{json,yaml,toml}.

The configuration file defines the projects that are part of the monorepo. Each project is defined by a type and a path.

Projects

Applications are defined in the projects section of the configuration file.

Each project is represented by a key-value pair, where the key is the name of the project and the value is a map with the following keys:

Key Description Allowed values
type The type of the project. rust, node, helm, toml, versionfile, yaml
path The path to the project. Any valid directory path relative to the repository root. If omitted, the repository root is used instead.
manifest_path The path to the manifest file of the project. Any valid file path relative to the project root. If omitted, the manifest file is assumed to be located at the project path. Generic project types such as yaml require an explicit manifest path.
tag_prefix Prefix for tag creation. A string that will be prefixed to the version number when creating a new tag. Can be set to an empty string if no prefix is desired. Defaults to <project-name>-.
selector The selector for the version number. The format of the selector depends on the type of the project.
dependents The dependents of the project. A list of dependent files which should be updated when the project is released. For more information, see the Project dependents section.

Selector formats for project types that use the selector key:

Project type Selector format
toml Dot-separated path to the version number in the TOML file. For example: package.version
yaml Dot-separated path to the version number in the YAML file. For example: package.version

Project types:

  • rust: A Rust project with a Cargo.toml manifest file.
  • node: A Node.js project with a package.json manifest file.
  • helm: A Helm chart with a Chart.yaml manifest file.
  • toml: Any generic project with a TOML manifest file.
  • versionfile: Any generic project with a version file that only contains the version number.
  • yaml: Any generic project with a YAML manifest file.

Project dependents

Projects can also have dependents. This is useful when you have a project that is used by other projects or files in the repository.

When a project is released, its dependents will be updated with the new version number. Dependents are defined in the dependents section of the project configuration.

Dependent settings can contain the following keys:

Key Description Allowed values
type The type of the dependent. regex, toml, yaml
path The path to the dependent file. Any valid file path relative to the project root.
selector The selector for the version number in the dependent file. A selector for the version number in the dependent file. The format of the selector depends on the type of the dependent.
replace String to replace the selector match with. A format string to replace the selector match with. The format of the string depends on the type of the dependent.

Selector formats for different dependent types:

Dependent type Selector format
regex A regular expression that matches any text in the dependent file. Note that you will need to escape characters that would otherwise be interpreted by the YAML/TOML parsing. For example: v\\d+\\.\\d+\\.\\d+
toml Dot-separated path to the version number in the TOML file. For example: dependencies.server.version
yaml Dot-separated path to the version number in the YAML file. For example: dependencies.server.version

Replace formats for different dependent types:

Dependent type Replace format
regex A format string that replaces the matching text in the dependent file. Defaults to the new version string. For example: v{{version}}
toml N/A
yaml N/A

The replace string can contain the {{version}} placeholder, which will be replaced with the new version number when the project is released.

Example YAML configuration

projects:
  server:
    type: rust
    path: server
    dependents:
      - type: regex
        path: client/package.json
        selector: "\"server\": \".?\\d+\\.\\d+\\.\\d+\""
        replace: '"server": "{{version}}"'
      - type: toml
        path: dependency.toml
        selector: dependencies.server.version
  client:
    type: node
    path: client
  nginx:
    type: helm
    path: apps/nginx
    manifest_path: apps/nginx/deployment/Chart.yaml

Example TOML configuration

[projects.server]
type = "rust"
path = "server"

[[projects.server.dependents]]
type = "regex"
path = "client/package.json"
selector = "\"server\": \".?\\d+\\.\\d+\\.\\d+\""
replace = '"server": "{{version}}"'

[[projects.server.dependents]]
type = "toml"
path = "dependency.toml"
selector = "dependencies.server.version"

[projects.client]
type = "node"
path = "client"

[projects.nginx]
type = "helm"
path = "apps/nginx"
manifest_path = "apps/nginx/deployment/Chart.yaml"

Usage

After installing monoverse and creating a configuration file, you can use it to manage the version numbers of your projects.

Release

You can create a new version by running monoverse release command

monoverse release <project>

where <project> is the key of the project as defined in the configuration file.

Monoverse will then check if the project has been modified since the last release. If there are changes, it will craft a new version number and update the project's manifest file depending on its type. You can force a release by using the --force flag.

If the project has dependents, Monoverse will also update the dependent files with the new version number.

The manifest file must not have any uncommitted changes, or the release will fail.

The following arguments are also available:

  • -f, --force: Force a release even if the project has no changes.
  • --commit: Commit the changes to the repository.
  • --tag: Create a new tag in the repository, requires --commit. By default, the tag format is <project>-<version>. It can be customized by configuring the tag_prefix key in the configuration file for each project.

Next

You can also get the next version number without actually updating the project's manifest file by running the monoverse next command

monoverse next <project>

where <project> is the key of the project as defined in the configuration file. The program will then print the next version number to the standard output if a new release is required.

Set logging verbosity

By default, Monoverse will only print errors and warnings to stderr. You can increase the logging verbosity by using the -v or --verbose flag. This may be useful for debugging purposes.

If you want to suppress warnings and only print errors, you can use the -q or --quiet flag. You can also use the -qq flag to suppress both warnings and errors.

Dependencies

~18–28MB
~477K SLoC