Javaプロジェクトのビルドとバージョン番号付け(ant、cvs、hudson)


134

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ディスカッションになるに値する場合は、コメントを残してください。


2
今後の読者のために、提案したコードのリビジョン番号はリポジトリのグローバルリビジョンではなく、ファイルのものであることに注意してください。詳細については、subversion.apache.org
faq.html#version

2
gradleおよび/またはを使用するときに誰かが同様の簡単なアプローチを持っているかどうか疑問に思っていgitますか?
bnjmn 2014年

回答:


63

私のいくつかのプロジェクトでは、subversionのリビジョン番号、時間、ビルドを実行したユーザー、およびいくつかのシステム情報をキャプチャし、それらを.propertiesファイルに入れてアプリケーションjarに含め、実行時にその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>

これを拡張して、追加したい情報を含めるのは簡単です。


12
クロスプラットフォームバージョンの場合は、上記のwhoamiプロパティの代わりにこれを使用します。<entry key = "builder" value = "$ {user.name}" />
Ed Brannin

プラットフォーム依存のソリューションがある場合は-1。antで利用可能なすべてのプロパティをファイルに入れるには、次のようにします。 `<property name =" antprops.file "location =" $ {build.temp.project.dir} /used_ant.properties "/> <echoproperties destfile =" $ {antprops.file} "/> <!-ファイルを並べ替えます。ant1.7.0以降の場合のみ!!!-> <concat> <union> <sort> <tokens> <file file =" $ {antprops .file} "/> <linetokenizer includedelims =" true "/> </ tokens> </ sort> </ union> </ concat>`
raudi

これを行った後、もう一度コミットしますか?または、これは実際のリビジョンをコミットする前に行われますか?
Charles Wood

6
gitリポジトリでこれを行う方法は?
TechCrunch 2014

46

あなたのbuild.xml

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

あなたのJavaコード

String ver = MyClass.class.getPackage().getImplementationVersion();

6
+1は、Javaがそのようなメソッドですでにサポートしているプロパティを使用するためのものです。
Ed Brannin、2010年

2
-1は、個別のプロパティファイルではなく、build.xmlにビルド番号を
含めるため

6
  • ビルド番号はhudsonのような継続的インテグレーションサーバーに関連付ける必要があります。異なるブランチ/チーム/ディストリビューションに異なるジョブを使用します。
  • 最終ビルドでバージョン番号を保持するには、ビルドシステムにmavenを使用することをお勧めします。最終的な.jar / .war / .whatever-arにアーカイブされた.propertiesファイルが作成されますMETA-INF/maven/<project group>/<project id>/pom.properties。.propertiesファイルには、バージョンプロパティが含まれます。
  • 私はmavenを推奨しているので、リリースプラグインをチェックして、ソースリポジトリのリリースを準備し、バージョンの同期を維持することをお勧めします。

6

ソフトウェア:

  • SVN
  • Hudson、継続的インテグレーション
  • svntask、SVNリビジョンを見つけるためのAntタスク:http://code.google.com/p/svntask/

Hudsonには、Continuous、Nightly、Releaseの3つのビルド/ジョブがあります。

継続的/夜間ビルドの場合:ビルド番号はsvntaskを使用して見つけたSVNリビジョンです。

リリースビルド/ジョブの場合:ビルド番号は、Antがプロパティファイルから読み取ったリリース番号です。プロパティファイルは、実行時にビルド番号を表示するためのリリースとともに配布することもできます。

Antビルドスクリプトは、ビルド中に作成されるjar / warファイルのマニフェストファイルにビルド番号を入れます。すべてのビルドに適用されます。

リリースビルドのビルド後のアクション。Hudsonプラグインを使用して簡単に実行できます。SVNにビルド番号をタグ付けします。

利点:

  • jar / warの開発バージョンの場合、開発者はjar / warからSVNリビジョンを見つけ、SVNで対応するコードを検索できます。
  • リリースの場合、SVNリビジョンは、リリース番号が含まれているSVNタグに対応するものです。

お役に立てれば。


リリースビルド/ジョブでビルド/リリース番号のプロパティファイルをチェックしてSVNに戻しますか?
matt b

継続的ビルドの場合、ビルド番号はSVNリビジョン番号です。したがって、チェックインするものは何もありません。リリースビルドの場合、ビルド番号の取得に使用されるのはチェックインされたファイルです。通常、リリースエンジニアや他の誰かは、リリースのかなり前にこのファイルを更新する必要があります。
ローリー、

4

私はHudsonも使用していますが、はるかに単純なシナリオです。

私のAntスクリプトには、次のようなターゲットがあります。

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

Hudsonは、ジョブが実行されるたびにこれらの環境変数を設定します。

私の場合、このプロジェクトはwebappであり、このbuild-number.txtファイルをwebappのルートフォルダーに含めています。

ビルドが成功したときにビルド番号/タイムスタンプでタグ付けするようにすでにHudsonジョブが設定されているため、これが行われるときはソース管理にタグを付けません。

