hey all how do you manage you ci pipelines? i am migrating our project one service at a time (from multiple repos to a poly monorepo) i have started with creating a single component containing all of the repo stuff and a project that contains the ci file (gitlab ci) how do you execute pipelines for the corresponding project upon changes in the component / base? i know poly can track changes and execute tests accordingly, but it does not offer deployment mechanism
At work, we use the Polylith API in our build.clj to get a list of projects that are affected by changes and we only build uberjars for those projects.
There's a projects-to-deploy function in that API: https://cljdoc.org/d/polylith/clj-poly/0.3.31/api/polylith.clj.core.api.interface#projects-to-deploy
;; in our build.clj:
(defn build-uberjars
"Build uberjars for specified, or changed, artifacts."
[params]
(let [projects (or (:projects params)
(changed-projects (get params :since "release")))]
(uberjars (assoc params :projects projects))))I talk about this in https://corfield.org/blog/2022/12/07/deps-edn-monorepo-10/ although the API didn't exist back then so changed-projects was a much more complicated fn in our build.clj
LMK if you have any Qs @itai
Our CI is BitBucket Pipelines, and our YAML file just runs certain fns in our build.clj file -- so our CI is essentially Clojure code in that, setting up the DB, running tests (via Polylith and my external test runner), and building just the uberjars that are needed -- and then posting them to S3 for subsequent deployment.
that's a nice function! i wonder how can i execute some jobs (like deploying to k8s, or building a docker image) based on the result of this api when ill get a better understanding and practice ill probably have more questions thanks!
We still have a bunch of bash/sh scripts from "the old days" that we run as part of dev/test/CI via functions like this:
(defn- run-build-script [script]
(let [{:keys [exit]}
(b/process {:command-args ["sh" (str base "/build/" script)]})]
(when-not (zero? exit)
(throw (ex-info (str script " aborted!") {:exit exit})))))At some point, we may rewrite those in Clojure (or bb)...
where do you place these script files? under the project folder? i understand that "project" is the deployable artifact, so i guess i should place there scripts and config files
specifically in the current project i'm migrating we use datomic ions so i have this script for deployment
(ns ci
(:require [datomic.ion.dev :as ion]))
(defn -main []
(let [{:keys [rev deploy-groups]} (ion/push {})
_ (println "rev" rev)
dep (ion/deploy {:rev rev
:group (first deploy-groups)})]
(loop []
(let [dep-status (ion/deploy-status dep)]
(case (:deploy-status dep-status)
"RUNNING" (do (println "waiting for CodeDeploy...")
(Thread/sleep 3000)
(recur))
"SUCCEEDED" (println dep-status)
(throw (Exception. (str dep-status))))))))
and a bunch of other stuff like datomic configsWe have a single build.clj at the root of the workspace and it manages builds for all 20+ projects.
Our repo has a build/ folder and build-related scripts live there.
(Well, we actually moved build.clj to bases/build but we still run it from the workspace root)
Our build.clj file has 27 public functions (tasks) and about 450 lines of code, FYI.
do you have experience with ions? i'm trying to build and deploy my ions and i get an error for local/root
{:paths ["resources"]
:mvn/repos {"ossrh-snapshots" {:url ""}
"datomic-cloud" {:url ""}}
:deps {poly/build {:local/root "../../components/build"}
poly/ions {:local/root "../../components/ions"}
org.clojure/clojure {:mvn/version "1.12.3"}}
:aliases {:test {:extra-paths []
:extra-deps {}}
:migrate {:exec-fn my-ns.build.core/migrate-datomic-schema
:exec-args {:schema my-ns.ions.datomic.schema/schema}}
:deploy {:exec-fn my-ns.build.core/deploy-ions}}}
error:
Execution error at datomic.ion.dev.bundle/require-uname-for-local-root!$fn (bundle.clj:80).
Dependency poly/ions is a :local/root dependency. You must specify a :uname argument to push. :uname builds are unreproducible!
poly.build
(defn deploy-ions [_]
(let [{:keys [rev deploy-groups]} (ion/push {})
dep (ion/deploy {:rev rev
:group (first deploy-groups)})]
(println "rev" rev)
(loop []
(let [dep-status (ion/deploy-status dep)]
(case (:deploy-status dep-status)
"RUNNING" (do (println "waiting for CodeDeploy...")
(Thread/sleep 3000)
(recur))
"SUCCEEDED" (println dep-status)
(throw (Exception. (str dep-status))))))))i dont want to provide :uname for it tho...
I can only suggest asking in #datomic or #ions-aws about that restriction. I've never used Datomic in any form (aside from working through the local tutorial when it first came out).
Make sure you have a clean git repo, i.e. no uncommitted changes.
Datomic Ions uses the git SHA as the revision/version number, but it requires a clean git repo so that the exact build can be reproduced later.
it also require not using :local/root