• Stars
    star
    1,188
  • Rank 39,371 (Top 0.8 %)
  • Language
    Go
  • License
    MIT License
  • Created about 9 years ago
  • Updated 6 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Work with Semantic Versions in Go

SemVer

The semver package provides the ability to work with Semantic Versions in Go. Specifically it provides the ability to:

  • Parse semantic versions
  • Sort semantic versions
  • Check if a semantic version fits within a set of constraints
  • Optionally work with a v prefix

Stability: Active GoDoc Go Report Card

If you are looking for a command line tool for version comparisons please see vert which uses this library.

Package Versions

Note, import github.com/github.com/Masterminds/semver/v3 to use the latest version.

There are three major versions fo the semver package.

  • 3.x.x is the stable and active version. This version is focused on constraint compatibility for range handling in other tools from other languages. It has a similar API to the v1 releases. The development of this version is on the master branch. The documentation for this version is below.
  • 2.x was developed primarily for dep. There are no tagged releases and the development was performed by @sdboyer. There are API breaking changes from v1. This version lives on the 2.x branch.
  • 1.x.x is the original release. It is no longer maintained. You should use the v3 release instead. You can read the documentation for the 1.x.x release here.

Parsing Semantic Versions

There are two functions that can parse semantic versions. The StrictNewVersion function only parses valid version 2 semantic versions as outlined in the specification. The NewVersion function attempts to coerce a version into a semantic version and parse it. For example, if there is a leading v or a version listed without all 3 parts (e.g. v1.2) it will attempt to coerce it into a valid semantic version (e.g., 1.2.0). In both cases a Version object is returned that can be sorted, compared, and used in constraints.

When parsing a version an error is returned if there is an issue parsing the version. For example,

v, err := semver.NewVersion("1.2.3-beta.1+build345")

The version object has methods to get the parts of the version, compare it to other versions, convert the version back into a string, and get the original string. Getting the original string is useful if the semantic version was coerced into a valid form.

Sorting Semantic Versions

A set of versions can be sorted using the sort package from the standard library. For example,

raw := []string{"1.2.3", "1.0", "1.3", "2", "0.4.2",}
vs := make([]*semver.Version, len(raw))
for i, r := range raw {
    v, err := semver.NewVersion(r)
    if err != nil {
        t.Errorf("Error parsing version: %s", err)
    }

    vs[i] = v
}

sort.Sort(semver.Collection(vs))

Checking Version Constraints

There are two methods for comparing versions. One uses comparison methods on Version instances and the other uses Constraints. There are some important differences to notes between these two methods of comparison.

  1. When two versions are compared using functions such as Compare, LessThan, and others it will follow the specification and always include prereleases within the comparison. It will provide an answer that is valid with the comparison section of the spec at https://semver.org/#spec-item-11
  2. When constraint checking is used for checks or validation it will follow a different set of rules that are common for ranges with tools like npm/js and Rust/Cargo. This includes considering prereleases to be invalid if the ranges does not include one. If you want to have it include pre-releases a simple solution is to include -0 in your range.
  3. Constraint ranges can have some complex rules including the shorthand use of ~ and ^. For more details on those see the options below.

There are differences between the two methods or checking versions because the comparison methods on Version follow the specification while comparison ranges are not part of the specification. Different packages and tools have taken it upon themselves to come up with range rules. This has resulted in differences. For example, npm/js and Cargo/Rust follow similar patterns while PHP has a different pattern for ^. The comparison features in this package follow the npm/js and Cargo/Rust lead because applications using it have followed similar patters with their versions.

Checking a version against version constraints is one of the most featureful parts of the package.

c, err := semver.NewConstraint(">= 1.2.3")
if err != nil {
    // Handle constraint not being parsable.
}

v, err := semver.NewVersion("1.3")
if err != nil {
    // Handle version not being parsable.
}
// Check if the version meets the constraints. The a variable will be true.
a := c.Check(v)

Basic Comparisons

There are two elements to the comparisons. First, a comparison string is a list of space or comma separated AND comparisons. These are then separated by || (OR) comparisons. For example, ">= 1.2 < 3.0.0 || >= 4.2.3" is looking for a comparison that's greater than or equal to 1.2 and less than 3.0.0 or is greater than or equal to 4.2.3.

The basic comparisons are:

  • =: equal (aliased to no operator)
  • !=: not equal
  • >: greater than
  • <: less than
  • >=: greater than or equal to
  • <=: less than or equal to

Working With Prerelease Versions

Pre-releases, for those not familiar with them, are used for software releases prior to stable or generally available releases. Examples of prereleases include development, alpha, beta, and release candidate releases. A prerelease may be a version such as 1.2.3-beta.1 while the stable release would be 1.2.3. In the order of precedence, prereleases come before their associated releases. In this example 1.2.3-beta.1 < 1.2.3.

According to the Semantic Version specification prereleases may not be API compliant with their release counterpart. It says,

A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version.

SemVer comparisons using constraints without a prerelease comparator will skip prerelease versions. For example, >=1.2.3 will skip prereleases when looking at a list of releases while >=1.2.3-0 will evaluate and find prereleases.

The reason for the 0 as a pre-release version in the example comparison is because pre-releases can only contain ASCII alphanumerics and hyphens (along with . separators), per the spec. Sorting happens in ASCII sort order, again per the spec. The lowest character is a 0 in ASCII sort order (see an ASCII Table)

Understanding ASCII sort ordering is important because A-Z comes before a-z. That means >=1.2.3-BETA will return 1.2.3-alpha. What you might expect from case sensitivity doesn't apply here. This is due to ASCII sort ordering which is what the spec specifies.

Hyphen Range Comparisons

