[解決済み] Javaプロジェクトのビルドとバージョン番号付け (ant、cvs、hudson)
質問
Java プロジェクトにおいて、ビルド番号とバージョン番号を体系的に管理するための現在のベストプラクティスは何ですか? 具体的には
-
分散開発環境におけるビルド番号の体系的な管理方法
-
ソース内のバージョン番号を管理する方法 / 実行時アプリケーションで利用できるようにする方法
-
ソースリポジトリと適切に統合する方法
-
バージョン番号とリポジトリタグをより自動で管理する方法
-
継続的ビルドインフラと統合する方法
かなり多くのツールがあり、ant(私たちが使っているビルドシステム)にはビルド番号を管理するタスクがありますが、CVSやsvnなどを使って複数の同時開発者がいる場合、これをどのように管理するかは明らかではありません。
[編集]
いくつかの良い、役に立つ部分的または具体的な回答が以下に現れましたので、そのうちのいくつかを要約してみます。 これについては、強力なベスト プラクティスがあるわけではなく、むしろ重複するアイデアの集合体であるように思えます。 以下に、私の要約と、人々がフォローアップとして答えようとするかもしれない、いくつかの質問を掲載します。 [スタックオーバーフローの初心者なので、私が間違っていたらコメントをください。]
-
SVN を使用している場合、特定のチェックアウトのバージョニングは、一緒にやってきます。 ビルド番号付けは、特定のチェックアウト/リビジョンを識別する一意のビルド番号を作成するために、これを悪用することができます。 [レガシーな理由で使用している CVS では、このレベルの洞察は得られません...タグによる手動介入で、ある程度は可能です]。
-
ビルドシステムとして maven を使用している場合、SCM からバージョン番号を生成するためのサポートと、自動的にリリースを生成するためのリリースモジュールが用意されています。 [私たちはさまざまな理由で maven を使用できませんが、これは使用できる人たちの助けになります。 [ありがとうございました。 marcelo-morales ]]
-
もし、あなたが を使用している場合 をビルドシステムとして使用している場合、次のタスクの説明は、ビルド情報をキャプチャするJava .propertiesファイルを生成するのに役立ち、その後、多くの方法でビルドに組み込むことができます。 [私たちはこのアイデアを拡張して、hudson 由来の情報を含むようにしました。 marty-lamb ].
-
Ant と maven (および hudson と cruise control) は、ビルド番号を .properties ファイルに、または .txt/.html ファイルに取得するための簡単な手段を提供します。 これは、意図的または偶発的に改ざんされることを防ぐのに十分な安全性でしょうか? ビルド時にバージョン管理クラスにコンパイルする方が良いのでしょうか?
-
断言します。ビルドナンバリングは、以下のような継続的インテグレーションシステムで定義/実行されるべきです。 ハドソン . [ありがとうございます マルセロモラレス ] 私たちはこの提案を受け止めましたが、リリースエンジニアリングの問題に風穴を開けてしまいました。 リリースはどのように行われるのですか? 1 つのリリースに複数の buildnumber があるのでしょうか? 異なるリリースの buildnumber の間に意味のある関係があるのでしょうか?
-
質問です。ビルド番号の背景にはどのような目的があるのでしょうか? QA に使用されるのですか? どのようにですか? 開発中に複数のビルドを区別するために開発者が主に使うのですか、それともエンドユーザがどのビルドを取得したかを判断するために QA がより多く使うのですか? もし目標が再現性であるなら、理論的にはリリースのバージョン番号はこれを提供するはずですが、なぜそうしないのですか? (これは、あなたが行った/提案した選択を明らかにするのに役立ちます。)
-
質問です。手動ビルドにビルド番号のための場所はありますか? これは、すべての人が CI ソリューションを使用する必要があるほど問題なのでしょうか?
-
質問です。ビルド番号は SCM にチェックインされるべきでしょうか? もし目標が特定のビルドを確実かつ曖昧さなく識別することであるなら、クラッシュ/再起動/その他を起こしうるさまざまな継続的または手動ビルド システムにどのように対処したらよいでしょうか......。
-
質問です。ビルド番号は、アーカイブ用のファイル名に貼り付けるのが簡単で、通信などで参照しやすいように、短くて甘い (すなわち、単調に増加する整数) べきでしょうか。それとも長くて、ユーザー名、日付スタンプ、マシン名などでいっぱいにすべきでしょうか。
-
質問です。ビルド番号の割り当てが、より大きな自動化されたリリース プロセスにどのように適合するかについて、詳細を説明してください。 そうです、maven の愛好家たちよ、これが完了したことは知っていますが、私たちのすべてがまだクーレイドを飲んだわけではありません...。
私は本当に、少なくとも私たちのcvs/ant/hudsonセットアップの具体例について、この質問を基に完全な戦略を構築できるように、これを完全な答えに具体化したいと思います。 この特定のケースについて、全体的な説明 (cvs タグ付けスキーム、関連する CI 設定項目、プログラム的にアクセスできるようにビルド番号をリリースに折り込むリリース手順など) ができる人を "The Answer" としてマークしておきます。 もし、他の特定の設定(例えば、svn/maven/cruise control)について質問/回答したい場合は、ここからその質問にリンクします。--JA
[09年10月23日編集] 他のいくつかの回答にも良いアイデアが含まれていますが、私はそれが合理的な解決策だと思うので、一番上に投票された回答を受け入れました。 他のいくつかの回答にも良いアイデアが含まれています。 marty-lamb のものと合成することを望む人がいれば、私は別のものを受け入れることを検討します。 marty-lamb の唯一の懸念は、信頼できるシリアル化されたビルド番号を生成しないことです -- ビルド番号を明確にするために、ビルダーのシステムのローカル クロックに依存していますが、これはあまりよくありません。
[7月10日編集]
現在、以下のようなクラスが含まれています。 これにより、バージョン番号が最終的な実行ファイルにコンパイルされるようになります。 バージョン情報の異なる形式は、ログ データ、長期アーカイブされた出力製品、および出力製品の私たちの分析 (時には数年後) を特定のビルドに追跡するために使用される際に出力されます。
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 のリビジョン番号、時間、ビルドを実行したユーザー、およびいくつかのシステム情報をキャプチャし、アプリケーション jar に含まれる .properties ファイルにそれらを詰め込み、実行時にその jar を読み込んでいます。
antのコードは次のようになります。
<!-- software revision number -->
<property name="version" value="1.23"/>
<target name="buildinfo">
<tstamp>
<format property="builtat" pattern="MM/dd/yyyy hh:mm aa" timezone="America/New_York"/>
</tstamp>
<exec executable="svnversion" outputproperty="svnversion"/>
<exec executable="whoami" outputproperty="whoami"/>
<exec executable="uname" outputproperty="buildsystem"><arg value="-a"/></exec>
<propertyfile file="path/to/project.properties"
comment="This file is automatically generated - DO NOT EDIT">
<entry key="buildtime" value="${builtat}"/>
<entry key="build" value="${svnversion}"/>
<entry key="builder" value="${whoami}"/>
<entry key="version" value="${version}"/>
<entry key="system" value="${buildsystem}"/>
</propertyfile>
</target>
これを拡張して、追加したい情報を入れるのは簡単です。
関連
-
java の例外が発生しました java
-
プロローグでのコンテンツは禁止されています
-
Eclipseプロンプトを実行する java仮想マシンを使用しない
-
node js npm gruntインストール、elasticsearch-head 5.Xインストール
-
spring aop アドバイスからの Null 戻り値が、サマリーのプリミティブ戻り値と一致しない。
-
SocketTimeoutExceptionの解決方法です。読み込みがタイムアウトした
-
このラインで複数のマーカーを解決する方法
-
[解決済み] クライアントにJavaScriptファイルを強制的に更新させるには?
-
[解決済み】Mavenの親POMとモジュールPOMの比較
-
[解決済み] アセンブリのバージョン番号を管理するためのベストプラクティス/ガイダンス
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
java.util.NoSuchElementException 原因解析と解決方法
-
エラーが報告されました。リソースの読み込みに失敗しました:サーバーは500(内部サーバーエラー)のステータスで応答しました。
-
をインスタンス化することができません。
-
エラーの解決方法 jarfile XXX.jarにアクセスできません。
-
スレッド "main" での例外 java.lang.ArrayIndexOutOfBoundsException: 1
-
スレッド "main" で例外発生 java.lang.ArrayIndexOutOfBoundsException: 4 at text.Division.main(Divisi
-
node js npm gruntインストール、elasticsearch-head 5.Xインストール
-
Javaエラーメッセージがenclosingクラスでない
-
java.lang.NoClassDefFoundError: org.apache.jasper.el.ELContextImpl クラスを初期化できませんでした。
-
スレッド "main" で例外発生 java.net.BindException: アドレスは既に使用中です。NET_Bind