version

package
v1.19.2 Latest Latest
Warning

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

Go to latest
Published: Feb 4, 2026 License: MIT Imports: 9 Imported by: 0

README

Version Package

Go Version Tests Coverage

Production-ready version and license management for Go applications with support for 11 open-source licenses, Go version constraints, and automatic package path extraction.


Table of Contents


Overview

The version package provides comprehensive version and license management for Go applications. It handles build metadata, release versions, license information, and Go version constraints with thread-safe operations and minimal memory overhead.

Design Philosophy
  1. Immutable After Creation: Version instances are read-only after construction
  2. Thread-Safe: All methods are safe for concurrent use
  3. Zero Dependencies: Only depends on github.com/nabbar/golib/errors and github.com/hashicorp/go-version
  4. Reflection-Based: Automatic package path extraction using Go reflection
  5. License Compliant: Built-in support for major open-source licenses

Key Features

  • Version Management: Build hash, release tag, date, author, and description
  • License Support: 11 open-source licenses with full legal text and boilerplate
    • MIT, Apache 2.0, GPL v3, AGPL v3, LGPL v3
    • Mozilla PL v2.0, Unlicense, CC0, CC BY, CC BY-SA
    • SIL Open Font License v1.1
  • Go Version Constraints: Validate runtime Go version with flexible operators
  • Package Path Extraction: Automatic detection via reflection
  • Formatted Output: Headers, info strings, and license text generation
  • Thread-Safe: Immutable design ensures safe concurrent access
  • High Performance: ~94ns for version creation, 0 allocations for license retrieval

Installation

go get github.com/nabbar/golib/version

Requirements:

  • Go ≥ 1.18
  • CGO enabled for race detection (optional)

Architecture

Package Structure
version/
├── version.go           # Core Version interface and NewVersion()
├── license.go           # License type and constants
├── license_*.go         # Individual license implementations
├── error.go             # Error codes and messages
└── doc.go              # Package documentation
Component Overview
┌─────────────────────────────────────────────────────────┐
│                   Version Interface                      │
│  GetRelease(), GetBuild(), GetDate(), GetAuthor()       │
│  GetLicense*(), CheckGo(), PrintInfo()                  │
└──────────────┬──────────────┬──────────────┬────────────┘
               │              │              │
      ┌────────▼─────┐  ┌────▼─────┐  ┌────▼────────┐
      │   Metadata   │  │ Licenses │  │ Validation  │
      │              │  │          │  │             │
      │ Build info   │  │ 11 types │  │ Go version  │
      │ Package path │  │ Legal    │  │ constraints │
      └──────────────┘  └──────────┘  └─────────────┘
Data Flow
NewVersion() → Reflection → Package Path Extraction
     │              │
     ├──────────────┴──→ Parse Date (RFC3339)
     │
     └──→ Create immutable Version instance
              │
              ├──→ GetHeader() / GetInfo()
              ├──→ GetLicense*()
              └──→ CheckGo()

Quick Start

Basic Usage
package main

import (
    "fmt"
    "github.com/nabbar/golib/version"
)

// Define a struct for reflection-based package path extraction
type MyApp struct{}

func main() {
    // Create version instance
    v := version.NewVersion(
        version.License_MIT,           // License type
        "MyApp",                        // Package name
        "My Application Description",  // Description
        "2024-01-15T10:30:00Z",        // Build date (RFC3339)
        "abc123def",                    // Build hash (git commit)
        "v1.2.3",                       // Release version
        "John Doe",                     // Author
        "MYAPP",                        // Prefix for env vars
        MyApp{},                        // Empty struct for reflection
        0,                              // Number of parent packages
    )

    // Display version information
    fmt.Println(v.GetHeader())
    // Output: MyApp (Release: v1.2.3, Build: abc123def, Date: Mon, 15 Jan 2024 10:30:00 UTC)

    // Check Go version constraint
    if err := v.CheckGo("1.18", ">="); err != nil {
        panic(err)
    }

    // Get license information
    fmt.Println(v.GetLicenseName())    // "MIT License"
    fmt.Println(v.GetLicenseBoiler())  // Boilerplate for file headers
}
Build Integration

Create a release package to inject build-time variables:

release/release.go:

package release

type EmptyStruct struct{}

var (
    // Injected at build time with -ldflags
    Release     = "v0.0.0"
    Build       = "dev"
    Date        = "2024-01-01T00:00:00Z"
    Package     = "myapp"
    Description = "My Application"
    Author      = "Author Name"
    Prefix      = "MYAPP"
)

release/version.go:

package release