There are multiple methods to handle ranges and the first is hyphens ranges. These look like:

  • 1.2 - 1.4.5 which is equivalent to >= 1.2 <= 1.4.5
  • 2.3.4 - 4.5 which is equivalent to >= 2.3.4 <= 4.5

Wildcards In Comparisons

The x, X, and * characters can be used as a wildcard character. This works for all comparison operators. When used on the = operator it falls back to the patch level comparison (see tilde below). For example,

  • 1.2.x is equivalent to >= 1.2.0, < 1.3.0
  • >= 1.2.x is equivalent to >= 1.2.0
  • <= 2.x is equivalent to < 3
  • * is equivalent to >= 0.0.0

Tilde Range Comparisons (Patch)

The tilde (~) comparison operator is for patch level ranges when a minor version is specified and major level changes when the minor number is missing. For example,

  • ~1.2.3 is equivalent to >= 1.2.3, < 1.3.0
  • ~1 is equivalent to >= 1, < 2
  • ~2.3 is equivalent to >= 2.3, < 2.4
  • ~1.2.x is equivalent to >= 1.2.0, < 1.3.0
  • ~1.x is equivalent to >= 1, < 2

Caret Range Comparisons (Major)

The caret (^) comparison operator is for major level changes once a stable (1.0.0) release has occurred. Prior to a 1.0.0 release the minor versions acts as the API stability level. This is useful when comparisons of API versions as a major change is API breaking. For example,

  • ^1.2.3 is equivalent to >= 1.2.3, < 2.0.0
  • ^1.2.x is equivalent to >= 1.2.0, < 2.0.0
  • ^2.3 is equivalent to >= 2.3, < 3
  • ^2.x is equivalent to >= 2.0.0, < 3
  • ^0.2.3 is equivalent to >=0.2.3 <0.3.0
  • ^0.2 is equivalent to >=0.2.0 <0.3.0
  • ^0.0.3 is equivalent to >=0.0.3 <0.0.4
  • ^0.0 is equivalent to >=0.0.0 <0.1.0
  • ^0 is equivalent to >=0.0.0 <1.0.0

Validation

In addition to testing a version against a constraint, a version can be validated against a constraint. When validation fails a slice of errors containing why a version didn't meet the constraint is returned. For example,

c, err := semver.NewConstraint("<= 1.2.3, >= 1.4")
if err != nil {
    // Handle constraint not being parseable.
}

v, err := semver.NewVersion("1.3")
if err != nil {
    // Handle version not being parseable.
}

// Validate a version against a constraint.
a, msgs := c.Validate(v)
// a is false
for _, m := range msgs {
    fmt.Println(m)

    // Loops over the errors which would read
    // "1.3 is greater than 1.2.3"
    // "1.3 is less than 1.4"
}

Contribute

If you find an issue or want to contribute please file an issue or create a pull request.

Security

Security is an important consideration for this project. The project currently uses the following tools to help discover security issues:

If you believe you have found a security vulnerability you can privately disclose it through the GitHub security page.

More Repositories

1

glide

Package Management for Golang
Go
8,155
star
2

squirrel

Fluent SQL generation for golang
Go
6,755
star
3

sprig

Useful template functions for Go templates.
Go
4,108
star
4

html5-php

An HTML5 parser and serializer for PHP.
HTML
1,539
star
5

go-in-practice

Repository for Manning Publications Go in Practice
Go
353
star
6

structable

Golang struct-to-table database mapper
Go
293
star
7

vcs

VCS Repo management through a common interface in Go
Go
194
star
8

learning-helm

HTML
108
star
9

goutils

GoUtils is a Go implementation of some string manipulation libraries of Apache Commons. This is an open source project aimed at providing Go users with utility functions to manipulate strings in various ways.
Go
98
star
10

cookoo

A chain-of-command framework written in Go
Go
60
star
11

vert

Command line version testing: Compare versions at the CLI for use in shell scripts and make files.
Go
59
star
12

go-fileserver

A Go Fileserver where you can specify custom NotFound and Error response handlers.
Go
48
star
13

glide-report

Go
28
star
14

stability

Share the stability of a project
28
star
15

Fortissimo

A Chain Of Command (CoCo) framework for PHP.
PHP
25
star
16

log-go

A Golang logging interface with some reference implementations.
Go
21
star
17

kitt

Make your CLI apps pretty
Go
16
star
18

engine

An HTML theme engine for Go
Go
15
star
19

godir

Go Path Tool: A utility for working with Go and filesystem paths.
Go
12
star
20

codl

Codl: The Cookoo Domain Language
Go
11
star
21

Fortissimo-CLI-Base

A skeleton for creating Fortissimo CLI applications.
PHP
11
star
22

glide.sh

The website for Glide
HTML
10
star
23

convert

A mathematical conversion library.
Go
8
star
24

rmvcsdir

remove version control directories
Go
7
star
25

formenc

Decode form values using a Go unmarshal
Go
6
star
26

httputil

Framework-free HTTP utilities
Go
4
star
27

cookoo-cli-tutorial

A Git-based tutorial for using Cookoo to write command line apps.
Go
3
star
28

Villain

A CMS to be feared
PHP
3
star
29

cookoo-web-tutorial

A Git-based dive into building Cookoo web apps
Shell
3
star
30

Fortissimo-CLI

A CLI Setup for Fortissimo.
PHP
2
star
31

glide-ppa

Shell
2
star
32

Fortissimo-Base

A base setup for Fortissimo based site.
PHP
2
star
33

Fortissimo-Twig

Integration between Fortissimo and Twig
PHP
1
star
34

fortissimo-commons

Common commands for the Fortissimo framework.
PHP
1
star