Каковы текущие лучшие практики для систематической нумерации сборки и управления номерами версий в проектах Java? В частности:
-
Как управлять номерами сборки систематически в распределенной среде разработки
-
Как поддерживать номера версий в источнике/доступны для приложения времени выполнения
-
Как правильно интегрировать исходный репозиторий
-
Как более автоматически управлять номерами версий и тегами репозитория
-
Как интегрироваться с инфраструктурой непрерывной сборки
Существует множество доступных инструментов, а ant (система сборки, которую мы используем) имеет задачу, которая будет поддерживать номер сборки, но неясно, как управлять этим с помощью нескольких одновременных разработчиков, использующих CVS, svn или тому подобное.
[EDIT]
Ниже приведены некоторые полезные и полезные частичные или конкретные ответы, поэтому я подведу некоторые из них. Это звучит для меня, как будто на самом деле не существует сильной "лучшей практики", а скорее совокупности перекрывающихся идей. Ниже вы найдете мои резюме и некоторые результирующие вопросы, которые люди могут попытаться ответить в качестве последующих мер. [Новое в stackoverflow... просьба предоставить комментарии, если я делаю это неправильно.]
-
Если вы используете SVN, для езды требуется версия для определенного заказа. Строка нумерации может использовать это, чтобы создать уникальный номер сборки, который идентифицирует конкретный checkout/revision. [CVS, который мы используем по причинам, связанным с наследством, не обеспечивает такого уровня понимания... ручное вмешательство с тегами помогает вам в этом частично.]
-
Если вы используете maven как свою систему сборки, есть поддержка для выпуска номера версии из SCM, а также модуль выпуска для автоматического выпуска релизов. [Мы не можем использовать maven по разным причинам, но это помогает тем, кто может. [Благодаря marcelo-morales]]
-
Если вы используете ant в качестве вашей системы сборки, следующее описание задачи может помочь создать файл .properties Java. захватывая информацию о сборке, которая затем может быть сложена в вашу сборку несколькими способами. [Мы расширили эту идею, чтобы включить информацию, полученную из хадсона, благодаря marty-lamb].
-
Ant и maven (и hudson и круиз-контроль) обеспечивают легкое средство для получения чисел сборки в файле .properties или в файле .txt/.html. Является ли это "безопасным", чтобы он не был подделан намеренно или случайно? Лучше ли компилировать его в класс "версия" во время сборки?
-
Утверждение: строчная нумерация должна быть определена/введена в систему непрерывной интеграции, например hudson. [Благодаря marcelo-morales] Мы приняли это предложение, но оно вскрыло вопрос о выпуске релиза: как происходит релиз? Есть ли множественные buildnumbers в выпуске? Существует ли значительная взаимосвязь между buildnumbers из разных выпусков?
-
Вопрос: Какова цель построения номера сборки? Используется ли он для QA? Как? Используется ли он прежде всего разработчиками для устранения неоднозначности между несколькими сборками во время разработки или более для QA, чтобы определить, что построил конечный пользователь? Если целью является воспроизводимость, теоретически это то, что должен предоставить номер версии выпуска - почему? (пожалуйста, ответьте на это как часть ваших ответов ниже, это поможет осветить выбранные вами варианты/предложил...)
-
Вопрос: Есть ли место для номеров сборки в ручных сборках? Разве это настолько проблематично, что КАЖДЫЙ должен использовать решение CI?
-
Вопрос: Должны ли быть зарегистрированы номера сборки в SCM? Если цель достоверно и однозначно идентифицирует конкретную сборку, как справиться с множеством непрерывных или ручных систем сборки, которые могут привести к сбою/перезапуску/etc...
-
Вопрос: Должен ли номер сборки быть коротким и сладким (т.е. монотонно увеличивать целое число), чтобы он легко вставлялся в имена файлов для архивирования, легко ссылался на сообщение и т.д.... или должен ли он быть длинный и полный имен пользователей, datestamps, имена машин и т.д.
-
Вопрос. Пожалуйста, предоставьте подробную информацию о том, как присвоение номеров сборки вписывается в ваш более крупный процесс автоматического выпуска. Да, любители maven, мы знаем, что это сделано и сделано, но не все из нас уже выпили kool-aid...
Мне бы очень хотелось наполнить это окончательным ответом, по крайней мере, для конкретного примера нашей установки cvs/ ant/hudson, чтобы кто-то мог построить полную стратегию, основанную на этом вопросе. Я буду отмечать как "Ответ" любого, кто может дать описание супа-орехов для этого конкретного случая (включая схему тегов cvs, соответствующие элементы конфигурации CI и процедуру освобождения, которая сводит номер сборки в выпуск, так что он программно доступный.) Если вы хотите спросить/ответить на другую конкретную конфигурацию (например, svn/maven/круиз-контроль), я свяжусь с вопросом здесь. --JA
[EDIT 23 окт. 09] Я согласился с ответом на верхний голос, потому что считаю это разумным решением, в то время как некоторые из других ответов также включают хорошие идеи. Если кто-то хочет взломать некоторые из них с помощью marty-lamb, я подумаю о принятии другого. Единственная проблема, с которой я сталкиваюсь с marty-lamb, заключается в том, что она не дает надежного сериализованного номера сборки - это зависит от локальных часов в системе-застройщике, чтобы обеспечить однозначные строковые номера, что не очень удобно.
[Редактировать 10 июля]
Теперь мы включим класс, подобный приведенному ниже. Это позволяет компилировать номера версий в окончательный исполняемый файл. Различные формы информации о версии испускаются при регистрации данных, долгосрочных архивных продуктах вывода и используются для отслеживания нашего (иногда многолетнего) анализа выходных продуктов на конкретную сборку.
public final class AppVersion
{
// SVN should fill this out with the latest tag when it checked out.
private static final String APP_SVNURL_RAW =
"$HeadURL: svn+ssh://[email protected]/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();
}
}
Оставьте комментарии, если это заслуживает обсуждения в вики.