Build numbers: major.minor.revision

29,571

Solution 1

The build_info.properties file:

build.major.number=00
build.revision.number=00
build.minor.number=00

The build.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<project name="project" default="current-number">

<property file="build_info.properties"/>
<property name="build.number" value="${build.major.number}.${build.minor.number}.${build.revision.number}"/>

<target name="current-number">
 <echo>Current build number:${build.number}</echo>
</target>

<target name="compile">
   <antcall target="revision"></antcall>
</target>

<target name="dist">
  <antcall target="minor"></antcall>
</target>

<target name="revision">
    <propertyfile  file="build_info.properties">
            <entry key="build.revision.number" type="int" operation="+" value="1" pattern="00"/>
    </propertyfile>
</target>

<target name="minor">
    <propertyfile  file="build_info.properties">
            <entry key="build.minor.number" type="int" operation="+" value="1" pattern="00"/>
            <entry key="build.revision.number" type="int" value="0" pattern="00"/>
    </propertyfile>
</target>

<target name="major">
    <propertyfile  file="build_info.properties">
            <entry key="build.major.number" type="int" operation="+" value="1" pattern="00"/>
            <entry key="build.minor.number" type="int" value="0" pattern="00"/>
            <entry key="build.revision.number" type="int" value="0" pattern="00"/>
    </propertyfile>
</target>

<target name="all">
    <propertyfile  file="build_info.properties">
            <entry key="build.major.number" type="int" operation="+" value="1" pattern="00"/>
            <entry key="build.minor.number" type="int" operation="+" value="1" pattern="00"/>
            <entry key="build.revision.number" type="int" operation="+" value="1" pattern="00"/>
    </propertyfile>
</target>

</project>

Solution 2

This solution does increment minor or revision number automatically if a compile or a dist target has been selected. The incrementation can be switched off if one of the following properties has been set:

  • -Dno.increment.minor=true
  • -Dno.increment.revision=true

If the property inc.major has been set, then the major number will be incremented and the other both values will be set to zero. The SHA-1 checksum is being calculated by the textual representation of the version file.

By the way: If would have been allowed, you could create your own ant task in java script, which is included in JDK 6.

Now here's the ant file

<?xml version="1.0" encoding="UTF-8"?>
<project name="Numbers" default="dist" basedir=".">

    <property name="version.file" location="${basedir}/version.properties"/>

    <target name="inc.revision.properties" unless="no.increment.revision">
        <propertyfile file="${version.file}">
            <entry key="minor.number" default="00" operation="=" pattern="00" type="int"/>
            <entry key="major.number" default="00" operation="=" pattern="00" type="int"/>
            <entry key="build.number" default="00" operation="+" pattern="00" type="int"/>
        </propertyfile>
    </target>

    <target name="inc.minor.properties" unless="no.increment.minor">
        <propertyfile file="${version.file}">
            <entry key="minor.number" default="00" operation="+" pattern="00" type="int"/>
            <entry key="major.number" default="00" operation="=" pattern="00" type="int"/>
            <entry key="build.number" value="00" operation="="  type="int"/>
        </propertyfile>
    </target>

    <target name="inc.major" if="inc.major">
        <property name="no.increment.minor" value="true" />
        <property name="no.increment.revision" value="true" />
        <propertyfile file="${version.file}">
            <entry key="minor.number" value="00" operation="=" pattern="00" type="int"/>
            <entry key="major.number" default="00" operation="+" pattern="00" type="int"/>
            <entry key="build.number" value="00" operation="=" pattern="00" type="int"/>
        </propertyfile>
        <load.version.info/>
    </target>

    <target name="inc.minor" depends="inc.major,inc.minor.properties">
        <property name="no.increment.revision" value="true"/>
        <load.version.info/>
    </target>

    <target name="inc.revision" depends="inc.major,inc.revision.properties">
        <load.version.info/>
    </target>

    <macrodef name="load.version.info">
        <sequential>
            <property file="${version.file}"/>
            <checksum file="${version.file}" property="sha1.number" algorithm="SHA" format="CHECKSUM"/>
            <echo>Version: ${major.number}.${minor.number}.${build.number}</echo>
            <echo>SHA1: ${sha1.number}</echo>
        </sequential>
    </macrodef>

    <target name="compile" depends="inc.revision" description="Compile Task"/>

    <target name="dist" depends="inc.minor, compile" description="Dest Task"/>

