Porównaj ceny domen i usług IT, sprzedawców z całego świata

Numeracja kompilacji i wersji dla projektów Java (ANT, CVS, Hudson)


Jakie są aktualne najlepsze praktyki w zakresie systematycznego zarządzania numeracją zestawów i numerami wersji w projektach Java? Konkretnie:
  • Jak systematycznie zarządzać numerami kompilacji w rozproszonym środowisku programistycznym
  • Jak zachować dostępne dla aplikacji numery wersji w kodzie źródłowym/środowisku wykonawczym
  • Jak poprawnie zintegrować się z repozytorium źródłowym
  • Jak bardziej automatycznie zarządzać numerami wersji i tagami repozytorium
  • Jak zintegrować się z infrastrukturą ciągłego budowania

Dostępnych jest sporo narzędzi, a ant (system kompilacji, którego używamy) ma zadanie, które będzie utrzymywać numer kompilacji, ale nie jest jasne, jak zarządzać tym z wieloma współbieżnymi programistami używającymi CVS, svn lub podobnego.
[EDIT]
Poniżej pojawiły się dobre i pomocne częściowe lub szczegółowe odpowiedzi, więc pokrótce przedstawię kilka z nich. Wydaje mi się, że w rzeczywistości nie jest to bardzo mocna „najlepsza praktyka”, ale raczej zestaw nakładających się pomysłów. Poniżej znajdziesz moje podsumowania i niektóre wynikające z nich pytania, na które ludzie mogą spróbować odpowiedzieć w ramach kontynuacji. [Nowość w stackoverflow… Jeśli robię to źle, podaj komentarze.]
  • Jeśli używasz SVN, będziesz potrzebować określonej kontroli wersji do kasy dla tej podróży. Numeracja zespołu może wykorzystać to do stworzenia unikalnego numeru zespołu, który identyfikuje konkretną kasę/rewizję. [CVS, którego używamy ze starszych powodów, nie zapewnia takiego poziomu zrozumienia… ręczne tagowanie pomoże ci to osiągnąć.]
  • Jeśli używasz maven jako systemu kompilacji, dostępna jest obsługa generowania numeru wersji z SCM, a także moduł wydania do automatycznego generowania wydań. [Nie możemy używać mavena z różnych powodów, ale pomaga tym, którzy mogą. [Podziękować Marcelo-Morales https://stackoverflow.com/user ... rales ]]
  • Jeśli używasz ant http://ant.apache.orgjako system kompilacji poniższy opis zadania może pomóc w utworzeniu pliku .properties w języku Java z informacjami o zespole, które można następnie wprowadzić do zespołu na kilka sposobów. [Rozszerzyliśmy ten pomysł o informacje z firmy Hudson, dzięki Marty-Lambou https://stackoverflow.com/users/79194/marty-lamb ].
  • Ant i maven (a także hudson i cruise control) zapewniają prosty sposób pobierania numerów kompilacji do pliku .properties lub .txt/.html. Czy jest to wystarczająco „bezpieczne”, aby zapobiec celowej lub przypadkowej ingerencji Może lepiej skompilować go do klasy "wersjonowania" w czasie kompilacji
  • Zatwierdzenie: numeracja zespołu musi być zdefiniowana/egzekwowana w systemie ciągłej integracji, takim jak hudson http://hudson-ci.org/... [Dzięki Marcelo-Morales https://stackoverflow.com/user ... rales] przyjęliśmy tę propozycję, ale nie obejmuje ona technicznej kwestii wydania: w jaki sposób odbywa się wydanie Czy w tej wersji jest wiele numerów kompilacji Czy istnieje znaczący związek między numerami kompilacji z różnych wersji
  • Pytanie: Jaki jest cel numeru kompilacji Czy jest używany do kontroli jakości Ale jak to zrobić Czy jest używany głównie przez programistów do rozróżniania wielu zestawów podczas programowania, czy też bardziej do kontroli jakości w celu ustalenia, który zestaw otrzymał użytkownik końcowy Jeśli celem jest odtwarzalność, to teoretycznie to właśnie powinien zapewniać numer wersji wydania - dlaczego nie (proszę odpowiedzieć na to jako część swoich odpowiedzi poniżej, pomoże to w oświetleniu wyborów, których dokonałeś/zasugerowałeś ...)
  • P: Czy jest miejsce na numery kompilacji w kompilacjach ręcznych Czy to tak problematyczne, że KAŻDY musi korzystać z rozwiązania CI
  • P: Czy numery kompilacji należy zwrócić do SCM Jeśli celem jest niezawodne i jednoznaczne zidentyfikowanie konkretnej kompilacji, jak radzić sobie z różnymi systemami kompilacji ciągłej lub ręcznej, które mogą ulec awarii/ponownym uruchomieniu/itp.
  • Pytanie: Czy numer kompilacji powinien być krótki i przyjemny (tj. Monotonicznie rosnąca liczba całkowita), aby można go było łatwo wstawić do nazw plików w celu archiwizacji, łatwo przywoływać w komunikacji itp. ... lub czy powinien to być długie i pełne nazwy użytkowników, data znaczki, nazwy maszyn itp.
  • P: Proszę podać szczegółowe informacje o tym, jak przypisanie numeru kompilacji pasuje do większego automatycznego procesu wydawania. Tak, 64 kochanków, wiemy, że to zrobione i zrobione, ale nie wszyscy z nas już wypili Kool-Aid ...

Naprawdę chciałbym przekształcić to w pełną odpowiedź, przynajmniej dla konkretnego przykładu naszej instalacji cvs/ant/hudson, aby ktoś mógł zbudować kompletną strategię w oparciu o to pytanie. Oznaczę jako „odpowiedź” każdego, kto może podać opis zupy do orzechów w tym konkretnym przypadku (w tym schemat znakowania cvs, odpowiednie elementy konfiguracji CI i procedurę wydania, która dodaje numer kompilacji do wydania aby był dostępny programowo.) Jeśli chcesz zapytać/odpowiedzieć na inną konkretną konfigurację (powiedzmy svn/maven/cruise control), odsyłam do tego pytania tutaj. - JA
[EDYCJA 23 października 09]
Przyjąłem odpowiedź, na którą głosowali najlepsi, ponieważ uważam, że jest to sprytne rozwiązanie, podczas gdy niektóre inne odpowiedzi również zawierają dobre pomysły. Jeśli ktoś chce spróbować zsyntetyzować niektóre z nich

Marty-Lamb
https://stackoverflow.com/users/79194/marty-lamb, Pomyślę o zaakceptowaniu innego. Jedyną rzeczą, która przeszkadza mi w przypadku Marty-Lamb, jest to, że nie generuje niezawodnie seryjnego numeru kompilacji - opiera się na lokalnym zegarze w systemie konstruktora, aby zapewnić jednoznaczne numery kompilacji, co nie jest dobre.
[Edytuj 10 lipca]
Teraz dołączamy klasę taką jak ta poniżej. Pozwala to skompilować numery wersji do ostatecznego pliku wykonywalnego. Różne formy informacji o wersji są generowane w danych dziennika, długoterminowych zarchiwizowanych wynikach i są wykorzystywane do śledzenia naszej (czasami po latach) analizy wyników dla określonej kompilacji.
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();
}
}

Zostaw komentarz, jeśli zasługuje na to, aby stać się dyskusją na wiki.
Zaproszony:
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

W przypadku kilku moich projektów zapisuję numer wersji subversion, czas, użytkownika, który rozpoczął kompilację i niektóre informacje o systemie, umieszczam je w pliku .properties, który jest zawarty w aplikacji jar, i czytam jej plik jar w czasie wykonywania.
Kod mrówki wygląda następująco:
<pre class="lang-xml prettyprint-override">
<!-- 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>

Łatwo jest rozszerzyć, aby uwzględnić wszelkie informacje, które chcesz dodać.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Twój

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>...

Twój kod java
String ver = MyClass.class.getPackage().getImplementationVersion();
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Oprogramowanie:

Hudson ma trzy budowania/zadania: ciągłe, nocne i stopniowe.
W przypadku kompilacji ciągłej/nocnej: numer kompilacji to wersja SVN znaleziona w svntask.
W przypadku wydania kompilacji/zadania: numer kompilacji to numer wersji odczytany przez Ant z pliku właściwości. Plik właściwości można również rozpowszechniać wraz z wydaniem, aby wyświetlać numer kompilacji w czasie wykonywania.
Skrypt budujący Ant umieszcza numer kompilacji w pliku manifestu plików jar/war wygenerowanych podczas kompilacji. Dotyczy wszystkich zespołów.
Akcja po kompilacji dla kompilacji wydania, łatwa do wykonania za pomocą wtyczki Hudson: tag SVN z numerem kompilacji.
Korzyści:
  • Dla wersji dev A jar/war, programista może znaleźć wersję SVN z jar/war i zobaczyć odpowiedni kod w SVN
  • W przypadku wydania wersja SVN odpowiada znacznikowi SVN, który wskazuje numer wydania.

Mam nadzieję że to pomoże.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

  • Numery kompilacji muszą być powiązane z serwerem ciągłej integracji, takim jak hudson http://hudson-ci.org/... Używaj różnych stanowisk dla różnych gałęzi/zespołów/dystrybucji.
  • Aby zachować numer wersji w ostatecznej kompilacji, polecam po prostu użyć maven http://maven.apache.orgzbudować system. Spowoduje to utworzenie pliku .properties spakowanego do ostatecznego pliku .jar/.war/. Whatthing-ar w lokalizacji
    META-INF/maven/& < project group & >/& < project id & >/pom. właściwości
    . Plik .properties będzie zawierał właściwość wersji.
  • Ponieważ polecam Mavena, gorąco polecam sprawdzenie wydanie wtyczki http://maven.apache.org/plugin ... .htmlaby przygotować wydanie w repozytorium źródłowym i zachować synchronizację wersji.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Używam też Hudsona, chociaż scenariusz jest dużo prostszy:
Mój skrypt Ant ma cel, który wygląda następująco:
<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 ustawia te zmienne środowiskowe za mnie, gdy moja praca jest wykonywana.
W moim przypadku ten projekt jest aplikacją internetową i umieszczam ten plik
build-number.txt
w folderze głównym aplikacji internetowej - nie obchodzi mnie, kto go zobaczy.
Nie oznaczamy kontroli źródła, gdy jest to zrobione, ponieważ mamy już zadanie Hudsona, aby oznaczyć je numerem kompilacji/znacznikiem czasu, gdy kompilacja się powiedzie.
Moje rozwiązanie obejmuje tylko przyrostowe numery kompilacji na potrzeby programowania, nie jesteśmy jeszcze wystarczająco zaawansowani w projekcie, w którym zajmujemy się numerami wersji.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Możesz również rzucić okiem na wtyczkę BuildNumber Maven i zadanie Ant w jednym słoiku znalezionym w

http://code.google.com/p/codeb ... umber
http://code.google.com/p/codeb ... er... Starałem się, aby wszystko było proste i jasne. Jest to bardzo mały plik jar, który zależy tylko od zainstalowanego Subversion wiersza poleceń.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Oto jak rozwiązałem ten problem:
  • pliki źródłowe są kopiowane do katalogu budowania
  • wtedy stosowane jest anttask "informacje o wersji"
  • kompilowanie zmodyfikowanych źródeł

Oto plik java przechowujący informacje o wersji:
public class Settings { public static final String VERSION = "$VERSION$";
public static final String DATE = "$DATE$";}

A oto anttask „informacje o wersji”:
<!-- ================================= 
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>
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Oto moje 2 centy:
  • Mój skrypt kompilacji generuje numer kompilacji (z sygnaturą czasową!) Za każdym razem, gdy buduję aplikację. Tworzy to zbyt wiele liczb, ale nigdy za mało. Jeśli mam zmianę w kodzie, numer kompilacji zmieni się przynajmniej raz.
  • Wersjonuję numer kompilacji z każdym wydaniem (choć nie pomiędzy). Kiedy aktualizuję projekt i otrzymuję nowy numer kompilacji (ponieważ wydał ją ktoś inny), nadpisuję lokalną wersję i zaczynam od nowa. Może to skutkować niższym numerem kompilacji, więc dołączyłem sygnaturę czasową.
  • Kiedy pojawia się wydanie, numer kompilacji jest zatwierdzany jako ostatni element w pojedynczym zatwierdzeniu z komunikatem „kompilacja 1547”. Następnie, gdy jest to oficjalne wydanie, całe drzewo jest oznaczane. W ten sposób plik kompilacji zawsze zawiera wszystkie tagi i istnieje proste mapowanie 1: 1 między tagami a numerami kompilacji.

[EDYCJA] Wdrażam version.html z moimi projektami, a następnie mogę użyć skrobaka, aby po prostu złożyć dokładną mapę tego, co jest zainstalowane i gdzie. Jeśli używasz Tomcata lub czegoś podobnego, umieść numer kompilacji i sygnaturę czasową w elemencie
opis

web.xml
http://e-docs.bea.com/wls/docs81/webapp/web_xml . html # 1013555 ... Pamiętaj: nigdy nie zapamiętuj niczego, jeśli możesz poprosić komputer, aby zrobił to za Ciebie.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Uruchamiamy naszą kompilację za pomocą CruiseControl (wstaw tutaj swojego ulubionego menedżera kompilacji) i uruchamiamy główne kompilacje i testy.
Następnie zwiększamy numer wersji za pomocą Ant i

BuildNumber
http://ant.apache.org/manual/T ... .html
i utwórz plik właściwości zawierający te informacje, a także datę kompilacji i inne metadane.
Mamy klasę poświęconą czytaniu tego i ujawnianiu go w GUI/logach itp.
Następnie pakujemy to wszystko i tworzymy możliwe do wdrożenia powiązanie numeru kompilacji i odpowiedniej kompilacji. Wszystkie nasze serwery zrzucają te metainformacje podczas uruchamiania. Możemy wrócić do dzienników CruiseControl i powiązać numer kompilacji z datą i potwierdzeniami.

Aby odpowiedzieć na pytania, Zaloguj się lub Zarejestruj się