import "github.com/nabbar/golib/version"

var vers version.Version

func init() {
    vers = version.NewVersion(
        version.License_MIT,
        Package,
        Description,
        Date,
        Build,
        Release,
        Author,
        Prefix,
        EmptyStruct{},
        1, // Go up one directory from release/ to app root
    )
}

func GetVersion() version.Version {
    return vers
}

Build command:

go build -ldflags "\
  -X release.Release=$(git describe --tags HEAD) \
  -X release.Build=$(git rev-parse --short HEAD) \
  -X release.Date=$(date -u +%Y-%m-%dT%H:%M:%SZ) \
  -X release.Package=$(basename $(pwd)) \
  -X release.Description='My Application' \
  -X release.Author='John Doe'"

Performance

Benchmark Results
Operation                    Time/op    Memory/op   Allocs/op
─────────────────────────────────────────────────────────────
NewVersion                   94.00 ns   144 B       1
GetHeader                   383.3 ns    272 B       8
GetInfo                     296.1 ns    160 B       5
GetLicenseLegal              19.50 ns     0 B       0
GetLicenseBoiler            817.0 ns   1201 B       5
GetLicenseFull              4.088 µs  12384 B      11
CheckGo                     4.749 µs   1982 B      27
ConcurrentAccess            331.3 ns    432 B      13
Performance Characteristics
  • Version Creation: Constant time O(1), single allocation
  • License Retrieval: Zero allocations for legal text (pre-compiled strings)
  • Thread-Safe: No locks needed due to immutable design
  • Memory Efficient: ~144 bytes per version instance
  • Concurrent Access: Linear scaling with CPU cores

Use Cases

1. Application Version Display
v := release.GetVersion()
fmt.Printf("Starting %s\n", v.GetHeader())
// Output: Starting MyApp (Release: v1.2.3, Build: abc123, Date: ...)
2. License File Generation
v := release.GetVersion()
licenseText := v.GetLicenseFull()
os.WriteFile("LICENSE", []byte(licenseText), 0644)
3. Go Version Validation
v := release.GetVersion()

// Require Go >= 1.18
if err := v.CheckGo("1.18", ">="); err != nil {
    log.Fatal("This application requires Go 1.18 or later")
}

// Pessimistic constraint (allow patch updates)
if err := v.CheckGo("1.20", "~>"); err != nil {
    log.Fatal("This application requires Go 1.20.x")
}
4. Multi-License Projects
v := version.NewVersion(version.License_MIT, ...)

// Combine multiple licenses
combined := v.GetLicenseFull(
    version.License_Apache_v2,
    version.License_Mozilla_PL_v2,
)
5. File Header Boilerplate
v := release.GetVersion()
header := v.GetLicenseBoiler()

// Add to source files
fileContent := header + "\n\npackage main\n\n// ..."

API Reference

Version Interface
type Version interface {
    // Version information
    GetPackage() string
    GetDescription() string
    GetRelease() string
    GetBuild() string
    GetDate() string
    GetTime() time.Time
    GetAuthor() string
    GetPrefix() string
    GetRootPackagePath() string
    
    // Formatted output
    GetHeader() string
    GetInfo() string
    GetAppId() string
    
    // License methods
    GetLicenseName() string
    GetLicenseLegal(addMoreLicence ...license) string
    GetLicenseBoiler(addMoreLicence ...license) string
    GetLicenseFull(addMoreLicence ...license) string
    
    // Validation
    CheckGo(RequireGoVersion, RequireGoContraint string) liberr.Error
    
    // Output methods
    PrintInfo()
    PrintLicense(addlicence ...license)
}
License Constants
const (
    License_MIT
    License_Apache_v2
    License_GNU_GPL_v3
    License_GNU_Affero_GPL_v3
    License_GNU_Lesser_GPL_v3
    License_Mozilla_PL_v2
    License_Unlicense
    License_Creative_Common_Zero_v1
    License_Creative_Common_Attribution_v4_int
    License_Creative_Common_Attribution_Share_Alike_v4_int
    License_SIL_Open_Font_1_1
)
Go Version Constraint Operators
  • == : Exact version match
  • != : Not equal
  • > : Greater than
  • >= : Greater than or equal
  • < : Less than
  • <= : Less than or equal
  • ~> : Pessimistic constraint (allows patch-level changes)
Error Codes
const (
    ErrorParamEmpty          // Required parameter is empty
    ErrorGoVersionInit       // Failed to parse version constraint
    ErrorGoVersionRuntime    // Failed to extract runtime Go version
    ErrorGoVersionConstraint // Go version constraint not satisfied
)

