Які сучасні найкращі практики для систематизованої нумерації збірок та управління номерами версій у проектах 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();
}
}
Залиште коментарі, якщо це заслуговує на те, щоб стати вікі-дискусією.
gradle
та / або git
?