</project>

Solution 3

Build Process

  1. build_info.properties will be created during build in your project folder You could write all information about your build in this file.
    • Like build number, major and minor numbers of release, timestamp, and revision number.
  2. Your build script can modify these values how ever your want
  3. After the build was successfull commit the file 'build_info.properties' back to the repository

During Development

After first build the file build_info.properties will be placed in the repository. You can change and commit any number (major, minor, build numbers) by your self when ever you want, or increase it automatically during build like build.number in the example below.

svnant Example

Using svnant 1.3.0:

<target name="checkout">
    <echo>Checking out revision ${param_SubProjectSvnREV} of project: ${param_SubProjectSvnName}</echo>
    <svn username="${svnant.repository.user}" password="${svnant.repository.passwd}">
        <checkout url="${svnant.latest.url}/${param_SubProjectSvnName}/" revision="${param_SubProjectSvnREV}" destPath="${all.projects.dir}/${param_SubProjectDirName}" />
        <info target="${all.projects.dir}/${param_SubProjectDirName}" ></info>
    </svn>
    <propertyfile  file="${all.projects.dir}/${param_SubProjectDirName}/build_info.properties" comment="Modify build numbers in a properties file.">
        <entry key="build.number" type="int" operation="+" value="1" pattern="00"/><!--increment it here -->
        <entry key="build.revision" type="string" value="${svn.info.rev}"/>
        <entry key="build.major.number" default="01"/><!-- can do some logic here to increase the values, or write value from somewhere else-->
        <entry key="build.minor.number" default="01"/><!-- can do some logic here to increase the values, or write value from somewhere else-->
    </propertyfile>
</target>

<target name="compile" depends="checkout">
    <property file="${all.projects.dir}/${param_SubProjectDirName}/build_info.properties" />
    <mkdir dir="${release.name}/${param_SubProjectDirName}/${build.major.number}.${build.minor.number}.${build.number}" />
    <!-- compile it to the new folder, an so on... -->
    <!-- after all, if the build wass successfull, commit the file 'build_info.properties' back to repository --> 
</target>

Solution 4

The easiest way of doing this is to change the problem. Instead of making the Any build do this for you, have whatever process that you're calling Ant calculate what the version number should be, and then pass that in as a property e.g.

ant -Dbuild.version=1.2.3

This has the flexibility of whatever build you're working with being able to take its cue from whatever, such as the SVN revision, the current date and time, or whatever.

ant -Dbuild.version=svnversion .

ant -Dbuild.version=date +"%Y%m%d%H%D"

ant -Dbuild.version=${major}.svnversion ..date +"%Y%m%d%H%D"

etc. You can get pretty comprehensive if you want.

If you want to have an ever incrementing number, then you can store it in a file and then pass that in at compile time. For example, you can do:

VER=cat build.version VER=$((VER+1)) echo $VER > build.version

Lastly, if you really want this to be in the build.xml file, the best thing to do is have a separate task to execute the increment-and-build option and fork off a nested ant build with your 'main' target. You'd thus end up with

ant -> ant -Dbuild.version=1.2.3.4 -> ...

In other words, given your build.xml with a (current) default of 'build', then change it to 'version' and have the ant 'version task do the calculation followed by a nested call to and build.

Implementation is left as an exercise to the reader, as is translating the approach to a non-UNIX platform.

Solution 5

This was a while ago, so this is from memory:

I build a custom CruiseControl.Net labeller block that ticked up the build number on each build. It maintained an XML file with all 4 components of the version number and identified each project by name (so it could support multiple projects).

The four values it generated get passed to the build process (nAnt, in our case), which had the responsibility of tweaking all the AssemblyInfo.cs files to reflect the proper build number.

Edited to note: The only value that get automatically ticked up was the build number. Major/Minor version numbers were specified in the CC.Net project configuration. The build number restarted at 0001 for each change in major or minor revision number (e.g., if you went from version 7.1 to version 7.3, for instance, the 7.1 build might be at build number 783, but the first 7.3 build started with build number 1; the next 7.1 build would be build 784.

Change version numbers merely required tweaking 1 setting the CC.Net config file.

Share:
29,571
Dave Jarvis
Author by

Dave Jarvis

https://dave.autonoma.ca/blog/

Updated on May 06, 2020

Comments

  • Dave Jarvis
    Dave Jarvis about 4 years

    How would you write a build.xml file, using neither custom code nor external dependencies (such as a shell script), that:

    • Generates a build number of the form major.minor.revision (e.g., 01.02.34).
    • Auto-increments the revision on each compile of the source code.
    • Auto-increments the minor version on each execution of a dist(ribution) task.

    Additionally:

    • Provides an option to increment the major number.
    • Provides an option to increment the minor number.
    • Whenever the major number is incremented, the minor and revision numbers are set to 0.
    • Whenever the minor number is incremented, the revision number is set to 0.

    Bonus:

    • Creates a variable based on the git revision number (like a subversion revision number).

    Clarification:

    • Automatic checkout (or commit) is not required.
    • Integration with Subversion is not desired.

    Thank you for any examples. Here are some related sites that describe how to perform similar tasks:

  • AlBlue
    AlBlue over 14 years
    Bear in mind that Git doesn't have the concept of an incrementing version number. Git revisions are SHA hashes and are non numeric (typically, they're represented in hex, though of course it does represent a number under the covers). However, the key important thing is that it's not an ever-increasing number, but rather takes disjoint hops (both up and down) across the numeric spectrum. In addition, the constraints you put on the requirement are inconsistent. You don't want any external dependencies, yet you've got Git, and presumably Ant as well.
  • Dustin
    Dustin over 14 years
    Git does have a concept of incrementing numbers. You tag (properly, using -s or -a) when you have a version that's interesting. You use describe to get a unique, human-readable version number from your tree.
  • AlBlue
    AlBlue over 14 years
    Dustin, The version number obtained by git describe isn't unique across all distributed repositories; and in any case, is a combination of the tag and the number of commits to the (local) repository since then. Things like rebasing or squashing commits can result in identical numbers but different content.
  • dz.
    dz. over 14 years
    using <buildnumber> things get much easier. But calculating an SHA1 checksum without the buildnumber in the file isn't an option. My old rule turns true: optional tasks makes the solution more complex.
  • Wirone
    Wirone almost 12 years
    Could you explain how major, minor and revision are incremented? I understand <entry> tasks, but I don't know when targets are called. Is it only for Java? I wanted to do such things with jQuery plugin project (building with Closure Compiler), is it possible?
  • Christopher Perry
    Christopher Perry almost 12 years
    @Wirone This explains a bit, although I'm not sure what a "distribution" task would be: en.wikipedia.org/wiki/Software_versioning
  • user2071938
    user2071938 over 8 years
    I have used this ant script, my problem is that I export a jar file after that. But the version numbers in the propertyfile are not yet updated when I create the jar. I use the versionnumber in the filename of my jar
  • Vasile Surdu
    Vasile Surdu about 8 years
    @Wirone use conditions like this <target name="increase.minor" if = "microEquals9andMinorNotEquals9"> <propertyfile file="build.properties"> <entry key="minor.number" default="0" operation="+" pattern="0" type="int"/> <entry key="micro.number" value="0" operation="=" pattern="0" type="int"/> </propertyfile> </target> <condition property="microEquals9andMinorNotEquals9"> <and> <equals arg1="${micro.number}" arg2="9"/> <not><equals arg1="${minor.number}" arg2="9"/></not> </and> </condition>