semver

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 15, 2025 License: Apache-2.0 Imports: 5 Imported by: 0

README

Semantic Versioning Package

A robust, SemVer 2.0.0 compliant version parser, validator, and comparator for Go.

Installation

go get github.com/dmitrymomot/gokit/semver

Overview

The semver package provides a clean, immutable implementation of the Semantic Versioning 2.0.0 specification. It offers reliable tools for parsing, validating, comparing, and manipulating version strings in Go applications. This package is thread-safe due to its immutable design and suitable for concurrent use in production systems.

Features

  • Full SemVer 2.0.0 specification compliance
  • Immutable Version type for thread safety
  • Parse version strings with or without leading 'v'
  • Compare versions for precedence with proper prerelease handling
  • Increment major, minor, and patch components
  • Manipulate version elements independently
  • Check if a version is within a specific range
  • Clear error types for validation failures

Usage

Parsing Versions
import (
    "fmt"
    "github.com/dmitrymomot/gokit/semver"
)

// Standard parsing with error checking
version, err := semver.Parse("1.2.3")
if err != nil {
    // Handle error
    return fmt.Errorf("failed to parse version: %w", err)
}
// version represents "1.2.3"

// Also supports leading 'v'
version, err = semver.Parse("v2.1.0")
// Returns version representing "2.1.0"

// Parse with prerelease and build metadata
version, err = semver.Parse("1.2.3-beta.1+20130313144700")
// Returns version representing "1.2.3-beta.1+20130313144700"

// Parse without error checking (panics on invalid versions)
version = semver.MustParse("1.2.3")
// Returns version representing "1.2.3"
Validating Versions
// Check if a string is a valid SemVer
isValid := semver.Validate("1.2.3")
// Returns: true

isValid = semver.Validate("v1.2.3-beta+exp.sha.5114f85")
// Returns: true

// Validate a Version struct
version := semver.Version{Major: 1, Minor: 2, Patch: 3}
isValid = version.IsValid()
// Returns: true
Comparing Versions
v1 := semver.MustParse("1.2.3")
v2 := semver.MustParse("2.0.0")

// Core comparison methods
if v1.LessThan(v2) {
    // This code will execute since 1.2.3 < 2.0.0
}

if v1.GreaterThan(v2) {
    // This code will not execute
}

if v1.Equal(v2) {
    // This code will not execute
}

if v1.LessThanOrEqual(v2) {
    // This code will execute
}

if v1.GreaterThanOrEqual(v2) {
    // This code will not execute
}

// Check if a version is within a range (inclusive)
v3 := semver.MustParse("1.5.0")
if v3.InRange(v1, v2) {
    // This code will execute since 1.2.3 <= 1.5.0 <= 2.0.0
}

// Manual comparison
result := v1.Compare(v2)
// Returns: -1 because v1 < v2
Manipulating Versions
version := semver.MustParse("1.2.3-alpha+001")

// Create new versions with modified components
v2 := version.WithMajor(2)        // Returns: 2.2.3-alpha+001
v2 = version.WithMinor(5)         // Returns: 1.5.3-alpha+001
v2 = version.WithPatch(7)         // Returns: 1.2.7-alpha+001
v2 = version.WithPrerelease("beta") // Returns: 1.2.3-beta+001
v2 = version.WithBuild("002")     // Returns: 1.2.3-alpha+002

// Increment components (resets prerelease and build metadata)
v2, err := version.Increment("major") // Returns: 2.0.0
if err != nil {
    // Handle error
}

v2, err = version.Increment("minor")  // Returns: 1.3.0
if err != nil {
    // Handle error
}

v2, err = version.Increment("patch")  // Returns: 1.2.4
if err != nil {
    // Handle error
}

// Get string representations
str := version.String()         // Returns: "1.2.3-alpha+001"
str = version.MajorMinorPatch() // Returns: "1.2.3"
Error Handling
import (
    "errors"
    "fmt"
    "github.com/dmitrymomot/gokit/semver"
)

