汇编和编号项目的版本 Java /ant, cvs, hudson/

项目管理编号组件和项目中版本号的现代建议是什么? Java? 具体来说:

如何系统地管理分布式开发环境中的装配号

如何在源代码中保存版本号 / 可用于应用程序环境

如何与源存储库集成

如何自动管理版本号和存储库标记

如何与连续装配基础设施集成

有很多可访问的工具,而且 ant /我们使用的装配系统/ 有一个支持装配号的任务,但目前尚不清楚如何使用几个并行开发人员管理这一点 CVS, svn 或类似的。

[EDIT]

一些良好和有用的部分或特定答案出现在下面,所以我将总结其中一些。 在我看来,事实上它不是很强烈 "best practice", 而且是一系列相交的想法。 下面您会发现我的简历和一些人们可以尝试作为随访回答的一些问题。 [新的 stackoverflow... 如果我做错了,请提供评论。]

如果您正在使用 SVN, 这次旅行您需要管理特定检查的版本。 装配编号可以使用它来创建一个唯一的装配号,标识特定的装配号 checkout/revision. [CVS, 我们在过时的原因使用的是,没有提供这样的理解水平...使用标签的手动干预将帮助您部分实现它。]

如果您正在使用 maven 作为装配系统,支持创建版本的版本 SCM, 和自动版本的释放模块。 [我们不能使用 maven 由于各种原因,但它有助于那些能够的人。 [谢

]]

如果您正在使用
http://ant.apache.org
作为装配系统,以下任务说明可以帮助创建文件。 Java .properties 随着装配信息,然后可以通过多种方式将其卷入您的组装中。 [我们通过包括从Hudson收到的信息,扩大了这个想法

].

Ant 和 maven /和 hudson 和巡航控制/ 提供用于将装配号的简单工具提供给文件。 .properties 或文件。 a .txt/.html 文件。 够了吗 "safe", 保护它免受刻意或随机干预吗? 也许最好将其编译成课程 "versioning" 在大会期间?

批准:必须确定编号组件/在持续集成系统中进入行动,例如
http://hudson-ci.org/
. [谢谢

] 我们接受了这一提议,但它没有透露释放的工程问题:释放如何? 释放中是否有几个装配号? 来自不同问题的装配号之间是否有重大连接?

问题:大会号码背后的目标是什么? 它被用来了 QA? 但怎么做? 它主要由开发人员使用,消除在开发期间或更多内容的多个组件之间的模糊性 QA, 确定哪个大会收到了最终用户? 如果目标是可重复性,那么理论上,它正是这应该提供版本号的版本号。 - 为什么不? /请作为下面答案的一部分回答它,它将有助于突出您的选择 made/suggested.../

问题:手动组件中是否有装配号码的位置? 这是如此有问题 EVERYONE 必须使用解决方案 CI?

问题:如果装配号码应返回 SCM? 如果目标是可靠地和明确地定义特定的装配,如何应对可以的各种连续或手动组装系统 crash/restart/etc...

问题:大会号码是否应该短而甜美 /即单调增加整数/, 要简单地将其插入存档的文件名中,很容易在通信等中引用它等......或者它应该是长而充满用户名,日期标签,机器名称等?

问题:请提供有关如何分配大会数字的详细信息适合您的更大的自动发布过程。 是的, 64 情人,我们知道它做了什么,但我们所有人都已经喝了Kul-Eid ......

我真的想在完整的答案中指定它,至少是我们安装的具体示例 cvs/ant/hudson, 对于某人可以根据这个问题建立一个完整的战略。 我注意到 "The Answer" 任何可以给予描述的人 soup-to-nuts 对于这种特殊的情况 /包括标记电路 cvs, 相关配置元素 CI 和一个折叠装配号的发布过程,以便以编程方式访问它。/ 如果你想问/回复其他特定配置 /让我们说 svn/maven/cruise control/, 我将从这里联系这个问题。 --JA

[EDIT 23 10月 09]
我接受了最佳投票的答案,因为我认为这是一个合理的决定,而其他一些答案也包括好主意。 如果有人想要尝试综合其中一些

, 我会考虑另一个人的接受。 在Marti-Lamb的情况下唯一令我困扰我的是,它不会可靠地序列化了装配号,这取决于构建器系统中的本地时钟,以确保不含明确的装配号,这不是很好。

[编辑 10 七月]

现在我们打开类似于以下内容的课程。 这允许您将版本编译到最终可执行文件。 在日记数据中生成各种形式的版本信息,长期存档输出产品并用于 trace 我们的 /有时多年/ 特定装配的输出产品分析。


