Comment obtenir l'accès runtime à la version numéro d'une application Clojure en cours d'exécution?

j'ai un service web écrit en Clojure qui est livraison continue. Pour permettre à nos outils de déploiement automatisés de savoir quelle version de la base de données codées a été déployée, le service web devrait fournir un moyen de demander quelle version il est. La version est déclarée comme faisant partie de la configuration du projet dans le Leiningen outil de construction, comme ceci:

(defproject my-web-service "1.2-SNAPSHOT"
  ; ... rest of project.clj
  )

le codebase est emballé sous forme de fichier JAR.

nous les développeurs ne voulons pas augmenter la numéro de version de chaque propagation. Au lieu de cela, nous voulons qu'il soit incrémenté automatiquement chaque fois qu'une nouvelle construction est déclenchée sur notre intégration continue serveur (dans ce cas Jenkins). Par exemple, lorsqu'un checkin de contrôle de version demande la construction de quarante-deuxième de cette base de données, la version est 1.2.42.

pour tout JAR particulier qui a été construit et déployé, je veux permettre d'interroger le numéro de version d'une manière ou d'une autre (par exemple avec une requête HTTP, mais c'est une implémentation détail.) La réponse doit inclure la chaîne 1.2.42.

Comment puis-je rendre ce numéro de version disponible pour l'application en cours d'exécution?

(double Possible, mais il ne comprend pas le Jenkins aspect: intégrer la chaîne de version du projet leiningen dans l'application)

16
demandé sur Community 2012-09-26 14:40:36

1 réponses

une façon d'accéder à ce numéro de version est le MANIFEST.MF fichier qui est stocké dans le fichier JAR. Cela permettra l'accès à l'exécution, par L'intermédiaire de Java java.lang.Package classe. Cela nécessite les trois étapes suivantes:

  1. en passant le numéro de construction Jenkins à Leiningen, à incorporer dans project.cljdefproject déclaration.
  2. Enjoignant de Leiningen, afin de construire un MANIFEST.MF avec une valeur de Implementation-Version.
  3. Invoquant Package#getImplementationVersion() pour obtenir de l' l'accès à un String contenant le numéro de version.

1-Obtenir le numéro de build Jenkins

Il est possible d'utiliser Jenkins' variables d'environnement pour accéder au numéro de build (joliment nommé BUILD_NUMBER). Ceci est disponible dans le cadre d'un processus JVM, en utilisant System.getenv("BUILD_NUMBER"). Dans ce cas, le processus JVM peut être le processus leiningen project.clj script, qui est le code Clojure qui peut invoquer (System/getenv "BUILD_NUMBER"). Suivant l'exemple ci-dessus, la Chaîne retournée serait "42".

2-Mise en place de la version dans le manifeste.MF

lors de la construction d'un bocal, Leiningen inclura un MANIFEST.MF le fichier par défaut. Il dispose également d'une option de configuration, qui permet de définir arbitrairement les couples clé-valeur dans ce fichier. Ainsi, lorsque nous pouvons accéder au numéro de build de Jenkins dans Clojure, nous pouvons combiner cela avec la déclaration de version statique pour définir le Implementation-Version dans le manifeste. Les parties pertinentes de l' project.clj ressembler à ceci:

(def feature-version "1.2")
(def build-version (or (System/getenv "BUILD_NUMBER") "HANDBUILT"))
(def release-version (str feature-version "." build-version))
(def project-name "my-web-service")

(defproject project-name feature-version
  :uberjar-name ~(str project-name "-" release-version ".jar")
  :manifest {"Implementation-Version" ~release-version}

  ... )

ça vaut le coup notant un couple de détails dans cet exemple. (if-let ...) lors de la définition de build-version est de permettre aux développeurs de construire le JAR localement, sans avoir besoin d'émuler les variables d'environnement de Jenkins. :uberjar-name la configuration permet de créer un fichier JAR nommé en utilisant les conventions Maven/Ivy. Le fichier résultant dans cet exemple serait my-web-service-1.2.42.jar.

avec cette configuration, lorsque Leiningen est invoqué par Jenkins sur le numéro de construction 42, le manifeste dans le bocal résultant sera contient la ligne "mise en œuvre-Version: 1.2.42".

3-accès à la version à l'exécution

maintenant que la chaîne de version que nous voulons utiliser est dans le fichier manifest, nous pouvons y accéder en utilisant les bibliothèques Java standard dans le code Clojure. L'extrait suivant le démontre:

(ns version-namespace
  (:gen-class))

(defn implementation-version []
  (-> (eval 'version-namespace) .getPackage .getImplementationVersion))

Remarque ici, que pour invoquer getImplementationVersion(), il nous faut un Package exemple, et d'obtenir que nous avons besoin d'une instance de java.lang.Class. Donc nous assurer qu'une classe Java est généré à partir de cet espace de noms (l'appel à (:gen-class)) (nous pouvons alors accéder au getPackage méthode de cette classe.

Le résultat de cette fonction est une Chaîne de caractères, par exemple "1.2.42".

mises en garde

il est intéressant de noter qu'il y a quelques gotchas dont vous pourriez avoir à vous soucier, mais qui sont acceptables pour notre cas d'utilisation:

  • paramétrage dynamique de la chaîne de version définie dans le project.clj(defproject ...) l'appel peut faire en sorte que d'autres outils ne fonctionnent pas, s'ils sur la version codée en dur
  • la sémantique de l' getImplementationVersion ont été légèrement abusés. Vraiment, la version doit être: pkg.getSpecificationVersion() + "." + pkg.getImplementationVersion(), mais puisque rien d'autre ne lit l'une ou l'autre de ces valeurs, nous pouvons nous en sortir en définissant simplement la version d'implémentation. Notez que si vous faites cela correctement, vous devrez ajouter "Spécification-Version" au manifeste.

avec les étapes ci-dessus, mon application en cours D'exécution Clojure peut accéder à un numéro de version qui correspond à la construction Jenkins qui a emballé le code.

19
répondu Grundlefleck 2012-10-09 08:21:09