如何在 Clojure 的 URL 路由中嵌入当前的 git sha

How to embed the current git sha in a URL route in Clojure

通常,我有一个 URL GET 路由用于我所有的服务器端应用程序,return 使用当前的 git 哈希作为检查确切版本的简单方法给定实例上的代码 运行ning。在解释性语言中(例如 Python、Node.js)这很容易,您只需在子进程中检查 运行 宁 shell 命令的输出。但是我通过使用 lein uberjar.

打包我的 Clojure 应用程序来将其分发到实例

所以我可以像这样使用 clojure.java.shell 以编程方式获取当前的 git sha:

(defn get-git-sha
  [_req]
  (trim ((sh "/bin/sh" "-c" "git rev-parse HEAD") :out)))

(defroutes server-routes
  (GET "/revision" [] get-git-sha))

(defn serve-http
  [port]
  (http-server/run-server server-routes {:port port}))

但我需要一种方法在 uberjar 过程中(而不是在 运行jar 不再在回购中时)将其嵌入代码中,以便从 returned URL 我使用 compojure 定义的路由并通过 http-kit 提供服务。我如何 运行 在编译时或构建时运行该函数并将其转储到常量或其他我可以从路由中 return 的东西?

虽然我想要一个符合这些思路的解决方案,但如前所述,这里的最终目标是能够通过 HTTP 查询 运行ning 实例并找到代码的确切版本 运行ning(强烈喜欢 git sha 而不是例如 semver 号)在生产中的给定实例上。

我意识到我可以通过将存储库克隆到所有实例并通过例如在本地构建 jar 来解决这个问题。 ansible 并在已知目录中查找 sha,但这看起来,嗯,hacky,以及容易出错 vs “签署”jar 文件可以说是在构建时。

编辑:

我的 project.clj 看起来像这样:

(defproject gps-server "0.1.0-SNAPSHOT"
  :description "Receives GPS data over TCP"
  :url "http://someurl"
  :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
            :url "https://www.eclipse.org/legal/epl-2.0/"}
  :dependencies [...]
  :main ^:skip-aot gps-server.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot [gps-server.core]}})

我认为我没有做任何特别的事情来实现这一点,所以检查一下你的罐子里有没有

 META-INF/maven/your-project/name/pom.properties

其中 your-project/name 来自您用来构建 uberjar

的 project.clj
(defproject your-project/name "4.2.6"
  ...

在 pom.properties 我有:

#Leiningen
#Tue Oct 01 13:20:45 CEST 2019
version=4.2.6
revision=4625a070a34ddc3c563b71025fa5dd907b406331
groupId=your-project
artifactId=name

修订来自 git。

我有一个/version端点returns这个信息,利用这个功能

defn- get-version []
  (let [rsrc (io/resource "META-INF/maven/your-project/name/pom.properties")
        rdr (io/reader rsrc)
        props (java.util.Properties.)]
    (.load props rdr)
    (into {} (for [[k v] props] [k v]))))

我在一个项目中遇到了这个问题,他们使用一些疯狂的未记录的黑客通过 lein 将 git SHA 放入全局变量中。不要那样做。

相反,要意识到您的构建过程不止一个步骤。在最简单的情况下,这两个步骤是:

  1. 捕获 git SHA 并将其保存到文件中(通常类似于 ./resources/build-info.txt(或者更好的是 build-info.edn)。
  2. 调用 lein uberjar 将所有内容打包到部署工件中。

因此,不要只从命令行调用 lein uberjar,而是制作一个包含上述步骤的 2 行部署脚本。也许像这样简单:

#!/bin/bash

# Capture current git SHA (or:  git log -n1 --format=format:"%H")
git rev-parse HEAD  > ./resources/build-info.txt   

# Create uberjar
lein clean ; lein uberjar

# Copy output someplace, etc...

以上内容可以简单地保存到 ./scripts/deploy.bash 或类似的文件中(当然,它会被签入 git!)。