Quelles sont les meilleures pratiques actuelles pour la gestion systématique des numéros de build et de version dans les projets Java ? Plus précisément :
-
Comment gérer systématiquement les numéros de build dans un environnement de développement distribué ?
-
Comment maintenir les numéros de version dans les sources / disponibles pour l'application d'exécution ?
-
Comment intégrer correctement le dépôt de sources
-
Comment gérer plus automatiquement les numéros de version par rapport aux balises de dépôt
-
Comment intégrer l'infrastructure de construction continue
Il y a un certain nombre d'outils disponibles, et ant (le système de construction que nous utilisons) a une tâche qui maintient un numéro de construction, mais il n'est pas clair comment gérer cela avec plusieurs développeurs simultanés utilisant CVS, svn, ou similaire.
[EDIT]
Plusieurs bonnes et utiles réponses partielles ou spécifiques sont apparues ci-dessous, je vais donc en résumer quelques-unes. Il me semble qu'il n'y a pas vraiment de "meilleure pratique" forte sur ce sujet, mais plutôt une collection d'idées qui se chevauchent. Vous trouverez ci-dessous mes résumés et quelques questions auxquelles les gens pourraient essayer de répondre en guise de suivi. (Nouveau sur stackoverflow... merci de faire des commentaires si je m'y prends mal).
-
Si vous utilisez SVN, le versionnement d'une sortie spécifique est inclus dans le processus. La numérotation des builds peut exploiter cela pour créer un numéro de build unique qui identifie le checkout/la révision spécifique. [CVS, que nous utilisons pour des raisons d'héritage, ne fournit pas tout à fait ce niveau de perspicacité... une intervention manuelle avec des balises vous permet d'y arriver en partie].
-
Si vous utilisez maven comme système de construction, il existe un support pour produire un numéro de version à partir du SCM, ainsi qu'un module release pour produire automatiquement des versions. [Nous ne pouvons pas utiliser maven, pour diverses raisons, mais cela aide ceux qui le peuvent. [Merci à marcelo-morales ]]
-
Si vous utilisez fourmi comme système de construction, la description de la tâche suivante peut aider à produire un fichier Java .properties capturant les informations de construction, qui peut ensuite être intégré dans votre construction de plusieurs façons. [Nous avons développé cette idée pour inclure les informations dérivées de Hudson, merci. marty-lambes ].
-
Ant et maven (et hudson et cruise control) fournissent des moyens faciles pour obtenir des numéros de build dans un fichier .properties, ou dans un fichier .txt/.html. Est-ce suffisamment "sûr" pour empêcher toute manipulation intentionnelle ou accidentelle ? Est-il préférable de le compiler dans une classe de "versioning" au moment de la construction ?
-
Affirmation : La numérotation des constructions doit être définie/actée dans un système d'intégration continue tel que hudson . [Merci à marcelo-morales ] Nous avons suivi cette suggestion, mais elle soulève la question de l'ingénierie des versions : Comment une version se produit-elle ? Y a-t-il plusieurs numéros de build dans une version ? Existe-t-il une relation significative entre les numéros de build de différentes versions ?
-
Question : Quel est l'objectif d'un numéro de construction ? Est-il utilisé pour l'assurance qualité ? Comment ? Est-il utilisé principalement par les développeurs pour faire la distinction entre plusieurs builds pendant le développement, ou plus pour l'AQ pour déterminer quel build un utilisateur final a obtenu ? Si le but est la reproductibilité, en théorie c'est ce qu'un numéro de version devrait fournir -- pourquoi ne le fait-il pas ? (veuillez répondre à cette question dans le cadre de vos réponses ci-dessous, cela aidera à éclairer les choix que vous avez faits/suggérés...)
-
Question : Y a-t-il une place pour les numéros de build dans les builds manuels ? Est-ce si problématique que TOUT LE MONDE devrait utiliser une solution CI ?
-
Question : Les numéros de build doivent-ils être enregistrés dans le SCM ? Si l'objectif est d'identifier de manière fiable et sans ambiguïté un build particulier, comment faire face à une variété de systèmes de build continus ou manuels qui peuvent se planter/redémarrer/etc...
-
Question : Un numéro de build doit-il être court et doux (c'est-à-dire un nombre entier croissant de façon monotone) afin d'être facile à coller dans les noms de fichiers pour l'archivage, facile à référencer dans la communication, etc... ou doit-il être long et plein de noms d'utilisateurs, d'horodatages, de noms de machines, etc... ?
-
Question : Veuillez fournir des détails sur la façon dont l'attribution des numéros de build s'intègre dans votre processus de publication automatisé plus large. Oui, les amoureux de maven, nous savons que c'est fait et fait, mais nous n'avons pas tous bu le kool-aid tout à fait encore...
J'aimerais vraiment étoffer cette question en une réponse complète, au moins pour l'exemple concret de notre configuration cvs/ant/hudson, afin que quelqu'un puisse élaborer une stratégie complète basée sur cette question. Je marquerai comme "La réponse" toute personne capable de donner une description complète pour ce cas particulier (y compris le schéma de marquage cvs, les éléments de configuration CI pertinents et la procédure de publication qui intègre le numéro de build dans la publication de manière à ce qu'il soit accessible par programme). Si vous voulez demander/répondre pour une autre configuration particulière (disons, svn/maven/cruise control), je ferai un lien vers la question à partir d'ici. --JA
[EDIT 23 Oct 09] J'ai accepté la réponse la plus votée parce que je pense qu'il s'agit d'une solution raisonnable, tandis que plusieurs des autres réponses comprennent également de bonnes idées. Si quelqu'un veut essayer de synthétiser certaines d'entre elles avec le logiciel marty-lambes je vais envisager d'en accepter un autre. Le seul problème que j'ai avec la méthode de marty-lamb est qu'elle ne produit pas un numéro de construction sérialisé fiable - elle dépend d'une horloge locale du système du constructeur pour fournir des numéros de construction non ambigus, ce qui n'est pas génial.
[Edit Jul 10]
Nous incluons maintenant une classe comme celle ci-dessous. Cela permet de compiler les numéros de version dans l'exécutable final. Différentes formes de l'information de version sont émises dans les données de journalisation, les produits de sortie archivés à long terme, et utilisées pour tracer notre analyse (parfois des années plus tard) des produits de sortie à une construction spécifique.
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();
}
}
Laissez des commentaires si cela mérite de devenir une discussion sur le wiki.