133 votes

Construction et numérotation des versions pour les projets Java (ant, cvs, hudson)

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.

63voto

Marty Lamb Points 1330

Pour plusieurs de mes projets, je saisis le numéro de révision de subversion, l'heure, l'utilisateur qui a lancé la construction et certaines informations système, je les place dans un fichier .properties qui est inclus dans le jar de l'application et je lis ce jar au moment de l'exécution.

Le code de la fourmi ressemble à ceci :

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

Il est facile de l'étendre pour inclure toute information que vous souhaitez ajouter.

46voto

user146146 Points 309

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

Votre code java

String ver = MyClass.class.getPackage().getImplementationVersion();

6voto

Raleigh Points 197

Logiciel :

Hudson a trois constructions/travaux : Continuous, Nightly et Release.

Pour une construction en continu/de nuit : Le numéro de build est la révision SVN, trouvée en utilisant svntask.

Pour une construction/un travail de Release : Le numéro de build est le numéro de la Release, lu par Ant, à partir d'un fichier de propriétés. Le fichier de propriétés peut également être distribué avec la release pour afficher le numéro de build au moment de l'exécution.

Le build Ant script met le numéro de build dans le fichier manifest des fichiers jar/war qui sont créés pendant le build. S'applique à tous les builds.

Action post-build pour les builds Release, réalisée facilement à l'aide d'un plug-in Hudson : taguer SVN avec le numéro de build.

Avantages :

  • Pour la version dev d'un jar/war, le développeur peut trouver la révision SVN du jar/war et rechercher le code correspondant dans le SVN.
  • Pour une version, la révision SVN est celle qui correspond à l'étiquette SVN qui contient le numéro de la version.

J'espère que cela vous aidera.

6voto

Marcelo Morales Points 2260
  • Les numéros de build doivent être associés à un serveur d'intégration continue tel que hudson . Utilisez différents travaux pour différentes branches/équipes/distributions.
  • Pour conserver le numéro de version dans le build final, je recommande d'utiliser simplement maven pour le système de construction. Il créera un fichier .properties archivé dans le fichier .jar/.war/.whatever-ar final. META-INF/maven/<project group>/<project id>/pom.properties . Le fichier .properties contiendra la propriété de la version.
  • Puisque je recommande maven, je vous conseille vivement de consulter la section plugin de libération pour préparer la version sur le dépôt de sources et garder les versions synchronisées.

4voto

matt b Points 73770

J'utilise également Hudson, bien que le scénario soit beaucoup plus simple :

Mon script Ant a une cible dedans qui ressemble à :

<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 définit ces variables d'environnement pour moi à chaque fois que mon travail s'exécute.

Dans mon cas, ce projet est une webapp et j'inclus ceci build-number.txt dans le dossier racine de la webapp - je ne me soucie pas vraiment de savoir qui le voit.

Nous ne marquons pas le contrôle de la source lorsque cela est fait parce que nous avons déjà configuré notre travail Hudson pour le marquer avec le numéro et l'horodatage de la construction lorsque celle-ci est réussie.

Ma solution ne couvre que les numéros de build incrémentiels pour le développement, nous ne sommes pas encore assez avancés dans le projet pour couvrir les numéros de version.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X