|
1 | 1 | (ns git.pull.main
|
2 |
| - "WIP - rebase-pull all tracked repos. dirty repos are skipped" |
| 2 | + "rebase-pull main branches of all tracked repos. |
| 3 | +
|
| 4 | + Repos are pulled if |
| 5 | + - repo has a supported remote |
| 6 | + - work tree is clean |
| 7 | + - checked out branch is master/main |
| 8 | +
|
| 9 | + idea: split into 3 parts: |
| 10 | + - collect all repo metadata (branch, remote, clean, etc) |
| 11 | + - validate repos by inspecting metadata |
| 12 | + - pull repos in parallel" |
3 | 13 | (:require [babashka.fs :as fs]
|
4 | 14 | [babashka.process :refer [sh]]
|
5 | 15 | [clojure.string :as str]
|
6 | 16 | [doric.core :as doric])
|
7 | 17 | (:import [java.util.concurrent Executors ExecutorService Future]))
|
8 | 18 |
|
| 19 | +(def ^:const supported-remotes |
| 20 | + |
| 21 | + "https://github.com"]) |
| 22 | + |
9 | 23 | (defn- run [& args]
|
10 | 24 | (let [{:keys [out err exit]} (apply sh args)]
|
11 | 25 | (when-not (zero? exit)
|
|
24 | 38 | (defn- is-clean? [repo-path]
|
25 | 39 | (zero-exit? repo-path "git diff --quiet"))
|
26 | 40 |
|
| 41 | +(defn- get-repo-remote [repo] |
| 42 | + (:out (sh "git" "-C" repo "config" "--get" "remote.origin.url"))) |
| 43 | + |
27 | 44 | (defn- get-current-branch [repo]
|
28 | 45 | (run "git" "-C" repo "branch" "--show-current"))
|
29 | 46 |
|
|
34 | 51 | [s n]
|
35 | 52 | (subs s 0 (min (count s) n)))
|
36 | 53 |
|
| 54 | +(defn has-supported-remote? [repo] |
| 55 | + (let [substr-in? (fn [e coll] |
| 56 | + (some #(str/includes? e %) coll)) |
| 57 | + supported-remote? #(substr-in? % supported-remotes) |
| 58 | + remote-url (get-repo-remote repo)] |
| 59 | + (when remote-url |
| 60 | + (supported-remote? remote-url)))) |
| 61 | + |
| 62 | +(defn is-on-default-branch? [repo] |
| 63 | + (let [branch (get-current-branch repo)] |
| 64 | + (some #{branch} ["master" "main"]))) |
| 65 | + |
37 | 66 | (defn- pull-repo [repo]
|
38 | 67 | (let [branch (get-current-branch repo)
|
39 | 68 | {:keys [exit out err]} (git-pull repo branch)]
|
|
59 | 88 | :err (fmt-msg err)})
|
60 | 89 |
|
61 | 90 | (defn -main [& _]
|
62 |
| - (let [clean-projects (filter is-clean? (list-projects)) |
| 91 | + (let [projects (list-projects) |
| 92 | + filtered-projects |
| 93 | + (filter (apply every-pred |
| 94 | + [is-clean? |
| 95 | + has-supported-remote? |
| 96 | + is-on-default-branch?]) |
| 97 | + projects) |
63 | 98 | executor (Executors/newFixedThreadPool 128)
|
64 |
| - tasks (mapv #(fn [] (pull-repo %)) clean-projects) |
| 99 | + tasks (mapv #(fn [] (pull-repo %)) filtered-projects) |
65 | 100 | execution-results (->> (.invokeAll ^ExecutorService executor tasks)
|
66 | 101 | (map #(.get ^Future %)))
|
67 | 102 | result (mapv prettify execution-results)
|
|
75 | 110 |
|
76 | 111 | (comment
|
77 | 112 |
|
78 |
| - (def clean-projects (filter is-clean? (list-projects))) |
| 113 | + (def projects (list-projects)) |
| 114 | + (def clean-projects (filter is-clean? projects)) |
| 115 | + (def supported-remote-projects (filter has-supported-remote? projects)) |
| 116 | + |
| 117 | + (filter (apply every-pred [is-clean? has-supported-remote?]) projects) |
| 118 | + |
| 119 | + (->> clean-projects |
| 120 | + (filter #(not (has-supported-remote? %)))) |
| 121 | + |
| 122 | + (get-repo-remote (nth clean-projects 60)) |
| 123 | + (has-supported-remote? (nth clean-projects 60)) |
| 124 | + (-> clean-projects last has-supported-remote?) |
| 125 | + |
| 126 | + (-> clean-projects last get-repo-remote) |
79 | 127 | (def pulled (->> clean-projects
|
80 | 128 | (take 5)))
|
81 | 129 | pulled
|
|
0 commit comments