Нумерація збірок та версій для Java-проектів (мураха, резюме, Хадсон)


134

Які сучасні найкращі практики для систематизованої нумерації збірок та управління номерами версій у проектах Java? Конкретно:

  • Як систематично керувати числами побудови в розподіленому середовищі розробки

  • Як підтримувати номери версій у джерелі / доступному для програми виконання

  • Як правильно інтегруватися з джерелом сховища

  • Як автоматично керувати номерами версій проти тегів репозиторію

  • Як інтегруватися з інфраструктурою безперервного побудови

Існує досить багато інструментів, і ant (система збирання, яку ми використовуємо) має завдання, яке підтримуватиме кількість збірки, але незрозуміло, як керувати цим кількома одночасно розробниками, що використовують CVS, svn чи подібні .

[EDIT]

Нижче наведено кілька хороших та корисних часткових чи конкретних відповідей, тому я підсумую декілька з них. Мені здається, що насправді щодо цього не існує сильної «найкращої практики», скоріше, це набір ідей, що перетинаються. Нижче знайдіть мої резюме та деякі виникаючі запитання, на які люди можуть спробувати відповісти як подальші дії. [Новий у stackoverflow ... будь ласка, надайте коментарі, якщо я роблю це неправильно.]

  • Якщо ви використовуєте SVN, для поїздки приходить версія конкретного замовлення. Нумерація збірок може використовувати це для створення унікального номера збірки, який ідентифікує конкретну замовлення / перегляд. [CVS, який ми використовуємо із застарілих причин, не забезпечує такого рівня розуміння ... вручну втручання з тегами перетворює вас на частку.]

  • Якщо ви використовуєте maven в якості системи збирання, існує підтримка створення номера версії з SCM, а також модуль випуску для автоматичного створення релізів. [Ми не можемо використовувати maven з різних причин, але це допомагає тим, хто може. [Завдяки марцело-моралі ]]

  • Якщо ви використовуєте мурашник як свою систему збирання, наступний опис завдання може допомогти створити файл Java .properties із захопленням інформації про збірку, який потім можна скласти у вашу збірку кількома способами. [Ми розширили цю ідею, щоб включити інформацію, отриману від Гудзона , завдяки марті-ягня ].

  • Мураха і Мейвен (і Хадсон і круїз-контроль) забезпечують прості засоби для отримання номерів збірки у файл .properties або у файл .txt / .html. Чи достатньо цього "безпечного", щоб уникнути його навмисного чи випадкового підробки? Чи краще скомпілювати його в клас "версії" під час збирання?

  • Затвердження: Нумерація збірок повинна бути визначена / прийнята в системі безперервної інтеграції, як Гудсон . [Завдяки marcelo-morales ] Ми прийняли цю пропозицію, але вона розкриває питання інженерії релізів: Як відбувається випуск? Чи є у випуску декілька чисел? Чи існує змістовна залежність між збірними номерами від різних випусків?

  • Питання: Яка мета стоїть за номером збірки? Він використовується для забезпечення якості? Як? Чи використовується вона в першу чергу розробниками для розмежування між декількома складаннями під час розробки, або більше для QA, щоб визначити, яку збірку отримав кінцевий користувач? Якщо мета - відтворюваність, теоретично це має забезпечувати номер версії випуску - чому це не робиться? (будь ласка, відповідайте на це як частину ваших відповідей нижче. Це допоможе висвітлити вибір, який ви зробили / запропонували ...)

  • Питання: Чи є місце для побудови номерів у ручних побудовах? Це настільки проблематично, що КОЖЕН повинен використовувати рішення CI?

  • Питання: Чи повинні бути зареєстровані номери побудови в СКМ? Якщо мета надійно і однозначно визначить конкретну збірку, як впоратися з різноманітними системами безперервного або ручного збирання, які можуть вийти з ладу / перезапустити / тощо ...

  • Запитання: Чи повинно число збірки бути коротким і солодким (тобто монотонно зростаючим цілим числом), щоб було легко дотримуватися імен файлів для архіву, легко посилатись у спілкуванні тощо ... чи воно повинно бути довгим і повним імен користувачів, позначки дат, назви машин тощо?

  • Питання: Будь ласка, надайте детальну інформацію про те, як присвоєння номерів збірки вписується у ваш більший процес автоматизованого випуску. Так, любителі Maven, ми знаємо, що це робиться і робиться, але ще не всі з нас випили kool-help ще ...