私のソリューションは、開発用の増分ビルド番号のみをカバーしています。リリース番号をカバーしているプロジェクトでは、まだ十分ではありません。


さらに(少なくとも現在のjenkinsバージョンでは)次のプロパティを確認できます。`env.SVN_URL_1env.SVN_REVISION_1 env.SVN_URL_2 env.SVN_REVISION_2など
raudi

3

また、http: //code.google.com/p/codebistro/wiki/BuildNumberにある1つのjarでBuildNumber MavenプラグインとAntタスクを確認することもできます。私はそれをシンプルでわかりやすいものにしようとしました。これは、インストールされているコマンドラインSubversionにのみ依存する非常に小さなjarファイルです。


3

これは私がこれをどのように解決したかです:

  • ソースはビルドディレクトリにコピーされます
  • その後、anttask "versioninfo"が適用されます
  • 変更されたソースをコンパイルする

バージョン情報を格納するjavaファイルは次のとおりです。

public class Settings {

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

}

そしてここにanttask "versioninfo"があります:

    <!-- ================================= 
     target: versioninfo              
     ================================= -->
    <target name="versioninfo"
            depends="init"
            description="gets version info from svn"
    >

        <!-- 
        get svn info from the src folder 
        -->
        <typedef resource="org/tigris/subversion/svnant/svnantlib.xml"
                 classpathref="ant.classpath"
        />
        <svnSetting id="svn.setting"
                    javahl="false"
                    svnkit="true"
                    dateformatter="dd.MM.yyyy"
        />
        <svn refid="svn.setting">
            <info target="src" />
        </svn>

        <!-- 
        if repository is a taged version use "v <tagname>"
        else "rev <revisionnumber> (SVN)" as versionnumber
         -->
        <taskdef resource="net/sf/antcontrib/antcontrib.properties"
                 classpathref="ant.classpath"
        />
        <propertyregex property="version"
                       input="${svn.info.url}"
                       regexp=".*/tags/(.*)/${ant.project.name}/src"
                       select="v \1"
                       defaultvalue="rev ${svn.info.lastRev} (SVN)"
                       override="true"
        />


        <!-- 
        replace date and version in the versionfile ()
         -->
        <replace file="build/${versionfile}">
            <replacefilter token="$DATE$" value="${svn.info.lastDate}" />
            <replacefilter token="$VERSION$" value="${version}" />
        </replace>

    </target>

2

これが私の2セントです。

  • ビルドスクリプトは、アプリをビルドするたびにビルド番号(タイムスタンプ付き!)を作成します。これにより作成される数は多すぎますが、少なすぎることはありません。コードに変更がある場合、ビルド番号は少なくとも1回は変更されます。

  • すべてのリリースでビルド番号をバージョン管理します(ただし、中間ではありません)。プロジェクトを更新して新しいビルド番号を取得すると(他の誰かがリリースしたため)、ローカルバージョンを上書きしてやり直します。これによりビルド番号が低くなる可能性があるため、タイムスタンプを含めました。

  • リリースが発生すると、ビルド番号が1回のコミットの最後の項目としてコミットされ、「ビルド1547」というメッセージが表示されます。その後、公式リリースになると、ツリー全体にタグが付けられます。このように、ビルドファイルには常にすべてのタグがあり、タグとビルド番号の間には単純な1:1マッピングがあります。

[編集]プロジェクトにversion.htmlをデプロイした後、スクレーパーを使用して、インストールされている場所の正確なマップを単純に収集できます。Tomcatなどを使用している場合は、ビルド番号とタイムスタンプdescriptionweb.xmlの要素に入れます。覚えておいてください:コンピューターに代わって実行させることができる場合は、何も記憶しないでください。


はい...それも私たちが持っているものです。そして、どの信じられないほど長いビルドがここまたはそこにデプロイされているかを覚えておかなければならないとき、それは使うのが面倒です。数が多すぎるとトラブルも発生します...
バルカン2009年

@Varkhan:なぜ?HTMLスクレイパーがあなたのためにそれを収集できる場所にバージョンを置いてください...
アーロン・ディグラ2009年

1

CruiseControlを介してビルドを実行し(お気に入りのビルドマネージャーをここに挿入)、メインのビルドとテストを実行します。

次に、AntとBuildNumberを使用してバージョン番号を増分し、この情報とビルドの日付およびその他のメタデータを含むプロパティファイルを作成します。

これを読んでGUI /ログなどに提供するためのクラスがあります。

次に、これらすべてをパッケージ化し、ビルド番号と対応するビルドを結び付けてデプロイ可能なビルドを作成します。すべてのサーバーは、起動時にこのメタ情報をダンプします。CruiseControlログをさかのぼって、ビルド番号を日付とチェックインに関連付けることができます。


ヒント:CCとAntのBuildNumberを使用している場合は、PropertyFileLabelIncrementerを使用して、CCラベルをビルド番号と同期させることができます。
Jeffrey Fredrick
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.