Versioning is a fundamental aspect of software development that often gets overlooked. Proper versioning extends beyond primary products to include internal tools, shared libraries, and services. Missing or inconsistent versioning can lead to severe integration issues, bug tracking difficulties, deployment confusion, and a general lack of accountability.

The Risks of Missing Versioning

When versioning is inconsistent or absent, several problems can arise:

  • Integration Nightmares: Different components may not work well together if their versions are not correctly tracked.
  • Bug Tracking Challenges: Identifying the exact version where a bug occurred becomes difficult without proper versioning.
  • Deployment Confusion: Ensuring that the correct versions are deployed can become a complex task.
  • Lack of Accountability: Without clear versioning, tracking changes and understanding who made them becomes challenging.

Implementing Comprehensive Versioning Strategies

To avoid these pitfalls, it is crucial to implement comprehensive versioning strategies across all aspects of your build and deployment processes. Here’s how you can set custom build versions in TeamCity and Azure DevOps, and why tools like GitVersion and semantic versioning are essential.

Setting Custom Build Versions in TeamCity

  1. Configure Build Number Format:

    • Navigate to the “Build Configuration Settings.”
    • Under “General Settings,” find the “Build number format” field.
    • Use parameters like %build.counter% or %build.vcs.number% to create a unique build number.
  2. Use Version Control Labeling:

    • Enable version control labeling in the VCS settings.
    • This ensures each build is labeled with a specific version in the version control system.
  3. Build Steps for Custom Versioning:

    • Add a build step to update the version number in your project files.
    • Use scripts to ensure the version number is consistent across all relevant files.

Setting Custom Build Versions in Azure DevOps

  1. Define Build Number Format:

    • Go to the “Edit” page of your pipeline.
    • Click on the “Options” tab.
    • In the “Build number format” field, define a format using variables like $(Build.DefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r).
  2. Use YAML Pipelines for Custom Versioning:

    • In your azure-pipelines.yml file, define the build number format:
      name: $(Build.DefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)
      
    • Ensure scripts within your pipeline update the version number in all necessary files.
  3. Versioning in NuGet Packages:

    • Use the dotnet pack command with version parameters to ensure your NuGet packages have consistent versioning:
      dotnet pack /p:PackageVersion=$(Build.BuildId)
      

Tools and Practices for Effective Versioning

GitVersion

Consider using GitVersion, a tool that calculates version numbers based on your Git history. GitVersion is flexible, easy to configure, and integrates well with your existing CI/CD pipeline.

Semantic Versioning

Semantic versioning (semver) is a widely adopted versioning system that uses a three-part version number: MAJOR.MINOR.PATCH. This system helps in communicating the nature of changes made in new releases:

  • MAJOR version when you make incompatible API changes,
  • MINOR version when you add functionality in a backward-compatible manner, and
  • PATCH version when you make backward-compatible bug fixes.

Public vs. Internal Versioning

It’s common to use different versioning schemes for internal builds and public releases. For example, your internal software build might be versioned as 1.12.0-build758, while the public release is simply 1.12. Tracking the exact build number is crucial for identifying which version was shipped to clients.

Conclusion

Effective versioning is not just a best practice; it’s a necessity for maintaining a smooth and efficient development workflow. By implementing comprehensive versioning strategies and using tools like GitVersion and semantic versioning, you can avoid the common pitfalls associated with missing versioning. This approach ensures better collaboration, easier debugging, and more reliable deployments, ultimately supporting the growth and innovation within your organization.