【问题标题】:Build numbers: major.minor.revision内部版本号:major.minor.revision
【发布时间】:2009-09-16 06:37:07
【问题描述】:

您将如何编写一个build.xml 文件,既不使用自定义代码也不使用外部依赖项(例如 shell 脚本):

  • 生成major.minor.revision 形式的内部版本号(例如,01.02.34)。
  • 在每次编译源代码时自动增加修订。
  • 在每次执行分发(分发)任务时自动增加次要版本。

另外:

  • 提供增加主编号的选项。
  • 提供增加次要编号的选项。
  • 每当主版本号增加时,次版本号和修订版本号都会设置为 0。
  • 每当次要编号增加时,修订号都会设置为 0。

奖金:

  • 根据git 修订号(如颠覆修订号)创建一个变量。

澄清:

  • 不需要自动签出(或提交)。
  • 不希望与 Subversion 集成。

感谢您提供任何示例。以下是一些描述如何执行类似任务的相关网站:

【问题讨论】:

    标签: java ant build-process versioning


    【解决方案1】:

    build_info.properties 文件:

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

    build.xml 文件:

    <?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>
    

    【讨论】:

    • 您能解释一下majorminorrevision 是如何递增的吗?我了解&lt;entry&gt; 任务,但我不知道何时调用目标。它仅适用于Java吗?我想用 jQuery 插件项目(用 Closure Compiler 构建)做这样的事情,有可能吗?
    • @Wirone 这解释了一点,虽然我不确定“分发”任务是什么:en.wikipedia.org/wiki/Software_versioning
    • 我用过这个ant脚本,我的问题是之后导出了一个jar文件。但是当我创建 jar 时,属性文件中的版本号尚未更新。我在我的 jar 文件名中使用版本号
    • @Wirone 使用条件像这样
    【解决方案2】:

    如果选择了编译或 dist 目标,此解决方案会自动增加次要或修订号。如果设置了以下属性之一,则可以关闭增量:

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

    如果属性 inc.major 已设置,则主编号将递增,其他两个值都将设置为零。 SHA-1 校验和由版本文件的文本表示计算。

    顺便说一句:如果允许的话,您可以在 Java 脚本中创建自己的 ant 任务,该脚本包含在 JDK 6 中。

    现在是 ant 文件

    <?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>
    

    【讨论】:

    • 使用 事情变得容易多了。但是在文件中没有内部版本号的情况下计算 SHA1 校验和不是一种选择。我的旧规则变成了现实:可选任务使解决方案更加复杂。
    【解决方案3】:

    构建过程

    1. build_info.properties 将在您的项目构建期间创建 文件夹 您可以在此文件中写入有关您的构建的所有信息。
      • 例如版本号、主要和次要版本号、时间戳和修订号。
    2. 您的构建脚本可以 修改这些值 想要
    3. 构建成功后,将文件“build_info.properties”提交回 存储库

    开发过程中

    第一次构建后,文件 build_info.properties 将被放置在存储库中。 您可以随时自行更改和提交任何数字(主要、次要、内部版本号),或者在构建过程中自动增加它,例如下面示例中的 build.number。

    svnant 示例

    使用 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>
    

    【讨论】:

      【解决方案4】:

      最简单的方法是改变问题。不要让 Any 构建为您执行此操作,而是让您调用 Ant 的任何过程计算版本号应该是什么,然后将其作为属性传递,例如

      ant -Dbuild.version=1.2.3

      这具有您正在使用的任何构建的灵活性,能够从任何内容中获取提示,例如 SVN 修订版、当前日期和时间等。

      ant -Dbuild.version=svnversion .

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

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

      等等。如果你愿意,你可以得到相当全面的。

      如果你想要一个不断递增的数字,那么你可以将它存储在一个文件中,然后在编译时将其传递进去。例如,您可以这样做:

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

      最后,如果你真的希望它出现在 build.xml 文件中,最好的办法是有一个单独的任务来执行 increment-and-build 选项并用你的“main”分叉一个嵌套的 ant 构建目标。因此,您最终会得到 ​​p>

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

      换句话说,给定您的 build.xml 的(当前)默认值为“build”,然后将其更改为“version”,并让 ant 的“version”任务进行计算,然后嵌套调用并构建。

      实现留给读者作为练习,将方法转换为非 UNIX 平台也是如此。

      【讨论】:

      • 请记住,Git 没有递增版本号的概念。 Git 修订版是 SHA 哈希值并且是非数字的(通常,它们以十六进制表示,尽管它确实代表了一个隐藏的数字)。然而,关键的重要一点是它不是一个不断增加的数字,而是在整个数字范围内进行不相交的跳跃(向上和向下)。此外,您对需求的约束是不一致的。你不想要任何外部依赖,但你已经有了 Git,大概还有 Ant。
      • Git 确实有递增数字的概念。当你有一个有趣的版本时,你标记(正确地,使用 -s 或 -a)。您使用describe 从您的树中获取一个唯一的、人类可读的版本号。
      • Dustin,通过 git describe 获得的版本号在所有分布式存储库中并不是唯一的;并且在任何情况下,是标签和从那时起提交到(本地)存储库的数量的组合。诸如变基或压缩提交之类的事情可能会导致相同的数字但不同的内容。
      【解决方案5】:

      这是不久前的事情,所以这是凭记忆:

      我构建了一个自定义 CruiseControl.Net 贴标器块,用于在每个构建中标记构建号。它维护了一个包含版本号的所有 4 个组件的 XML 文件,并通过名称识别每个项目(因此它可以支持多个项目)。

      它生成的四个值被传递给构建过程(在我们的例子中是 nAnt),它负责调整所有 AssemblyInfo.cs 文件以反映正确的构建号。

      编辑注意:唯一会自动勾选的值是内部版本号。在 CC.Net 项目配置中指定了主要/次要版本号。对于主要或次要修订号的每次更改,内部版本号都从 0001 重新开始(例如,如果您从版本 7.1 转到版本 7.3,例如,7.1 版本可能在内部版本号 783,但第一个 7.3 版本从内部版本号开始1;下一个 7.1 版本将是 784 版本。

      更改版本号只需要调整 1 设置 CC.Net 配置文件。

      【讨论】:

        【解决方案6】:

        在我的项目中,我不会自动增加次要编号和主要编号。我们从全局构建属性中设置它。像这样:

        <entry key="build.major.number" value="${global.release.major}"></entry> 
        <entry key="build.minor.number" value="${global.release.minor}"></entry>
        

        这是因为它们将针对发布(而不是测试或其他构建)进行更改,并与其他来源一起提交(我们已经能够构建一些旧版本或分支版本)。

        但如果你想增加次要号码,你可以像我的例子中的内部版本号那样做。

        <entry key="build.major.number" type="int" operation="+" default="1" pattern="00"/>
        

        【讨论】:

          【解决方案7】:

          我们可以使用条件来检查是否应该增加微版本,次要版本和主要版本。

          如果 micro 为 9,则增加小数,依此类推。

                <target name="increaseBuildNumber" depends="increase.micro, increase.minor, increase.major" description="Increase Build Number"/>
          
                <target name="increase.micro" if ="microNotEquals9">
                      <propertyfile file="build.properties">
                          <entry key="micro.number" default="0" operation="+"    pattern="0" type="int"/>
                      </propertyfile>
          
              </target>
          
              <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>
          
              <target name="increase.major" if = "microAndMinorEquals9" >
                      <propertyfile file="build.properties">
                          <entry key="major.number" default="0" operation="+" pattern="0" type="int"/>
                          <entry key="minor.number" value="0" operation="=" pattern="0" type="int"/>
                          <entry key="micro.number" value="0" operation="=" pattern="0" type="int"/>
                      </propertyfile>
          
          
              </target>
          
              <condition property="minorEquals9"> 
                     <equals arg1="${minor.number}" arg2="9"/>
              </condition>
          
              <condition property="microEquals9andMinorNotEquals9"> 
                      <and> 
                          <equals arg1="${micro.number}" arg2="9"/> 
                          <not><equals arg1="${minor.number}" arg2="9"/></not>
                      </and>
              </condition>
          
              <condition property="microAndMinorEquals9"> 
                      <and> 
                          <equals arg1="${micro.number}" arg2="9"/> 
                          <equals arg1="${minor.number}" arg2="9"/>
                      </and>
              </condition>
          
              <condition property="microNotEquals9"> 
                      <not><equals arg1="${micro.number}" arg2="9"/></not>
              </condition>
          

          【讨论】: