polylith 2025-11-22

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.

;; 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 configs

We 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.

🙏 1

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).

👍 1

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