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)
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:
- en passant le numéro de construction Jenkins à Leiningen, à incorporer dans
project.clj
defproject
déclaration. - Enjoignant de Leiningen, afin de construire un
MANIFEST.MF
avec une valeur deImplementation-Version
. - Invoquant
Package#getImplementationVersion()
pour obtenir de l' l'accès à unString
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.