Best Practices

1. Use Build-Time Injection

Always inject version information at build time rather than hardcoding:

go build -ldflags "-X package.Variable=value"
2. Validate Go Version Early

Check Go version constraints during application initialization:

func init() {
    if err := release.GetVersion().CheckGo("1.18", ">="); err != nil {
        log.Fatal(err)
    }
}
3. Single Version Instance

Create one version instance per application (singleton pattern):

var version = version.NewVersion(...)  // Package-level variable

func GetVersion() version.Version {
    return version
}
4. Package Path Extraction

Use numSubPackage to navigate from nested packages:

// In myapp/internal/release/version.go
v := version.NewVersion(..., EmptyStruct{}, 2)
// Goes up 2 levels: internal/release → internal → myapp
5. License Selection

Choose the appropriate license for your project:

  • Permissive: MIT, Apache 2.0, Unlicense
  • Copyleft (Strong): GPL v3, AGPL v3
  • Copyleft (Weak): LGPL v3, Mozilla PL v2.0
  • Creative Commons: CC0, CC BY, CC BY-SA (for content/docs)
  • Fonts: SIL Open Font License

Testing

Test Suite: 173 specs using Ginkgo v2 and Gomega (93.8% coverage)

# Run tests
go test ./...

# With coverage
go test -cover ./...

# With race detection (recommended)
CGO_ENABLED=1 go test -race ./...

Coverage Areas

  • Version creation and metadata management
  • License operations (all 11 licenses)
  • Go version constraint validation
  • Error handling and edge cases
  • Thread safety and concurrent access

Quality Assurance

  • ✅ Zero data races (verified with -race)
  • ✅ Thread-safe concurrent operations
  • ✅ Immutable design pattern
  • ✅ High test coverage (93.8%)

See TESTING.md for detailed testing documentation.


Contributing

Contributions are welcome! Please follow these guidelines:

Code Contributions

  • Do not use AI to generate package implementation code
  • AI may assist with tests, documentation, and bug fixing
  • All contributions must pass go test -race
  • Maintain or improve test coverage (≥90%)
  • Follow existing code style and patterns

Documentation

  • Update README.md for new features
  • Add examples for common use cases
  • Keep TESTING.md synchronized with test changes

Testing

  • Write tests for all new features
  • Test edge cases and error conditions
  • Verify thread safety with race detector
  • Add comments explaining complex scenarios

Pull Requests

  • Provide clear description of changes
  • Reference related issues
  • Include test results
  • Update documentation

See CONTRIBUTING.md for detailed guidelines.


Future Enhancements

Potential improvements for future versions:

Additional Licenses

  • BSD 2-Clause / 3-Clause
  • ISC License
  • Boost Software License

Enhanced Metadata

  • Git branch information
  • CI/CD build numbers
  • Semantic version parsing

Output Formats

  • JSON/YAML version info export
  • SPDX license identifiers
  • Machine-readable metadata

Validation

  • Semantic version validation
  • License compatibility checking
  • Dependency version tracking

Integration

  • GitHub Actions integration
  • Docker label generation
  • Kubernetes annotation support

Suggestions and contributions are welcome via GitHub issues.


AI Transparency Notice

In accordance with Article 50.4 of the EU AI Act, AI assistance has been used for testing, documentation, and bug fixing under human supervision.


License

MIT License - See LICENSE file for details.


Resources

Documentation

Overview

Package version provides version management and license handling for Go applications.

Overview

This package offers a comprehensive solution for managing application version information, including build metadata, release versions, license information, and Go version constraints. It supports multiple open-source licenses and provides formatted output for version and license information.

Features

  • Version information management (release, build, date, author)
  • Multiple license support (MIT, Apache, GPL, LGPL, AGPL, Mozilla, Creative Commons, etc.)
  • Go version constraint validation
  • Automatic package path extraction via reflection
  • Thread-safe operations
  • Formatted output for headers, info, and license text

Basic Usage

Creating a version instance:

import "github.com/nabbar/golib/version"

type MyStruct struct{}

v := version.NewVersion(
	version.License_MIT,           // License type
	"MyApp",                        // Package name
	"My Application Description",  // Description
	"2024-01-15T10:30:00Z",        // Build date (RFC3339)
	"abc123def",                    // Build hash
	"v1.2.3",                       // Release version
	"John Doe",                     // Author
	"MYAPP",                        // Prefix for environment variables
	MyStruct{},                     // Empty struct for reflection
	0,                              // Number of parent packages to traverse
)

Retrieving Version Information

// Get formatted header
fmt.Println(v.GetHeader())

// Get detailed info
fmt.Println(v.GetInfo())

// Get individual fields
release := v.GetRelease()
build := v.GetBuild()
date := v.GetDate()
author := v.GetAuthor()

License Management

The package supports multiple license types:

  • MIT License
  • Apache License v2.0
  • GNU GPL v3
  • GNU Affero GPL v3
  • GNU Lesser GPL v3
  • Mozilla Public License v2.0
  • Unlicense
  • Creative Commons Zero v1.0
  • Creative Commons Attribution v4.0
  • Creative Commons Attribution-ShareAlike v4.0
  • SIL Open Font License v1.1

Retrieving license information:

// Get license name
name := v.GetLicenseName()

// Get full license text
legal := v.GetLicenseLegal()

// Get license boilerplate (for file headers)
boiler := v.GetLicenseBoiler()

// Get complete license (boilerplate + legal text)
full := v.GetLicenseFull()

// Support for multiple licenses
combined := v.GetLicenseLegal(
	version.License_Apache_v2,
	version.License_MIT,
)

Go Version Constraints

Validate that the application is running with a compatible Go version:

// Require Go >= 1.18
if err := v.CheckGo("1.18", ">="); err != nil {
	log.Fatal(err)
}

// Require exact Go version
if err := v.CheckGo("1.21.0", "=="); err != nil {
	log.Fatal(err)
}

// Pessimistic constraint (compatible with minor versions)
if err := v.CheckGo("1.20", "~>"); err != nil {
	log.Fatal(err)
}

Supported constraint operators:

  • "==" : Exact version match
  • "!=" : Not equal
  • ">" : Greater than
  • ">=" : Greater than or equal
  • "<" : Less than
  • "<=" : Less than or equal
  • "~>" : Pessimistic constraint (allows patch-level changes)

Package Path Extraction

The package uses reflection to automatically extract the package path. The numSubPackage parameter controls how many parent directories to traverse:

// numSubPackage = 0: github.com/myorg/myapp/cmd
// numSubPackage = 1: github.com/myorg/myapp
// numSubPackage = 2: github.com/myorg

Error Handling

The package uses the github.com/nabbar/golib/errors package for error handling. Error codes:

  • ErrorParamEmpty: Required parameter is empty
  • ErrorGoVersionInit: Failed to initialize Go version constraint
  • ErrorGoVersionRuntime: Failed to extract runtime Go version
  • ErrorGoVersionConstraint: Go version constraint not satisfied

Thread Safety

All methods are safe for concurrent use. The Version interface is read-only after creation, making it inherently thread-safe.

Testing

The package includes comprehensive tests with high code coverage (>93%). Run tests with:

make test              # Run all tests
make test-race         # Run with race detector
make test-coverage     # Generate coverage report

Dependencies

  • github.com/hashicorp/go-version: Version constraint parsing
  • github.com/nabbar/golib/errors: Error handling

See Also

  • github.com/nabbar/golib/errors: Error handling package
  • github.com/hashicorp/go-version: Version constraint library

License

This package is released under the MIT License. See the LICENSE file for details.

Index

Constants

View Source
const (
	// ErrorParamEmpty indicates that a required parameter is empty or missing.
	ErrorParamEmpty liberr.CodeError = iota + liberr.MinPkgVersion

	// ErrorGoVersionInit indicates a failure to initialize the Go version constraint parser.
	// This typically occurs when the constraint string is malformed.
	ErrorGoVersionInit

	// ErrorGoVersionRuntime indicates a failure to extract the current Go runtime version.
	// This is rare and usually indicates a problem with the Go installation.
	ErrorGoVersionRuntime

	// ErrorGoVersionConstraint indicates that the current Go version does not satisfy
	// the required version constraint.
	ErrorGoVersionConstraint
)

Error codes for the version package. These codes are used with the github.com/nabbar/golib/errors package.

