Javaプロジェクトにおける体系的なビルド番号付けとバージョン番号管理の現在のベストプラクティスは何ですか?具体的には:
分散開発環境で体系的にビルド番号を管理する方法
ソース内のバージョン番号を維持する方法/ランタイムアプリケーションで利用可能
ソースリポジトリと適切に統合する方法
バージョン番号とリポジトリタグをより自動的に管理する方法
継続的ビルドインフラストラクチャと統合する方法
非常に多くのツールが利用可能であり、ant(使用しているビルドシステム)にはビルド番号を維持するタスクがありますが、CVSやsvnなどを使用して複数の同時開発者がこれを管理する方法は明確ではありません。
[編集]
いくつかの優れた役立つ部分的または具体的な回答が以下に表示されているので、それらのいくつかを要約します。これには本当に強力な「ベストプラクティス」はなく、重複するアイデアのコレクションがあるように思えます。以下に、私の要約と、人々がフォローアップとして回答しようとする可能性があるいくつかの結果の質問を示します。[stackoverflowの新機能...これが間違っている場合はコメントを入力してください。]
SVNを使用している場合は、特定のチェックアウトのバージョン管理が行われます。ビルド番号はこれを利用して、特定のチェックアウト/リビジョンを識別する一意のビルド番号を作成できます。[レガシーの理由で使用しているCVSは、このレベルの洞察を提供していません...タグを手動で操作することで、その一部を実現できます。]
ビルドシステムとしてmavenを使用している場合、SCMからバージョン番号を生成するためのサポートと、リリースを自動的に生成するためのリリースモジュールがあります。[私たちはさまざまな理由でmavenを使用できませんが、これは使用できる人を助けます。[ マルセロモラルのおかげで]]
ビルドシステムとしてantを使用している場合、次のタスクの説明は、ビルド情報をキャプチャするJava .propertiesファイルを生成するのに役立ちます。これは、さまざまな方法でビルドに組み込むことができます。[このアイデアを拡張して、ハドソン派生の情報を含めました。おかげでmarty -lamb ]。
Antとmaven(およびhudsonとcruiseコントロール)は、ビルド番号を.propertiesファイルまたは.txt / .htmlファイルに取得する簡単な手段を提供します。これは、意図的または偶発的に改ざんされないように「安全」ですか?ビルド時にそれを「バージョン管理」クラスにコンパイルする方が良いですか?
アサーション:ビルド番号は、hudsonのような継続的インテグレーションシステムで定義/制定する必要があります。[ marcelo-moralesに感謝します ]この提案を採用しましたが、リリースエンジニアリングに関する質問を解き明かします。リリースはどのように行われるのですか?リリースに複数のビルド番号はありますか?異なるリリースのビルド番号の間に意味のある関係はありますか?
質問:ビルド番号の目的は何ですか?QAに使用されますか?どうやって?開発中に複数のビルド間を明確にするために主に開発者によって使用されていますか、それともQAがエンドユーザーが取得したビルドを特定するために使用されていますか?目標が再現性である場合、理論的にはこれがリリースバージョン番号で提供されるものです-なぜそうではないのですか?(以下の回答の一部としてこれに回答してください。これは、あなたが行った/提案した選択を明らかにするのに役立ちます...)
質問:手動ビルドでビルド番号の場所はありますか?これは問題があるので、誰もがCIソリューションを使用する必要がありますか?
質問:ビルド番号をSCMにチェックインする必要がありますか?目標が特定のビルドを確実かつ明確に識別することである場合、クラッシュ/再起動/などする可能性があるさまざまな継続的または手動のビルドシステムに対処する方法...
質問:ビルド番号は短くて甘いもの(つまり、単調に増加する整数)にする必要があります。これにより、アーカイブのためにファイル名を簡単に挿入したり、コミュニケーションなどで参照したりしやすくなります。日付スタンプ、マシン名など?
質問:ビルド番号の割り当てが大規模な自動リリースプロセスにどのように適合するかについて詳細を教えてください。はい、メイベン愛好家、私たちはこれが行われていることを知っていますが、私たち全員がまだクールエイドを飲んでいるわけではありません...
少なくともcvs / ant / hudsonのセットアップの具体例については、これを完全な答えに具体化して、誰かがこの質問に基づいて完全な戦略を構築できるようにしたいと思います。この特定のケース(cvsタグ付けスキーム、関連するCI構成項目、およびビルド番号をリリースに組み込んでプログラム的になるようにリリースするリリース手順を含む)についての説明を提供できる人は、「The Answer」としてマークしますアクセス可能。)別の特定の構成(たとえば、svn / maven / cruise control)について質問/回答したい場合は、ここから質問にリンクします。--JA
[編集10月23日09]他のいくつかの回答にも良いアイデアが含まれている一方で、それは合理的な解決策だと思うので、私はトップ投票の回答を受け入れました。これらのいくつかを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ディスカッションになるに値する場合は、コメントを残してください。
gradle
および/またはを使用するときに誰かが同様の簡単なアプローチを持っているかどうか疑問に思っていgit
ますか?