How to Use UpdateVersion in Your CI/CD PipelineContinuous Integration/Continuous Deployment (CI/CD) pipelines automate building, testing, and deploying software. A common step in modern pipelines is updating the project’s version number—both to reflect semantic versioning and to ensure reproducible artifacts. This article explains how to use a tool or script named UpdateVersion (generic term for a version-updating utility) within your CI/CD pipeline, covering versioning strategies, practical pipeline integration, automation examples, handling artifact metadata, and tips for reliability and security.
Why automate version updates?
Automating version updates removes human error, provides consistent artifact names, and makes releases traceable. Benefits include:
- Deterministic build artifacts: Each build has a unique version.
- Traceability: Versions link artifacts to commits and changelogs.
- Faster releases: Automation reduces manual steps and context switching.
- Compatibility enforcement: Helps maintain semantic versioning (semver) rules across teams.
Versioning strategies
Choose a strategy that fits your release cadence and compatibility guarantees.
- Semantic Versioning (semver): MAJOR.MINOR.PATCH
- MAJOR for incompatible API changes.
- MINOR for added functionality in a backward-compatible manner.
- PATCH for backward-compatible bug fixes.
- Date-based versions: YYYY.MM.DD or YYYY.MM.DD.N (good for daily/continuous releases).
- Build metadata: append +build.sha or +build.number for CI-specific identifiers.
- Git-based versions: use tags (v1.2.3), commit counts (v1.2.3-45-gabc123), or short SHA suffixes.
Decide whether UpdateVersion will:
- bump automatically (e.g., increment patch on merge to main),
- require explicit bump via PR/commit message (e.g., “feat!: bump to 2.0.0”),
- or compute from git history/tags.
Where UpdateVersion fits in the pipeline
Common placement points:
- Pre-build: Update version before building artifacts so compiled outputs embed the new version.
- Post-build, pre-release: Update metadata and tags after a successful build and tests.
- Release job: When creating a release or publishing artifacts (packages, Docker images), ensure the final version is set and tagged.
Example flow:
- Run tests.
- Run UpdateVersion to set the new version.
- Build artifacts embedding the version.
- Run integration tests.
- Tag the repository and publish artifacts.
Implementing UpdateVersion: patterns and examples
Below are practical examples for popular CI systems. Replace UpdateVersion with your actual script/utility or implement equivalent behavior.
GitHub Actions
Use a job that computes the next version, updates files, commits, tags, and pushes.
Example steps:
- Checkout code.
- Install dependencies and UpdateVersion tool (or run a script).
- Determine new version (from commit messages, PR labels, or manual input).
- Update files (package.json, setup.cfg, VERSION).
- Commit, create tag, push, and create a release.
- Build and publish artifacts using the new version.
Key considerations:
- Use a bot/service account or GitHub token with permission to push tags.
- Prevent infinite workflow loops by excluding commits made by the workflow user.
GitLab CI
Use a pipeline stage like release:
- Use CI_COMMIT_TAG / CI_COMMIT_REF_NAME variables to decide whether to bump.
- Run a script to update version files and create tags using gitlab-ci token.
- Publish to GitLab Package Registry or Docker Registry.
Jenkins
Use a declarative pipeline:
- Use environment variables and credentials to allow the Jenkins job to create tags.
- Use a shared library function UpdateVersion.bump(kind) to centralize logic.
Example UpdateVersion script (pseudocode)
Use a small script to read current version, compute next, update files, and optionally tag.
#!/usr/bin/env bash set -e # Simple semantic version bumper FILE="VERSION" CURRENT=$(cat $FILE) PART=$1 # major | minor | patch IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT" case "$PART" in major) MAJOR=$((MAJOR+1)); MINOR=0; PATCH=0;; minor) MINOR=$((MINOR+1)); PATCH=0;; patch) PATCH=$((PATCH+1));; *) echo "Usage: $0 {major|minor|patch}"; exit 2;; esac NEW="$MAJOR.$MINOR.$PATCH" echo "$NEW" > $FILE git add $FILE git commit -m "chore(release): bump version to $NEW" git tag -a "v$NEW" -m "Release $NEW" git push origin HEAD --follow-tags echo "Updated version to $NEW"
Embedding build metadata
For reproducibility, append build metadata such as CI build number or short commit SHA:
- semver build metadata: 1.2.3+ci.456 or 1.2.3+sha.abcdef
- Use environment variables: CI_PIPELINE_ID, GITHUB_RUN_NUMBER, CI_COMMIT_SHA.
Example: final artifact name myapp-1.2.3+sha.abcdef.jar
Handling version files in various ecosystems
- Node.js: update package.json version field; run npm version if you prefer built-in handling.
- Python: update setup.cfg / pyproject.toml / version in a module; use setuptools_scm for git-derived versions.
- Java/Maven: update pom.xml; use versions-maven-plugin.
- Docker images: tag images with both semantic version and latest, plus a commit SHA tag.
Changelog and release notes
Integrate changelog generation:
- Conventional Commits + semantic-release: parse commit messages to determine bump type and auto-generate changelog.
- Keep a CHANGELOG.md updated by the UpdateVersion step or a separate job.
- Link releases to changelog entries and CI builds for traceability.
Testing and safety
- Dry-run mode: allow UpdateVersion to report changes without committing.
- Protected branches: require PRs for direct changes to main; run UpdateVersion in CI after merge.
- Locking/serialization: ensure only one release job updates tags at a time to avoid race conditions.
- Rollback plan: if a release needs to be reverted, document how to untag and republish artifacts.
Security and credentials
- Use scoped deploy keys or CI tokens with least privilege to push tags and publish artifacts.
- Rotate tokens regularly and store them in CI secret storage.
- Verify the source of triggers (e.g., only allow tag pushes from protected branches).
Observability and auditing
- Store build metadata (version, commit SHA, pipeline ID) in artifact metadata or a releases database.
- Emit release events or create release notes in Git hosting for human-readable audit trails.
- Monitor failed versioning steps and alert on repeated failures.
Tips and common pitfalls
- Avoid altering history of published tags — prefer new tags over force-pushes.
- Keep versioning logic in one place (script, tool, or shared library) to avoid divergence.
- Decide whether to include pre-release identifiers (alpha, beta, rc) and handle them consistently.
- Ensure local developer workflows (e.g., running tests locally) can reproduce the same versioning behavior.
Example end-to-end workflow (summary)
- Developer opens PR with feature.
- CI runs tests; on merge to main, a release job triggers.
- Release job computes bump (conventional commits), runs UpdateVersion to change VERSION and package files.
- Job builds artifacts with the new version, tags the repo, and publishes artifacts and release notes.
- Artifacts are stored in registries with versions and build metadata.
Automating versioning with UpdateVersion in your CI/CD pipeline makes releases predictable, traceable, and faster. Implement the chosen strategy consistently, secure the process, and provide observability so teams can trust automated releases.
Leave a Reply