This is a language agnostic git versioning tool using tags.
There are plenty of tools available that can generate a version based on Git tags. However, they are typically:
- driven by commit messages, not configuration
- dependent on programming languages
I didn't want to have to introduce a programming language into my pipeline, especially when it was a language that had absolutely nothing to do with my pipeline, e.g. using an action implemented in JS in a Python project. I also didn't feel like commit messages were the way to go, typos happen, and then someone needs to go and update it manually.
The aim has been to have a very simple approach at versioning without introducing new dependencies, and for it to be configuration driven.
You can either:
- download this script into your pipeline
- use the provided versioner-action
A bash script that calculates semantic versions from git tags and branches, with support for feature branch pre-releases.
- Git repository with commit history
jqcommand-line JSON processor- Bash shell
-
Download the script:
curl -sL https://raw.githubusercontent.com/DragosDumitrache/versioner/main/version.sh -o version.sh chmod +x version.sh
-
Create version.json in your repository root:
{ "default_branch": "main", "major": "1", "minor": "0", "tag_prefix": "v" } -
Run the script:
./version.sh
The version.json file supports the following options:
| Field | Description | Default | Example |
|---|---|---|---|
default_branch |
Main branch name | "master" |
"main", "master" |
major |
Minimum major version | "0" |
"1", "2" |
minor |
Minimum minor version | "0" |
"0", "5" |
tag_prefix |
Prefix for tags and output | "" |
"v", "release-" |
On your default branch (e.g., main), the script produces clean semantic versions:
# No previous tags
./version.sh
# Output: v1.0.0
# After tag v1.0.0, with 3 more commits
./version.sh
# Output: v1.0.3
# With version constraints (major: "2", minor: "1")
./version.sh
# Output: v2.1.0 (enforces minimums)On feature branches, the script produces pre-release versions:
# On branch "feature/user-auth"
./version.sh
# Output: v1.0.3-dev.feature-user-auth.abc1234
# On branch "bugfix/login-issue"
./version.sh
# Output: v1.0.3-dev.bugfix-login-issue.def5678When you have uncommitted changes:
./version.sh
# Main branch: v1.0.3-dirty
# Feature branch: v1.0.3-dev.feature-auth.abc1234.dirty# Initialize repository
git init
git config user.name "Your Name"
git config user.email "your@email.com"
# Create version configuration
cat <<EOF > version.json
{
"default_branch": "main",
"major": "1",
"minor": "0",
"tag_prefix": "v",
"include_v_prefix": true
}
EOF
# Download and run script
curl -sL https://raw.githubusercontent.com/DragosDumitrache/versioner/main/version.sh | bash
# Output: v1.0.0# After creating some tags
git tag v1.2.0
git commit -m "Add feature"
git commit -m "Fix bug"
./version.sh
# Output: v1.2.2 (v1.2.0 + 2 commits)git checkout -b feature/api-improvement
git commit -m "Improve API"
./version.sh
# Output: v1.2.3-dev.feature-api-improvement.a1b2c3d{
"default_branch": "main",
"major": "0",
"minor": "1",
"tag_prefix": ""
}./version.sh
# Output: 0.1.0 (no prefix)#!/bin/bash
VERSION=$(./version.sh)
echo "Building version: $VERSION"
# Use in Docker build
docker build -t myapp:$VERSION .
# Use in package.json
npm version $VERSION --no-git-tag-versionVERSION := $(shell ./version.sh)
.PHONY: version
version:
@echo $(VERSION)
.PHONY: build
build:
docker build -t myapp:$(VERSION) .
.PHONY: tag
tag:
git tag $(VERSION)
git push origin $(VERSION)#!/bin/bash
set -e
# Get version
VERSION=$(./version.sh)
CLEAN_VERSION=${VERSION#v} # Remove v prefix
# Check if pre-release
if [[ "$VERSION" =~ -dev\. ]]; then
echo "Pre-release version: $VERSION"
echo "Deploying to staging..."
else
echo "Release version: $VERSION"
echo "Deploying to production..."
fi./version.sh
# Output: 1.0.0-SNAPSHOT# Install jq first
# Ubuntu/Debian:
sudo apt-get install jq
# macOS:
brew install jq
# CentOS/RHEL:
sudo yum install jqIf version.json is malformed, the script will use defaults and may produce unexpected results. Validate your JSON:
jq . version.json
# Should output the parsed JSON without errorsThe script automatically normalizes branch names:
feature/user-auth→feature-user-authbugfix/fix_login→bugfix-fix-loginrelease/v2.0→release-v2.0
// With v prefix
{
"tag_prefix": "v"
}
// Result: v1.2.3
// No prefix
{
"tag_prefix": ""
}
// Result: 1.2.3
// Custom prefix
{
"tag_prefix": "release-"
}
// Result: release-1.2.3Use version constraints to enforce minimum versions:
{
"major": "2",
"minor": "1"
}Even if your latest tag is v1.5.0, the script will output v2.1.0 to meet the minimum requirements.
- Ensure you're on the correct branch
- Check that commits exist since the last tag
- Verify git history with
git log --oneline
- Check
version.jsonsyntax withjq . version.json - Ensure all values are strings:
"1"not1 - Verify tag prefix matches existing tags
- You're not in a git repository
- Run
git initand make at least one commit - Ensure
.gitdirectory exists
Run the included tests:
# Install bats
npm install -g bats
# Run tests
bats test.batsMIT