Как встроить текущий git sha в URL-маршрут в Clojure

Обычно у меня есть URL-маршрут GET для всех моих серверных приложений, который возвращает текущий хэш git как простой способ проверить точную версию кода, работающего на данном экземпляре. В интерпретируемых языках (например, Python, Node.js) это легко, вы просто проверяете результат выполнения команды оболочки в подпроцессе. Но я распространяю свое приложение Clojure по экземплярам, ​​упаковывая его с помощью lein uberjar.

Таким образом, я могу получить текущий git sha программно, используя clojure.java.shell, например:

(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 (а не во время выполнения, когда банка больше не находится в репо), чтобы он возвращался из маршрута URL, который я определяю с помощью compojure и обслуживаю через http-kit. Как мне запустить эту функцию во время компиляции или во время сборки и сбросить ее в константу или что-то еще, что я могу затем вернуть из маршрута?

Хотя я хотел бы решение в этом направлении, как указано, конечная цель здесь заключается в том, чтобы иметь возможность запрашивать работающий экземпляр через HTTP и находить точную версию работающего кода (настоятельно предпочитаю git sha, а не, например, номер semver) на данный экземпляр в производстве.

Я понимаю, что могу обойти это, клонировав репо во все экземпляры и создав банку локально, например. ansible и найдите sha в известном каталоге, но это кажется, ну, хакерским, а также подверженным ошибкам по сравнению с подписью файла jar, так сказать, во время сборки.

РЕДАКТИРОВАТЬ:

Мой проект.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]}})

person Jared Smith    schedule 29.12.2020    source источник
comment
Макросы запускаются во время компиляции, их целью является создание кода, который фактически компилируется. Пробовали ли вы выполнять git-get-sha в макросе, AOT-компилировать вызов этого макроса (т. е. чтобы окончательно скомпилированный код включал SHA в виде буквальной строки) и включать результирующий файл класса в uberjar ?   -  person Biped Phill    schedule 29.12.2020
comment
@BipedPhill У меня не было, но вы, конечно, правы. Если я отойду от leiningen, который, кажется, делает это автоматически, я, вероятно, так и сделаю.   -  person Jared Smith    schedule 29.12.2020


Ответы (2)


Я не думаю, что делаю что-то особенное, чтобы это произошло, так что загляните в свою банку на наличие

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

Где your-project/name происходит из project.clj, который вы используете для создания своего uberjar

(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, которая возвращает эту информацию, используя эту функцию.

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]))))
person jas    schedule 29.12.2020
comment
Я добавил clojure.java.io, скопировал вашу функцию и заменил your-project именем моего проекта (я также обновил вопрос своим проектом.clj), создал банку и запустил ее с помощью java -jar, но rsrc кажется нулевым: Exception in thread "main" java.lang.IllegalArgumentException: Cannot open <nil> as a Reader.. Интересное в стороне: ваш дескриптор SO также является моими инициалами. - person Jared Smith; 29.12.2020
comment
На самом деле, я думаю, вы привели меня к что мне нужно. сейчас экспериментирую... - person Jared Smith; 29.12.2020
comment
Это сделал это, спасибо. Теперь я чувствую себя тупым из-за того, что не читал FAQ :/ - person Jared Smith; 29.12.2020

У меня была эта проблема в проекте, и они использовали несколько сумасшедших недокументированных хаков, чтобы преобразовать git SHA в глобальную переменную через lein. Не делай этого.

Вместо этого поймите, что ваш процесс сборки состоит из более чем одного шага. В простейшем случае это два шага:

  1. Захватите git SHA и сохраните его в файл (обычно что-то вроде ./resources/build-info.txt (или, что еще лучше, build-info.edn).
  2. Вызовите lein uberjar, чтобы упаковать все в артефакт развертывания.

Итак, вместо того, чтобы просто вызывать lein uberjar из командной строки, создайте двухстрочный сценарий развертывания, содержащий описанные выше шаги. Возможно, что-то простое, например:

#!/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!).

person Alan Thompson    schedule 29.12.2020
comment
Это определенно сработает. Но в часто задаваемых вопросах говорится, что начиная с версии 2.4.1 они автоматически включать эту информацию в файл с именем pom.properties, доступный как из встроенной банки, так и из ответа lein run a la jas. Помимо переносимости (в случае, если я перешел на другой инструмент сборки), есть ли какая-либо причина не использовать его? - person Jared Smith; 29.12.2020
comment
Звучит как приятное дополнительное преимущество lein. Я не уверен, что ветки и т. д. могут усложнить проблему. Определенно используйте простой скрипт для других ситуаций, таких как SCM без git (Mecurial и т. д.) или там, где требуется больше, чем git SHA. Например, вы можете сохранить время сборки, например «2020-12-29T13:51:43Z», версию Clojure и т. д. Все это легко добавить в файл build-info.edn. - person Alan Thompson; 30.12.2020