View Source
const (
	// License_MIT represents the MIT License - a permissive license.
	License_MIT license = iota

	// License_GNU_GPL_v3 represents the GNU General Public License v3.0 - a strong copyleft license.
	License_GNU_GPL_v3

	// License_GNU_Affero_GPL_v3 represents the GNU Affero General Public License v3.0 - GPL with network use clause.
	License_GNU_Affero_GPL_v3

	// License_GNU_Lesser_GPL_v3 represents the GNU Lesser General Public License v3.0 - weak copyleft for libraries.
	License_GNU_Lesser_GPL_v3

	// License_Mozilla_PL_v2 represents the Mozilla Public License v2.0 - weak copyleft, file-level.
	License_Mozilla_PL_v2

	// License_Apache_v2 represents the Apache License v2.0 - permissive with patent grant.
	License_Apache_v2

	// License_Unlicense represents the Unlicense - public domain dedication.
	License_Unlicense

	// License_Creative_Common_Zero_v1 represents CC0 1.0 Universal - public domain dedication.
	License_Creative_Common_Zero_v1

	// License_Creative_Common_Attribution_v4_int represents CC BY 4.0 - requires attribution.
	License_Creative_Common_Attribution_v4_int

	// License_Creative_Common_Attribution_Share_Alike_v4_int represents CC BY-SA 4.0 - attribution + share-alike.
	License_Creative_Common_Attribution_Share_Alike_v4_int

	// License_SIL_Open_Font_1_1 represents the SIL Open Font License v1.1 - for fonts.
	License_SIL_Open_Font_1_1
)

Supported open-source license types. These constants can be passed to NewVersion to specify the application's license.

Variables

This section is empty.

Functions

This section is empty.

Types

type Version

type Version interface {
	// CheckGo validates that the current Go runtime version satisfies the given constraint.
	// RequireGoVersion is the version to check against (e.g., "1.18", "1.21.0").
	// RequireGoContraint is the operator (e.g., ">=", "==", "~>").
	// Returns an error if the constraint is not satisfied or if parsing fails.
	CheckGo(RequireGoVersion, RequireGoContraint string) liberr.Error

	// GetAppId returns a unique application identifier including version, OS, and architecture.
	GetAppId() string
	// GetAuthor returns the author information with source package path.
	GetAuthor() string
	// GetBuild returns the build identifier (typically a git commit hash).
	GetBuild() string
	// GetDate returns the build date as a formatted string.
	GetDate() string
	// GetTime returns the build date as a time.Time object.
	GetTime() time.Time
	// GetDescription returns the application description.
	GetDescription() string
	// GetHeader returns a formatted header string with package, release, and build info.
	GetHeader() string
	// GetInfo returns detailed version information including release, build, and date.
	GetInfo() string
	// GetPackage returns the package name.
	GetPackage() string
	// GetRootPackagePath returns the root package path extracted via reflection.
	GetRootPackagePath() string
	// GetPrefix returns the uppercase prefix for environment variables.
	GetPrefix() string
	// GetRelease returns the release version string.
	GetRelease() string

	// GetLicenseName returns the name of the primary license.
	GetLicenseName() string
	// GetLicenseLegal returns the full legal text of the license(s).
	// Additional licenses can be provided to combine multiple license texts.
	GetLicenseLegal(addMoreLicence ...license) string
	// GetLicenseFull returns the complete license including boilerplate and legal text.
	// Additional licenses can be provided to combine multiple licenses.
	GetLicenseFull(addMoreLicence ...license) string
	// GetLicenseBoiler returns the license boilerplate suitable for file headers.
	// Additional licenses can be provided to combine multiple boilerplates.
	GetLicenseBoiler(addMoreLicence ...license) string

	// PrintInfo prints version information to stderr.
	PrintInfo()
	// PrintLicense prints license boilerplate to stderr.
	// Additional licenses can be provided to print multiple licenses.
	PrintLicense(addlicence ...license)
}

Version is the main interface for accessing version and license information. All methods are safe for concurrent use.

func NewVersion

func NewVersion(License license, Package, Description, Date, Build, Release, Author, Prefix string, emptyInterface interface{}, numSubPackage int) Version

NewVersion creates a new Version instance with the provided information.

Parameters:

  • License: The primary license type (e.g., License_MIT, License_Apache_v2)
  • Package: The package/application name (use "" or "noname" to auto-detect from reflection)
  • Description: A description of the application
  • Date: Build date in RFC3339 format (e.g., "2024-01-15T10:30:00Z")
  • Build: Build identifier, typically a git commit hash
  • Release: Release version string (e.g., "v1.2.3")
  • Author: Author name or organization
  • Prefix: Prefix for environment variables (will be converted to uppercase)
  • emptyInterface: An empty struct instance used for reflection to extract package path
  • numSubPackage: Number of parent directories to traverse from the reflected package path (0 = current package, 1 = parent, 2 = grandparent, etc.)

Returns a Version interface for accessing version and license information.

Example:

type MyApp struct{}
v := NewVersion(
	License_MIT,
	"MyApp",
	"My Application",
	"2024-01-15T10:30:00Z",
	"abc123",
	"v1.0.0",
	"John Doe",
	"MYAPP",
	MyApp{},
	0,
)

Jump to

Keyboard shortcuts

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