Я дуже хотів би деталізувати це на повну відповідь, принаймні, на конкретний приклад нашого налаштування cvs / ant / hudson, щоб хтось міг побудувати повну стратегію на основі цього питання. Я позначу як "Відповідь" кожного, хто може дати опис супу до горіхів для даного конкретного випадку (включаючи схему тегів cvs, відповідні елементи конфігурації CI та процедуру випуску, яка містить номер збірки у випуску таким чином, що це програмно доступно.) Якщо ви хочете запитати / відповісти на іншу конкретну конфігурацію (скажімо, svn / maven / круїз-контроль), я посилаюся на питання звідси. --JA

[РЕДАКЦІЯ 23 жовтня 09] Я прийняв відповідальну відповідь, оскільки вважаю, що це розумне рішення, тоді як деякі інші відповіді також містять хороші ідеї. Якщо хтось хоче взяти тріщину, синтезуючи деякі з них з мученицею , я розглядаю питання про прийняття іншого. Єдине занепокоєння, яке я маю з мартин-ягнятом, полягає в тому, що він не створює надійно серіалізованого номера збірки - це залежить від місцевого годинника в системі будівельника, щоб забезпечити однозначні номери збірок, що не дуже.

[Редагувати 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();
  }
}

Залиште коментарі, якщо це заслуговує на те, щоб стати вікі-дискусією.


2
Для майбутніх читачів врахуйте, що номер редакції у запропонованому вами коді має файл, а не глобальну редакцію сховища. Для отримання додаткової інформації дивіться: subversion.apache.org/faq.html#version-value-in-source
maayank

2
Мені цікаво, чи хтось має подібні прості підходи при використанні gradleта / або git?
bnjmn

Відповіді:


63

Для кількох моїх проектів я фіксую номер ревізії підриву, час, користувача, який запустив збірку, та деяку системну інформацію, вкладає їх у файл .properties, який потрапляє в банку додатків, і читаю цю банку під час виконання.

Код мурашки виглядає приблизно так:

<!-- 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 за рішення, залежне від платформи. хороший спосіб включити всі файли мурашок, доступних у файл, є: `<name name =" antprops.file "location =" $ {build.temp.project.dir} /used_ant.properties "/> <echoproperties destfile =" $ {antprops.file} "/> <! - сортуйте файл, ТІЛЬКИ для ant 1.7.0 та новіших !!! -> <concat> <union> <sort> <tokens> <file file =" $ {antprops .file} "/> <linetokenizer includeelims =" true "/> </tokens> </sort> </union> </concat>`
raudi

Ви чините знову після цього? Або це робиться перед тим, як здійснити фактичну ревізію?
Чарльз Вуд

6
Як це зробити для сховища git?
TechCrunch

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 вже підтримує таким методом.
Ед Браннін

2
-1 за те, що номер зборки є у build.xml, а не в окремому файлі властивостей
raudi

6
  • Номери побудови повинні бути пов’язані з сервером безперервної інтеграції, таким як Хадсон . Використовуйте різні завдання для різних галузей / команд / дистрибуцій.
  • Щоб зберегти номер версії в остаточній збірці, я рекомендую просто використовувати maven для системи збирання. Це створить файл .properties, заархівований до остаточного .jar / .war / .wever-ar META-INF/maven/<project group>/<project id>/pom.properties. Файл .properties міститиме властивість версії.
  • Оскільки я рекомендую maven, я закликаю вас перевірити плагін випуску, щоб підготувати реліз у вихідному сховищі та тримати версії синхронізованими.

6

Програмне забезпечення:

  • SVN
  • Мураха
  • Хадсон, для постійної інтеграції
  • svntask, завдання мурашки знайти редакцію SVN: http://code.google.com/p/svntask/

Хадсон має три складові / робочі місця: Постійне, Нічне та Випускне.

Для безперервного / нічного побудови: номер збірки - це редакція SVN, знайдена за допомогою svntask.

Для складання / завдання випуску: Номер збірки - це номер випуску, прочитаний Ant, з файлу властивостей. Файл властивостей також може бути розповсюджений з випуском для відображення номера збірки під час виконання.

Сценарій збірки Ant ставить номер збірки у файл маніфесту jar / war файлів, які створюються під час збирання. Застосовується для всіх версій.

Дія після збирання для версій версій, виконана легко за допомогою плагіна Hudson: тег SVN з номером збірки.