public final class AppVersion
{
// SVN should fill this out with the latest tag when it's checked out.

private static final String APP_SVNURL_RAW =
"$HeadURL: svn+ssh://user@host/svnroot/app/trunk/src/AppVersion.java $";
private static final String APP_SVN_REVISION_RAW = "$Revision: 325 $";

private static final Pattern SVNBRANCH_PAT =
Pattern.compile/"/branches|trunk|releases/\\//[\\w\\.\\-]+/\\/.*"/;
private static final String APP_SVNTAIL =
APP_SVNURL_RAW.replaceFirst/".*\\/svnroot\\/app\\/", ""/;

private static final String APP_BRANCHTAG;
private static final String APP_BRANCHTAG_NAME;
private static final String APP_SVNREVISION =
APP_SVN_REVISION_RAW.replaceAll/"\\$Revision:\\s*",""/.replaceAll/"\\s*\\$", ""/;


static {
Matcher m = SVNBRANCH_PAT.matcher/APP_SVNTAIL/;
if /!m.matches/// {
APP_BRANCHTAG = "[Broken SVN Info]";
APP_BRANCHTAG_NAME = "[Broken SVN Info]";
} else {
APP_BRANCHTAG = m.group/1/;
if /APP_BRANCHTAG.equals/"trunk"// {
// this isn't necessary in this SO example, but it
// is since we don't call it trunk in the real case
APP_BRANCHTAG_NAME = "trunk";
} else {
APP_BRANCHTAG_NAME = m.group/2/;
}
}
}

public static String tagOrBranchName//
{ return APP_BRANCHTAG_NAME; }

/** Answers a formatter String descriptor for the app version.
* @return version string */
public static String longStringVersion//
{ return "app "+tagOrBranchName//+" /"+
tagOrBranchName//+", svn revision="+svnRevision//+"/"; }

public static String shortStringVersion//
{ return tagOrBranchName//; }

public static String svnVersion//
{ return APP_SVNURL_RAW; }

public static String svnRevision//
{ return APP_SVNREVISION; }

public static String svnBranchId//
{ return APP_BRANCHTAG + "/" + APP_BRANCHTAG_NAME; }

public static final String banner//
{
StringBuilder sb = new StringBuilder//;
sb.append/"\n----------------------------------------------------------------"/;
sb.append/"\nApplication -- "/;
sb.append/longStringVersion///;
sb.append/"\n----------------------------------------------------------------\n"/;
return sb.toString//;
}
}


如果值得成为讨论,请留下评论 wiki.
已邀请:

二哥

赞同来自:

对于我的几个项目,我写了版本号 subversion, 时间,用户运行程序集和一些系统信息,将它们放在文件中 .properties, 其中包含在申请中 jar, 并阅读它 jar 在执行期间。

代码 ant 如下:


 software revision number 
<property name="version" value="1.23"></property>
<target name="buildinfo">
<tstamp>
<format pattern="MM/dd/yyyy hh:mm aa" property="builtat" timezone="America/New_York"></format>
</tstamp>
<exec executable="svnversion" outputproperty="svnversion"></exec>
<exec executable="whoami" outputproperty="whoami"></exec>
<exec executable="uname" outputproperty="buildsystem"><arg value="-a"></arg></exec>
<propertyfile comment="This file is automatically generated - DO NOT EDIT" file="path/to/project.properties">
<entry key="buildtime" value="${builtat}"></entry>
<entry key="build" value="${svnversion}"></entry>
<entry key="builder" value="${whoami}"></entry>
<entry key="version" value="${version}"></entry>
<entry key="system" value="${buildsystem}"></entry>
</propertyfile>
</target>


很容易扩展以启用您可能想要添加的任何信息。

风见雨下

赞同来自:

你的

build.xml


...
<property name="version" value="1.0"></property>
...
<target depends="compile" name="jar">
<buildnumber file="build.num"></buildnumber>
<manifest file="MANIFEST.MF">
...
<attribute name="Main-Class" value="MyClass"></attribute>
<attribute name="Implementation-Version" value="${version}.${build.number}"></attribute>
...
</manifest>
</target>
...


你的代码 java


String ver = MyClass.class.getPackage//.getImplementationVersion//;

卫东

赞同来自:

软件:

SVN

Ant

哈德森持续集成

svntask, 一个任务 Ant 找到 SVN 修订: http://code.google.com/p/svntask/

哈德森有三个 builds/jobs: 连续,夜晚和舞会。

对于连续的 / 夜总会:装配号是修订版 SVN, 找到了帮助 svntask.

释放 build/job: 装配号码 - 这是一个释放号码,可读 Ant 从属性文件。 属性文件也可以与释放一起分发以在执行期间显示装配号。

剧本汇编 Ant 将装配号放在文件清单文件中 jar/war, 在大会期间创建。 适用于所有组件。

装配毕业组件后的动作,易于使用插件进行 Hudson: tag SVN 随着装配号。

好处:

为了 dev 版本 A jar/war, 开发人员可以找到版本 SVN 的 jar/war 并看到相应的代码 SVN

版本版本 SVN 对应于tagu. SVN, 其中指定了释放号码。

我希望它会有所帮助。

董宝中

赞同来自:

装配号必须与连续集成服务器相关联,例如
http://hudson-ci.org/
. 使用不同的任务 branches/teams/distributions.

要在最终组装中保存版本号,我建议只需使用
http://maven.apache.org
构建一个系统。 它将创建一个文件 .properties, 存档在决赛中 .jar/.war/.whatever-ar 在
META-INF/maven/<project group="">/<project id="">/pom.properties

. 文件 .properties 将包含一个财产 version.

因为我推荐 maven, 我强烈推荐你检查
http://maven.apache.org/plugin ... .html
, 准备源文本的存储库中的版本并保存版本同步。
</project></project>

石油百科

赞同来自:

我也使用Hudson,虽然是一个简单的脚本:

在我的场景中 Ant 有一个看起来像这样的目标:


<target name="build-number">
<property environment="env"></property>
<echo append="false" file="${build.dir}/build-number.txt">Build: ${env.BUILD_TAG}, Id: ${env.BUILD_ID}, URL: ${env.HUDSON_URL}</echo>
</target>


哈德森在执行工作时为我设置这些环境变量。

在我的情况下,这个项目是一个Web应用程序,我打开这个文件。
build-number.txt

在根文件夹Web中 - 应用程序 - 我不在乎谁看到它。

我们在完成后不标记版本控制系统,因为我们已经有了任务 Hudson, 用装配号标记它/timestamp, 当大会成功时。

我的决定只涵盖了发展的增量组装数量,我们在项目中没有足够高达,我们涵盖了释放的发布。

冰洋

赞同来自:

你也可以看看插件 BuildNumber Maven 和任务 Ant 在一个 jar, 在发现
http://code.google.com/p/codeb ... umber
. 我试过一切都很简单易懂。 这是一个非常小的文件。 jar, 仅取决于已安装的命令行subversion。

龙天

赞同来自:

这就是我解决这个问题的方式:

源文件将复制到装配目录

然后应用 anttask "versioninfo"

修改来源的汇编

这是一个文件 java, 存储有关版本的信息:


public class Settings {

public static final String VERSION = "$VERSION$";
public static final String DATE = "$DATE$";

}


这是andtast "versioninfo":


 ================================= 
target: versioninfo
=================================
<target depends="init" description="gets version info from svn" name="versioninfo">
<!--
get svn info from the src folder
-->
<typedef classpathref="ant.classpath" resource="org/tigris/subversion/svnant/svnantlib.xml"></typedef>
<svnsetting dateformatter="dd.MM.yyyy" id="svn.setting" javahl="false" svnkit="true"></svnsetting>
<svn refid="svn.setting">
<info target="src"></info>
</svn>
<!--
if repository is a taged version use "v <tagname>"
else "rev <revisionnumber> /SVN/" as versionnumber
-->
<taskdef classpathref="ant.classpath" resource="net/sf/antcontrib/antcontrib.properties"></taskdef>
<propertyregex defaultvalue="rev ${svn.info.lastRev} /SVN/" input="${svn.info.url}" override="true" property="version" regexp=".*/tags//.*//${ant.project.name}/src" select="v \1"></propertyregex>
<!--
replace date and version in the versionfile //
-->
<replace file="build/${versionfile}">
<replacefilter token="$DATE$" value="${svn.info.lastDate}"></replacefilter>
<replacefilter token="$VERSION$" value="${version}"></replacefilter>
</replace>
</target>

涵秋

赞同来自:

这是我的 2 美分:

我的装配脚本创建了装配号 /从 timestamp!/ 每次我创建一个应用程序。 它创造了太多数字,但永远不会太少。 如果我在代码中有更改,则装配号将至少更改一次。

我希望每个版本都有装配号 /虽然不在他们之间/. 当我更新项目并获取新的装配号时 /因为别人发布了/, 我重写我的本地版本并重新开始。 它可以导致较低的装配号码,所以我打开了 timestamp.

发生释放时,将装配号固定为与消息的一个固定中的最后一个元素 "build 1547". 之后,当这是官方版本时,所有树都标记为。 因此,装配文件始终包含所有标记,并且有一个简单的比较。 1:1 在标签和装配号之间。

[EDIT] 我部署 version.html 使用我的项目,然后我可以使用刮刀来收集一个准确的地图,在哪里安装。 如果您正在使用 Tomcat 或类似的东西,放置装配号码和 timestamp 在元素中
description

http://e-docs.bea.com/wls/docs ... 13555
. 记住:当您可以为您提供电脑时,从不记得任何内容。

詹大官人

赞同来自:

我们推出了我们的大会 CruiseControl /在这里插入您最喜爱的装配经理/ 并执行主要构建和测试。

然后我们增加版本号 Ant 和
http://ant.apache.org/manual/T ... .html
并使用此信息创建属性文件,以及装配日期和其他元数据。

我们有一个致力于这个的课程并提供它 GUIs / logs 等等。

然后我们打包所有这些并创建部署的装配号和相应的组件。 我们所有的服务器在启动时重置此元信息。 我们可以返回杂志 CruiseControl 并将装配号绑定到日期并检查。

要回复问题请先登录注册