// Handling parsing errors
_, err := semver.Parse("invalid.version")
if err != nil {
    switch {
    case errors.Is(err, semver.ErrInvalidVersion):
        // Handle invalid version format
        fmt.Println("The version string format is invalid")
    case errors.Is(err, semver.ErrEmptyVersion):
        // Handle empty version string
        fmt.Println("The version string is empty")
    case errors.Is(err, semver.ErrInvalidPrerelease):
        // Handle invalid prerelease identifier
        fmt.Println("The prerelease identifier is invalid")
    case errors.Is(err, semver.ErrInvalidBuild):
        // Handle invalid build metadata
        fmt.Println("The build metadata is invalid")
    default:
        // Handle other errors
        fmt.Println("An unexpected error occurred:", err)
    }
}

// Checking version requirements
clientVersion := semver.MustParse("2.1.3")
minRequired := semver.MustParse("2.0.0")

if clientVersion.LessThan(minRequired) {
    return fmt.Errorf("client version %s is less than minimum required %s", 
        clientVersion, minRequired)
}
// Client version 2.1.3 is not less than minimum required 2.0.0, so this error won't be returned

// Check compatibility with a version range
minSupported := semver.MustParse("1.5.0")
maxSupported := semver.MustParse("3.0.0")

if !clientVersion.InRange(minSupported, maxSupported) {
    return errors.New("unsupported client version")
}
// Client version 2.1.3 is in range 1.5.0 to 3.0.0, so this error won't be returned

Best Practices

  1. Version Semantics:

    • Use major version zero (0.y.z) for initial development only
    • Increment major version (x.0.0) when making incompatible API changes
    • Increment minor version (x.y.0) when adding functionality in a backward compatible manner
    • Increment patch version (x.y.z) when making backward compatible bug fixes
  2. Prerelease and Build Identifiers:

    • Use prerelease versions (e.g., 1.0.0-alpha.1) for pre-release testing
    • Use build metadata (e.g., 1.0.0+20130313144700) for build identification
    • Remember that build metadata does not affect version precedence
  3. Error Handling:

    • Always check for errors when parsing user-supplied version strings
    • Use MustParse only for hard-coded versions or when panics are acceptable
    • Check specific error types for better error messages
  4. Comparisons:

    • Use the proper comparison methods for semantic version comparison
    • Avoid string-based version comparisons which can lead to incorrect results
    • For version ranges, always use InRange rather than separate comparisons

API Reference

Types
type Version struct {
    Major      uint64 // Major version component
    Minor      uint64 // Minor version component
    Patch      uint64 // Patch version component
    Prerelease string // Prerelease version component (e.g., "alpha.1")
    Build      string // Build metadata (e.g., "20130313144700")
}
Functions
func Parse(version string) (Version, error)

Parses a version string into a Version struct.

func MustParse(version string) Version

Parse without error checking (panics on invalid input).

func Validate(version string) bool

Validates a version string.

Methods
func (v Version) IsValid() bool

Checks if a Version struct is valid.

func (v Version) Compare(other Version) int

Compares versions and returns -1, 0, or 1.

func (v Version) LessThan(other Version) bool

Checks if version is less than other.

func (v Version) GreaterThan(other Version) bool

Checks if version is greater than other.

func (v Version) Equal(other Version) bool

Checks if versions are equal.

func (v Version) LessThanOrEqual(other Version) bool

Checks if version is less than or equal to other.

func (v Version) GreaterThanOrEqual(other Version) bool

Checks if version is greater than or equal to other.

func (v Version) InRange(lower, upper Version) bool

Checks if version is within a range (inclusive).

func (v Version) WithMajor(major uint64) Version

Creates a new version with a different major component.

func (v Version) WithMinor(minor uint64) Version

Creates a new version with a different minor component.

func (v Version) WithPatch(patch uint64) Version

Creates a new version with a different patch component.

func (v Version) WithPrerelease(prerelease string) Version

Creates a new version with a different prerelease component.

func (v Version) WithBuild(build string) Version

Creates a new version with a different build metadata.

func (v Version) Increment(component string) (Version, error)

Increments a version component (major, minor, or patch).

func (v Version) String() string

Returns the full version as a string.

func (v Version) MajorMinorPatch() string

Returns the major.minor.patch portion as a string.

Error Types
var ErrInvalidVersion = errors.New("invalid semantic version")
var ErrInvalidPrerelease = errors.New("invalid prerelease identifier")
var ErrInvalidBuild = errors.New("invalid build metadata")
var ErrEmptyVersion = errors.New("empty version string")
var ErrNegativeValue = errors.New("negative value in version")

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrInvalidVersion indicates that the provided string is not a valid semantic version
	ErrInvalidVersion = errors.New("invalid semantic version")

	// ErrInvalidPrerelease indicates that the provided prerelease string is invalid
	ErrInvalidPrerelease = errors.New("invalid prerelease identifier")

	// ErrInvalidBuild indicates that the provided build metadata is invalid
	ErrInvalidBuild = errors.New("invalid build metadata")

	// ErrEmptyVersion indicates an empty version string was provided
	ErrEmptyVersion = errors.New("empty version string")

	// ErrNegativeValue indicates a negative number was encountered in version components
	ErrNegativeValue = errors.New("negative value in version")
)

Error definitions for semver package

Functions

func Validate

func Validate(version string) bool

Validate checks if a version string is a valid semantic version.

Types

type Version

type Version struct {
	Major      uint64
	Minor      uint64
	Patch      uint64
	Prerelease string
	Build      string
}

Version represents a semantic version as defined by the SemVer 2.0.0 specification.

func MustParse

func MustParse(version string) Version

MustParse parses a version string into a Version struct. It panics if the version is invalid.

func Parse

func Parse(version string) (Version, error)

Parse parses a version string into a Version struct. It accepts versions with or without the leading 'v' character.

func (Version) Compare

func (v Version) Compare(other Version) int

Compare compares two versions and returns:

-1 if v < other
 0 if v == other
 1 if v > other

Prerelease versions are considered less than the corresponding release version. Build metadata is ignored when comparing versions for precedence.

func (Version) Equal

func (v Version) Equal(other Version) bool

Equal returns true if v == other

func (Version) GreaterThan

func (v Version) GreaterThan(other Version) bool

GreaterThan returns true if v > other

func (Version) GreaterThanOrEqual

func (v Version) GreaterThanOrEqual(other Version) bool

GreaterThanOrEqual returns true if v >= other

func (Version) InRange

func (v Version) InRange(lower, upper Version) bool

InRange checks if the version is between the lower and upper bounds (inclusive)

func (Version) Increment

func (v Version) Increment(component string) (Version, error)

Increment returns a new version with the specified component incremented

func (Version) IsValid

func (v Version) IsValid() bool

IsValid checks if the version is valid according to the semver specification

func (Version) LessThan

func (v Version) LessThan(other Version) bool

LessThan returns true if v < other

func (Version) LessThanOrEqual

func (v Version) LessThanOrEqual(other Version) bool

LessThanOrEqual returns true if v <= other

func (Version) MajorMinorPatch

func (v Version) MajorMinorPatch() string

MajorMinorPatch returns the version without prerelease or build metadata

func (Version) String

func (v Version) String() string

String returns the string representation of the version.

func (Version) WithBuild

func (v Version) WithBuild(build string) Version

WithBuild returns a new version with the build component changed

func (Version) WithMajor

func (v Version) WithMajor(major uint64) Version

WithMajor returns a new version with the major component changed

func (Version) WithMinor

func (v Version) WithMinor(minor uint64) Version

WithMinor returns a new version with the minor component changed

func (Version) WithPatch

func (v Version) WithPatch(patch uint64) Version

WithPatch returns a new version with the patch component changed

func (Version) WithPrerelease

func (v Version) WithPrerelease(prerelease string) Version

WithPrerelease returns a new version with the prerelease component changed

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL