如何获得运行中Clojure应用程序版本号的运行时访问权限?
我有一个用Clojure编写的web服务。为了让我们的自动化部署工具知道部署了哪个版本的代码库,web服务应该提供一种查询它是哪个版本的方法。版本在生成工具中声明为项目设置的一部分,如下所示:如何获得运行中Clojure应用程序版本号的运行时访问权限?,clojure,continuous-integration,jenkins,leiningen,continuous-deployment,Clojure,Continuous Integration,Jenkins,Leiningen,Continuous Deployment,我有一个用Clojure编写的web服务。为了让我们的自动化部署工具知道部署了哪个版本的代码库,web服务应该提供一种查询它是哪个版本的方法。版本在生成工具中声明为项目设置的一部分,如下所示: (defproject my-web-service "1.2-SNAPSHOT" ; ... rest of project.clj ) (def feature-version "1.2") (def build-version (or (System/getenv "BUILD_NUMBE
(defproject my-web-service "1.2-SNAPSHOT"
; ... rest of project.clj
)
(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}
... )
代码库打包为JAR文件
我们开发人员不希望在每次提交时增加版本号。相反,我们希望每当在我们的服务器上触发一个新的构建时(在本例中是Jenkins),它就会自动递增。例如,当版本控制签入提示该代码库的第四十二次构建时,版本为1.2.42
对于已经构建和部署的任何特定JAR,我希望以某种方式允许查询版本号(例如,使用HTTP请求,但这是一个实现细节)。响应应包括字符串1.2.42
如何使该版本号可用于正在运行的应用程序
(可能重复,但不包括Jenkins方面:)访问此版本号的一种方法是通过存储在JAR文件中的
MANIFEST.MF
文件。这将允许在运行时通过Java类进行访问。这需要以下三个步骤:
project.clj
的defproject
声明中MANIFEST.MF
,其值为实现版本
包#getImplementationVersion()
以访问包含版本号的字符串
内部版本号
)。这在JVM进程中可用,使用System.getenv(“BUILD\u NUMBER”)
。在这种情况下,JVM进程可以是leiningenproject.clj
脚本,它是可以调用(System/getenv“BUILD\u NUMBER”)
的Clojure代码。按照上面的示例,返回的字符串将是“42”
2-在MANIFEST.MF中设置版本
在构建JAR时,默认情况下,Leiningen将包含一个MANIFEST.MF
文件。它还有一个配置选项,允许在该文件中设置任意键值对。因此,当我们可以访问Clojure中的Jenkins内部版本号时,我们可以将其与静态版本声明结合起来,在清单中设置实现版本。project.clj
的相关部分如下所示:
(defproject my-web-service "1.2-SNAPSHOT"
; ... rest of project.clj
)
(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}
... )
值得注意的是,本例中有几个细节。定义构建版本时的(if let…
)允许开发人员在本地构建JAR,而无需模拟Jenkins的环境变量。:uberjar name
配置允许创建使用Maven/Ivy约定命名的JAR文件。本例中的结果文件是my-web-service-1.2.42.jar
在这种配置下,当Jenkins在构建编号42上调用Leiningen时,结果JAR中的清单将包含行“实现版本:1.2.42”
3-在运行时访问版本
现在我们要使用的版本字符串已经在清单文件中,我们可以使用Clojure代码中的Java标准库来访问它。以下代码段演示了这一点:
(ns version-namespace
(:gen-class))
(defn implementation-version []
(-> (eval 'version-namespace) .getPackage .getImplementationVersion))
这里需要注意的是,为了调用getImplementationVersion()
,我们需要一个包
实例,为了得到它,我们需要一个java.lang.Class
实例。因此,我们确保从该名称空间生成Java类(调用(:gen class)
)(然后我们可以从该类访问getPackage
方法
此函数的结果是一个字符串,例如“1.2.42”
警告
值得注意的是,您可能需要担心一些问题,但这些问题对于我们的用例来说是可以接受的:
- 动态设置
project.clj
的(defproject…
调用中定义的版本字符串可能会导致其他一些工具无法工作,如果它们依赖于硬编码的版本
getImplementationVersion
的语义有点被滥用。实际上版本应该是:pkg.getSpecificationVersion()+“+pkg.getImplementationVersion()
,但由于没有其他内容可以读取这两个值中的任何一个,因此只需设置实现版本即可。请注意,正确执行此操作还需要在清单中添加“规范版本”
通过以上步骤,我正在运行的Clojure应用程序可以访问与打包代码的Jenkins版本相对应的版本号。Nice writeup。注意两点:您应该使用或而不是if-let-in-project.clj。此外,我非常确定您可以直接读取清单,而不是在类上调用.getPackage。但是如果您不能,您仍然可以不使用eval获得类。如果您想在没有AOT的情况下优雅地失败,您可以尝试解析。感谢您的响应。更新为使用或而不是If let
。如果读取清单的最简单方法是:我想我更喜欢使用标准JDK方法获得此特定属性。非常感谢!