Переваги:

  • Для розробленої версії jar / war, розробник може знайти версію SVN з jar / war і шукати відповідний код у SVN
  • Для випуску редакція SVN - це те, що відповідає тегу SVN, у якому номер випуску.

Сподіваюся, це допомагає.


Чи є у вас файл Release build / job перевірити файл властивостей build / release number у SVN?
мат b

Для безперервних збірок номер збірки - це номер редакції SVN. Отже, нічого не потрібно перевіряти. Для випуску версій це зареєстрований файл, який використовується для отримання номера збірки. Як правило, інженер випуску чи хтось інший захотів би оновити цей файл задовго до випуску.
Релі

4

Я також використовую Хадсона, хоча набагато простіший сценарій:

У мого сценарію 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>

Хадсон встановлює ці змінні середовища для мене, коли моя робота працює.

У моєму випадку цей проект є веб-сайтом, і я включаю це build-number.txt файл у кореневу папку webapp - мені не дуже важливо, хто його бачить.

Ми не тегуємо керування джерелом, коли це робиться, тому що у нас вже створена робота Хадсона, щоб позначити його номером / часовою позначкою збірки, коли збірка успішна.

Моє рішення охоплює лише додаткові номери складання для розробки, ми ще не зайшли досить далеко в проект, де ми висвітлюємо номери релізів.


додатково (принаймні, у поточних версіях jenkins) ви можете перевірити властивості: `env.SVN_URL_1 env.SVN_REVISION_1 env.SVN_URL_2 env.SVN_REVISION_2 тощо
raudi

3

Ви також можете ознайомитись із плагіном і завданням Ant за допомогою модуля BuildNumber Maven в одній банці, знайденій за адресою http://code.google.com/p/codebistro/wiki/BuildNumber . Я намагався зробити це просто і прямо. Це дуже невеликий файл jar, який залежить лише від встановленого Subversion командного рядка.


3

Ось як я вирішив це:

  • джерела копіюються в каталог збірки
  • то застосовується антитаск "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 копійки:

  • Мій сценарій збирання створює номер збірки (із позначкою часу!) Щоразу, коли я створюю додаток. Це створює занадто багато цифр, але ніколи занадто мало. Якщо у мене зміниться код, номер збірки зміниться хоча б раз.

  • Я версію номера збірки з кожним випуском (хоча і не між ними). Коли я оновлюю проект і отримую новий номер збірки (тому що хтось інший зробив реліз), я перезаписую свою локальну версію і починаю заново. Це може призвести до меншої кількості збірки, тому я включив позначку часу.

  • Коли випуск трапляється, номер збірки виконується як останній елемент в одному коміті з повідомленням "build 1547". Після цього, коли це офіційний реліз, все дерево позначається тегами. Таким чином, у файлі збірки завжди є всі теги, і існує просте зіставлення 1: 1 між тегами та номерами збірки.

[EDIT] Я розгортаю version.html зі своїми проектами, і тоді я можу за допомогою скребка просто зібрати точну карту, що встановлено куди. Якщо ви використовуєте Tomcat або подібне, введіть номер збірки та часову позначку в descriptionелемент web.xml . Пам'ятайте: Ніколи нічого не запам'ятовуйте, коли у вас є комп'ютер, зробіть це за вас.


Так ... це теж у нас. І це біль, коли потрібно пам'ятати, яка неймовірно довга конструкція була розгорнута тут чи там. Тож занадто багато номерів теж неприємності ...
Вархан

@Varkhan: Чому? Просто поставте версію кудись, де HTML-скребок може зібрати її для вас ...
Аарон Дігулла,

1

Ми запускаємо свою збірку через CruiseControl (вставте сюди свій улюблений менеджер збірки) та виконуємо основні збірки та тести.

Потім ми збільшуємо номер версії за допомогою Ant та BuildNumber та створюємо файл властивостей з цією інформацією, а також дату збирання та інші метадані.

У нас є клас, присвячений читанню цього та наданню його в GUI / журнали тощо.

Потім ми пакуємо все це вгору і створюємо розгортається, зв’язуючи разом номер збірки та відповідну збірку. Усі наші сервери скидають цю мета-інформацію при запуску. Ми можемо повернутися через журнали CruiseControl і прив’язати номер збірки до дати та чеків.


Порада: Якщо ви використовуєте CC та Ant's BuildNumber, ви можете використовувати PropertyFileLabelIncrementer, щоб синхронізувати мітки CC з номером збірки.
Джефрі Фредрік
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.