Skip to content

Instantly share code, notes, and snippets.

@davidyang
Created December 15, 2023 13:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save davidyang/e13e72005d24886d3d906331d9a2574a to your computer and use it in GitHub Desktop.
Save davidyang/e13e72005d24886d3d906331d9a2574a to your computer and use it in GitHub Desktop.
{:min-bb-version "0.9.0"
:deps {babashka/nrepl-client {:git/url "https://github.com/babashka/nrepl-client"
:git/sha "c83b15906d224b67a67951343b05623c4c00cdcf"}}
:tasks {:requires ([babashka.fs :as fs]
[clojure.string :as str]
[cheshire.core :as json]
[babashka.nrepl-client :as nrepl])
;;:enter (log "[bb tasks] Started:" (:name (current-task)))
;;:leave (log "[bb tasks] Finished:" (:name (current-task)))
:init
(do (fs/create-dirs "./logs/")
(def prod-web-host "supportive-web.husky-clownfish.ts.net")
(def dropbox-dir (fs/expand-home "~/Dropbox/LightweightLabsExec/dev"))
(defn log [& args]
(locking :log-lock
(apply println args)))
(defn pid [] (.pid (java.lang.ProcessHandle/current)))
(defn kill-pidfile [pidfile]
(when (fs/exists? pidfile)
(log "killing" pidfile)
(try
(shell "pkill -SIGINT -F" pidfile)
(finally
(fs/delete pidfile)))))
(defn prod-shell! [& cmds]
(let [r (shell {:in (str/join "\n" (concat ["set -x"
"cd biosync/app"]
cmds))
:out :string}
(format "ssh %s /bin/bash -l" prod-web-host))]
(-> r :out str/trim)))
(defn prod-nrepl-eval! [expr]
(let [s (pr-str expr)]
(log "[prod-nrepl-eval] expr:" s)
(let [result (nrepl/eval-expr
{:host prod-web-host :port 1337 :expr s})]
(log "[prod-nrepl-eval] result:" result))))
(defn git-branch []
(-> (shell {:out :string} "git" "branch" "--show-current")
:out
str/trim))
(defn git-sha [& [name]]
(-> (shell {:out :string} "git" "rev-parse" (or name "HEAD"))
:out str/trim))
(defn git-rev-count []
(->> (shell {:out :string} "git" "rev-list" "HEAD" "--count")
:out str/trim parse-long))
(defn git-uncommitted-diffs? []
(not= 0 (:exit (shell {:continue true} "git" "diff" "--quiet"))))
(defn git-uncommitted-diffs-hash []
(when (git-uncommitted-diffs?)
(-> (shell {:out :string} "git" "diff")
:out str/trim hash abs)))
(defn git-tag! [tag message]
(println "tagging branch as" tag "with message:" message)
(shell "git" "tag" "-a" tag "-m" message)
(shell "git" "push" "origin" tag))
(defn assert-no-uncommitted-git-diffs! []
(when (git-uncommitted-diffs?)
(println "ERROR: All git diffs must be committed.")
(System/exit 1)))
(defn eas-env []
{"SUP_GIT_SHA" (str (git-sha))
"SUP_GIT_REV_COUNT" (str (git-rev-count))
"SUP_GIT_UNCOMMITTED_DIFFS_HASH" (str (git-uncommitted-diffs-hash))
"EXPO_ASC_KEY_ID" "B2AXAXR32S"
"EXPO_ASC_ISSUER_ID" "69a6de73-3bbd-47e3-e053-5b8c7c11a4d1"
"EXPO_APPLE_TEAM_ID" "K7LX94NLZH"
"EXPO_APPLE_TEAM_TYPE" "INDIVIDUAL"
"EXPO_ASC_API_KEY_PATH" "../secrets/AuthKey_B2AXAXR32S.p8"
"SENTRY_AUTH_TOKEN" "442ffd072ea2a1bc4ef05a6e6618e71035888e8dde9cf267fdd2fb6b52b32299"
;; "SENTRY_ORG" "lightweight-labs"
;; "SENTRY_PROJECT" "supportive-mobile"
;;"EAS_LOCAL_BUILD_SKIP_CLEANUP" "1"
})
(defn eas-cli [& args]
(let [[out args] (if (keyword? (first args))
[(first args) (rest args)]
[:inherit args])
env (eas-env)]
(println "eas-env:" env)
(apply shell {:dir "mobile"
:out out
:extra-env env}
"npx" "eas-cli@latest"
args)))
(defn eas-config []
(let [r (-> (eas-cli :string
"config"
"--profile=base"
"--platform=ios"
"--non-interactive"
"--json"))]
(try
(json/decode (:out r) true)
(catch Throwable t
(println "eas-cli error:\n\n" r "\n\n")
(System/exit 1)))))
(defn mobile-eas-build! [profile ext]
(run 'watch-del)
(run '-node-modules-mobile)
(let [tgt-dir (format "./build/ios-%s/" profile)
;; tgt-name must match name key in app.config.js
tgt-name "Supportive"
native-version (-> (eas-config) :appConfig :version)]
(fs/create-dirs (str "./mobile/" tgt-dir))
(eas-cli "build"
"--local"
"--platform=ios"
(format "--profile=%s" profile)
(format "--output=%s/%s.%s" tgt-dir tgt-name ext))
(let [archive-dir (str dropbox-dir
"/ios-builds/"
profile "-" native-version "." (git-rev-count))]
(fs/copy-tree (str "./mobile/" tgt-dir) archive-dir)
(println "Archived" archive-dir))
[tgt-dir tgt-name]))
(defn alter-json-file! [path f]
(as-> path $
(slurp $)
(json/decode $ true)
(f $)
(json/encode $ {:pretty true})
(spit path $))))
scratch (do
(println
(pr-str
{:result
(prod-shell! "git rev-parse HEAD")})))
rev-count (println (git-rev-count))
clean (doseq [dir [".cpcache/"
".shadow-cljs/"
"web/static/gen/"
"mobile/target"
"mobile/dist"
"mobile/build"]]
(fs/delete-tree dir))
-node-modules-mobile (shell {:dir "mobile"} "yarn install")
-node-modules-web (shell {:dir "web"} "yarn install")
-check-secrets (if-not (fs/exists? "secrets/secrets.edn")
(throw (ex-info "You need secrets/secrets.edn - consider running 'bb link-secrets` for dev or putting the file into production" {})))
link-secrets (fs/create-sym-link "./secrets" (str dropbox-dir "/secrets"))
start-ngrok
;; TODO: somehow linked to Aaron's account?
(do (shell "ngrok http --domain=likely-happy-adder.ngrok-free.app 8080"))
discord-share
(do (when-not (fs/exists? "/opt/homebrew/Cellar/pod-babashka-filewatcher/0.0.1/bin/pod-babashka-filewatcher")
(shell "brew install borkdude/brew/pod-babashka-filewatcher"))
(shell "bb scripts/codewatch.clj"))
outdated
(clojure (str/join " " (concat ["-Sdeps '{:deps {com.github.liquidz/antq {:mvn/version \"RELEASE\"}}}' -M -m antq.core"]
*command-line-args*)))
server-deps-tree
(clojure "-Stree -A:server:server-dev:server-test:server-prod")
tailwind-release
{:depends [-node-modules-web]
:task (shell {:dir "web"}
"npx tailwindcss -i ../src/css/main.css -o ./static/gen/css/main.css")}
tailwind-dev
{:depends [-node-modules-web]
:task (shell {:dir "web"
:out "logs/tailwind-dev.log"
:err "logs/tailwind-dev.log"}
"npx tailwindcss -i ../src/css/main.css -o ./static/gen/css/main.css --postcss --watch")}
mobile-client-dev
{:depends [-node-modules-mobile]
:task (clojure {:out "logs/mobile-client-dev.log"
:err "logs/mobile-client-dev.log"}
"-A:mobile:mobile-dev -M -m shadow.cljs.devtools.cli watch mobile")}
mobile-playground
{:depends [clean -node-modules-mobile]
:task
(clojure
"-A:mobile-playground -M -m shadow.cljs.devtools.cli watch mobile-playground")}
watch-del (let [d (-> (fs/cwd) (fs/parent) (fs/real-path))] ;; git dir root
(shell {:out nil} "watchman watch-del" d))
expo-start
{:depends [-node-modules-mobile]
:task (do (run 'watch-del)
(spit ".expo-task.pid" (str (pid)))
(shell {:dir "mobile"} "yarn expo start --clear"))}
server-dev
{:depends [-check-secrets]
:task (clojure {:out "logs/server.stdout.log"
:err "logs/server.stdout.log"}
"-A:server:server-dev:server-test"
"-M"
"-e" "(set! *warn-on-reflection* true)"
"-m" "biosync.server.main")}
tail-logs (shell "sh scripts/tail.sh")
-dev {:depends [discord-share server-dev tailwind-dev mobile-client-dev tail-logs]}
dev {:task (do (run 'clean)
(run '-dev {:parallel true}))}
mobile-release
{:depends [clean -node-modules-mobile]
:task (clojure "-A:mobile:mobile-release -M -m shadow.cljs.devtools.cli release mobile")}
mobile-eas-build-dev-sim
(do (shell "open -a Simulator")
(let [[tgt-dir tgt-name] (mobile-eas-build! "dev-sim" "tgz")]
(shell {:dir (format "./mobile/%s" tgt-dir)}
(format "tar -xzvf %s.tgz" tgt-name))
(shell {:dir "mobile"}
(format "xcrun simctl install booted %s/%s.app" tgt-dir tgt-name))
(shell "xcrun simctl launch booted bio.vitals.biosync")))
mobile-eas-build-dev-device
(let [[tgt-dir tgt-name] (mobile-eas-build! "dev-device" "ipa")]
(shell {:dir "mobile"}
"ideviceinstaller" "-i" (format "%s/%s.ipa" tgt-dir tgt-name)))
mobile-eas-build-prod
(do (assert-no-uncommitted-git-diffs!)
(let [cfg (eas-config)
tag (format "native-build-%s-%s"
(-> cfg :appConfig :version)
(-> cfg :appConfig :ios :buildNumber))]
(println tag)
(mobile-eas-build! "production" "ipa")
(git-tag! tag "mobile-eas-build-prod")))
mobile-eas-submit
(eas-cli "submit"
"--profile=production"
"--platform=ios"
(format "--path=%s" (first *command-line-args*)))
mobile-eas-update
(let [channel (first *command-line-args*)]
(when-not (seq channel)
(println "Must specify channel, e.g. production or staging")
(System/exit 1))
(assert-no-uncommitted-git-diffs!)
(run 'kill-expo)
(run 'kill-shadow)
(run 'clean)
(run 'watch-del)
(run 'mobile-release)
(shell {:dir "mobile"}
"npx" "expo" "export"
"--platform=ios"
"--output-dir=dist"
"--max-workers=64"
"--no-minify"
"--dump-sourcemap")
;; this is a terrible hack where we set up the android metadata
(alter-json-file! "mobile/dist/metadata.json"
(fn [m] (assoc-in m [:fileMetadata :android]
(get-in m [:fileMetadata :ios]))))
(eas-cli "update"
"--platform=ios"
"--non-interactive" ;; don't prompt for message
"--auto" ;; use the last git message as the push message
;;(str "--branch=" channel)
(str "--channel=" channel)
"--skip-bundler")
(git-tag! (str "eas-update-"
(-> (eas-config) :appConfig :version)
"."
(git-rev-count))
"mobile-eas-update")
(shell (str "bb scripts/deploy-notice.clj "
(str "mobile-eas-update:" channel))))
run-prod-server
{:doc "Builds resources and runs prod webserver"
:depends [clean tailwind-release]
:task (clojure {:out "logs/server.stdout.log"
:err "logs/server.stdout.log"}
"-M:server:server-prod")}
-check-prod-server-branch
{:task (let [local-sha (git-sha "HEAD")
remote-sha (prod-shell! "git rev-parse HEAD")]
(log "Local HEAD: " local-sha)
(log "prod-server HEAD:" remote-sha)
(when (not= local-sha remote-sha)
(log (str "local git SHA does not match remote. push? [y/n] "))
(if (= "y" (read-line))
(do (shell (str "git push -f origin "
(git-branch) ":server-production-release"))
(prod-shell! "git pull origin server-production-release"))
(throw (ex-info "User canceled push" {})))))}
deploy-prod-server
{:depends [-check-prod-server-branch]
:task (do (shell (format "rsync -azvh ./secrets/ %s:biosync/app/secrets/"
prod-web-host))
(shell "bb scripts/deploy-notice.clj deploy-prod-server")
(prod-shell! "killall java"
"nohup bb run-prod-server"))}
quick-deploy-prod-server
{:depends [-check-prod-server-branch]
:task (do (shell "bb scripts/deploy-notice.clj quick-deploy-prod-server")
(prod-shell! "bb tailwind-release")
(prod-nrepl-eval! '(user/reset)))}
kill-shadow (kill-pidfile ".shadow-cljs/server.pid")
kill-expo (kill-pidfile ".expo-task.pid")
prod-logs
(shell (format "ssh %s 'tail -F biosync/logs/*'" prod-web-host))
test-server
(apply clojure
"-A:server:server-dev:server-test"
"-M"
"-e" "(biosync.server.init/init!)"
"-m" "kaocha.runner"
*command-line-args*)
scratch-backfill-tags
(let [tags (-> (shell {:out :string} "git" "tag")
:out
(str/split (re-pattern "\n")))]
(doseq [tag tags
:let [v (-> tag
(str/replace-first (re-pattern "^[^\\d]+") "")
(str/replace (re-pattern "-") "."))]
:when (seq v)
:let [tag' (str "eas-update-" v)]]
(shell "git" "tag" "-a" "-f" tag' tag "-m" "mobile-eas-update")
(shell "git" "push" "origin" tag')))
}}
{:paths ["src/common"]
:deps {amalloy/ring-buffer {:mvn/version "1.3.1"}
camel-snake-kebab/camel-snake-kebab {:mvn/version "0.4.3"}
cider/cider-nrepl {:mvn/version "0.44.0"}
com.rpl/specter {:mvn/version "1.1.4"}
com.taoensso/encore {:mvn/version "3.74.0"}
com.taoensso/timbre {:mvn/version "6.3.1"}
com.widdindustries/time-literals {:mvn/version "0.1.10"}
djblue/portal {:mvn/version "0.49.1"}
fipp/fipp {:mvn/version "0.6.26"}
funcool/promesa {:mvn/version "10.0.594"}
garden/garden {:mvn/version "1.3.10"}
integrant/integrant {:mvn/version "0.8.1"}
integrant/repl {:mvn/version "0.3.3"}
lambdaisland/uri {:mvn/version "1.16.134"}
medley/medley {:mvn/version "1.4.0"}
metosin/malli {:mvn/version "0.13.0"}
metosin/potpuri {:mvn/version "0.5.3"}
metosin/reitit {:mvn/version "0.6.0"}
nrepl/nrepl {:mvn/version "1.1.0"}
org.clojars.akiel/async-error {:mvn/version "0.3"}
org.clojure/clojure {:mvn/version "1.11.1"}
org.clojure/core.async {:mvn/version "1.6.681"}
org.clojure/data.avl {:mvn/version "0.1.0"}
refactor-nrepl/refactor-nrepl {:mvn/version "3.9.1"}
swiss-arrows/swiss-arrows {:mvn/version "1.0.0"}
thheller/shadow-cljs {:mvn/version "2.26.2"}
tick/tick {:mvn/version "0.7.5"}
town.lilac/pyramid {:mvn/version "3.4.0"}}
:aliases
{:server
{:extra-paths ["src/server"]
:extra-deps
{aero/aero {:mvn/version "1.1.6"}
amalloy/ring-gzip-middleware {:mvn/version "0.1.4"}
babashka/fs {:mvn/version "0.4.19"}
batik-rasterize/batik-rasterize {:mvn/version "0.1.2"}
cheshire/cheshire {:mvn/version "5.12.0"}
co.deps/ring-etag-middleware {:mvn/version "0.2.1"}
com.cognitect.aws/api {:mvn/version "0.8.686"}
com.cognitect.aws/dynamodb {:mvn/version "848.2.1413.0"}
com.cognitect.aws/endpoints {:mvn/version "1.1.12.504"}
com.cognitect.aws/s3 {:mvn/version "848.2.1413.0"}
com.cognitect.aws/sesv2 {:mvn/version "847.2.1387.0"}
com.cognitect.aws/sns {:mvn/version "847.2.1365.0"}
com.cognitect.aws/sqs {:mvn/version "847.2.1398.0"}
com.cognitect/transit-clj {:mvn/version "1.0.333"}
com.datomic/peer {:mvn/version "1.0.7010"}
com.drewnoakes/metadata-extractor {:mvn/version "2.19.0"}
com.eatthepath/pushy {:mvn/version "0.15.2"}
com.fzakaria/slf4j-timbre {:mvn/version "0.4.1"}
com.googlecode.libphonenumber/libphonenumber {:mvn/version "8.13.26"}
com.helger/ph-css {:mvn/version "7.0.1"}
com.taoensso/nippy {:mvn/version "3.3.0"}
com.wsscode/pathom-viz-connector {:mvn/version "2022.02.14"}
com.wsscode/pathom3 {:mvn/version "2023.08.22-alpha"}
commons-codec/commons-codec {:mvn/version "1.16.0"}
commons-validator/commons-validator {:mvn/version "1.7"}
duratom/duratom {:mvn/version "0.5.8"}
hato/hato {:mvn/version "0.9.0"}
hiccup/hiccup {:mvn/version "2.0.0-RC2"}
io.aviso/pretty {:mvn/version "1.4.4"}
io.netty/netty-all {:mvn/version "4.1.100.Final"}
io.sentry/sentry {:mvn/version "6.34.0"}
jarohen/chime {:mvn/version "0.3.3"}
javax.servlet/javax.servlet-api {:mvn/version "4.0.1"}
org.apache.commons/commons-lang3 {:mvn/version "3.14.0"}
org.apache.commons/commons-math3 {:mvn/version "3.6.1"}
org.asciidoctor/asciidoctorj {:mvn/version "2.5.10"}
org.clojure/core.cache {:mvn/version "1.0.225"}
org.clojure/core.memoize {:mvn/version "1.0.257"}
org.clojure/data.csv {:mvn/version "1.0.1"}
org.clojure/tools.logging {:mvn/version "1.2.4"}
org.clojure/tools.namespace {:mvn/version "1.4.4"}
org.clojure/tools.reader {:mvn/version "1.3.7"}
org.graalvm.js/js {:mvn/version "23.0.2"}
org.graalvm.js/js-scriptengine {:mvn/version "23.1.1"}
org.ocpsoft.prettytime/prettytime {:mvn/version "5.0.7.Final"}
org.slf4j/jcl-over-slf4j {:mvn/version "2.0.9"}
org.slf4j/jul-to-slf4j {:mvn/version "2.0.9"}
org.slf4j/log4j-over-slf4j {:mvn/version "2.0.9"}
org.slf4j/slf4j-api {:mvn/version "2.0.9"}
ring/ring-core {:mvn/version "1.10.0"}
ring/ring-devel {:mvn/version "1.10.0"}
ring/ring-headers {:mvn/version "0.3.0"}
ring/ring-jetty-adapter {:mvn/version "1.10.0"}
ring/ring-ssl {:mvn/version "0.3.0"}
software.amazon.awssdk/s3 {:mvn/version "2.21.30"}
squint/squint {:git/url "https://github.com/squint-cljs/squint" :git/sha "53cc76c" :git/tag "v0.3.38"}
uap-clj/uap-clj {:mvn/version "1.7.0"}}
:override-deps
{org.apache.xmlgraphics/batik-anim {:mvn/version "1.17"}
org.apache.xmlgraphics/batik-codec {:mvn/version "1.17"}
org.apache.xmlgraphics/batik-transcoder {:mvn/version "1.17" :exclusions [xerces/xercesImpl]}
org.apache.xmlgraphics/xmlgraphics-commons {:mvn/version "2.9"}
xerces/xerces {:mvn/version "2.4.0"}
org.apache.activemq/artemis-core-client {:mvn/version "2.30.0"}}
:jvm-opts ["-Djava.awt.headless=true"]}
:server-dev
{:extra-paths ["src/server-dev"]
:extra-deps {com.clojure-goes-fast/clj-memory-meter {:mvn/version "0.3.0"}
spyscope/spyscope {:git/url "https://github.com/den1k/spyscope" :git/sha "83f9a19939378f83e6fbc108b02288c4eb7d5552"}}
:jvm-opts ["-Dbiosync.configProfile=dev"
"-Djdk.attach.allowAttachSelf"
"-XX:-OmitStackTraceInFastThrow"]}
:flowstorm
{:extra-deps {com.github.jpmonettas/flow-storm-dbg {:mvn/version "RELEASE"}
com.github.jpmonettas/flow-storm-inst {:mvn/version "RELEASE"}}}
:server-test
{:extra-paths ["src/server-test" "src/common-test"]
:extra-deps {lambdaisland/kaocha {:mvn/version "1.87.1366"}
etaoin/etaoin {:mvn/version "1.0.40"}
nubank/matcher-combinators {:mvn/version "3.8.8"}
nubank/mockfn {:mvn/version "0.7.0"}
org.clojars.favila/datomock {:mvn/version "0.2.2-favila1"}}}
:server-prod
{:jvm-opts ["-Dbiosync.configProfile=prod"]
:main-opts ["-m" "biosync.server.main"]}
:mobile
{:extra-paths ["src/mobile"]
:extra-deps {applied-science/js-interop {:mvn/version "0.4.2"}
lilactown/helix {:git/url "https://github.com/lilactown/helix" :git/sha "9b2755515b4665732808684606a0b0b8281ad4e0"}
com.cognitect/transit-cljs {:mvn/version "0.8.280"}}}
:mobile-dev
{:extra-paths ["src/mobile-dev" "src/mobile-test" "src/common-test"]}
:mobile-playground
{:extra-deps {applied-science/js-interop {:mvn/version "0.4.2"}
lilactown/helix {:git/url "https://github.com/lilactown/helix" :git/sha "9b2755515b4665732808684606a0b0b8281ad4e0"}}
:extra-paths ["src/mobile-playground"]}
:mobile-release
{:extra-paths ["src/mobile-release"]}}}
{:nrepl {:middleware [refactor-nrepl.middleware/wrap-refactor]}
:npm-deps {:install false} ;; TODO: ask thheller to allow this to be set differently per build or target
;; uncomment this to install new deps where they need to go
;;:npm-deps {:install-dir "mobile"}
;;:npm-deps {:install-dir "web"}
:target-defaults
{:browser {:js-options {:js-package-dirs ["web/node_modules"]}}
:react-native {:js-options {:js-package-dirs ["mobile/node_modules"]}}}
:builds {:mobile
{:target :react-native
:deps {:aliases [:mobile]}
:output-dir "mobile/target",
:build-hooks [(biosync.mobile.config/capture-build-state-hook)]
:dev {:compiler-options {:output-feature-set :es5
:warnings {:fn-deprecated false}}
:init-fn dev/init!
:devtools {:repl-pprint true
:reload-strategy :full
:preloads [helix.experimental.refresh]}}
:release {:init-fn biosync.mobile.main/init
:compiler-options {:output-feature-set :es5
:optimizations :advanced
:source-map true
:pseudo-names true
;; for debugging
;;:pretty-print true
}}}
:mobile-playground
{:target :react-native
:deps {:aliases [:mobile-playground]}
:output-dir "mobile/target",
:dev {:compiler-options {:output-feature-set :es5
;;:source-map-include-sources-content true
;;:source-map-detail-level :all
}
:init-fn biosync.mobile.main/init
:devtools {:repl-pprint true
:reload-strategy :full}}}}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment