From 3d20614ebe0d6c4b773ba7b7917146c07da1c770 Mon Sep 17 00:00:00 2001 From: Itai Edri Date: Sun, 15 Mar 2026 12:57:43 +0200 Subject: [PATCH] Add --ignore-changes option for filtering changes by file patterns - Add `--ignore-changes` CLI flag accepting comma-separated regexp patterns - Filter out commits where all changed files match ignore patterns - Support workspace-level `:ignore-changes` in `:kmono/workspace` config - Support per-package `:ignore-changes` override in `:kmono/package` config - Precedence order: CLI > per-package > workspace - Per-commit filtering: each commit is individually evaluated against patterns --- README.md | 52 +++++++- .../src/k16/kmono/cli/commands/exec.clj | 10 +- .../src/k16/kmono/cli/commands/query.clj | 10 +- .../src/k16/kmono/cli/commands/run.clj | 10 +- .../src/k16/kmono/cli/common/config.clj | 5 +- .../src/k16/kmono/cli/common/opts.clj | 5 + .../src/k16/kmono/core/packages.clj | 4 +- .../kmono-core/src/k16/kmono/core/schema.clj | 13 +- .../kmono-git/src/k16/kmono/git/files.clj | 30 ++++- .../kmono-version/src/k16/kmono/version.clj | 68 +++++++--- .../test/k16/kmono/changes_test.clj | 124 ++++++++++++++++++ 11 files changed, 294 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 1ea3fe3..3789a5e 100644 --- a/README.md +++ b/README.md @@ -197,6 +197,42 @@ last tagged version. The `k16.kmono.version/resolve-package-changes-since` can be used to find commits that have changed the package since a given git revision. +#### Ignoring Changes by File Pattern + +When using change detection (`--changed` or `--changed-since`), you can filter out changes to specific files using +`--ignore-changes`. This accepts a comma-separated list of regexp patterns matched against file paths relative to the +package root. If **all** changed files in a package match the ignore patterns, that package is treated as unchanged. + +```bash +# Ignore markdown-only changes +kmono run --changed --ignore-changes ".*\.md$" -M :test + +# Ignore multiple patterns (comma-separated) +kmono run --changed --ignore-changes ".*\.md$,LICENSE,^docs/" -M :build + +# Works with --changed-since too +kmono run --changed-since main --ignore-changes ".*\.md$" -M :test +``` + +This is useful in CI/CD workflows where documentation-only changes shouldn't trigger builds or tests. + +Patterns can also be configured at the workspace level in `deps.edn` (see [Workspace Configuration](#workspace-configuration)): + +```clojure +{:kmono/workspace {:group com.example + :ignore-changes [".*\\.md$" "^docs/" "LICENSE"]}} +``` + +Individual packages can override the workspace-level patterns by setting `:ignore-changes` in their `:kmono/package` +config (see [Package Configuration](#package-configuration)): + +```clojure +;; packages/my-lib/deps.edn +{:kmono/package {:ignore-changes [".*\\.md$" "^test-fixtures/"]}} +``` + +The precedence order is: CLI `--ignore-changes` > per-package `:ignore-changes` > workspace `:ignore-changes`. + These tools and others can be used to build sophisticated build and release pipelines for kmono workspaces. ## API Documentation @@ -263,6 +299,7 @@ configuration accepts the following properties: | `:repl-aliases` | `[keyword?]` | `nil` | A set of `deps` aliases to include when running `kmono repl` | | `:aliases` | `[keyword?]` | `nil` | A set of `deps` aliases to include for all kmono workspace commands by default | | `:package-aliases` | `[keyword?]` | `nil` | A set of namespaced [alias globs](#alias-globs) that describe the aliases of packages within the workspace to include in the classpath | +| `:ignore-changes` | `[string?]` | `nil` | A list of regexp patterns for file paths to ignore when determining package changes (used with `--changed` / `--changed-since`) | Example: @@ -271,7 +308,9 @@ Example: {:kmono/workspace {:group com.example :packages #{"./(packages|modules)/**"} ;; Include any `:test` aliases from all (`*`) packages in the workspace - :package-aliases [:*/test]} + :package-aliases [:*/test] + ;; Ignore doc-only changes when using --changed + :ignore-changes [".*\\.md$" "LICENSE"]} :paths ["src" "resources"] @@ -285,9 +324,10 @@ Packages in the workspace can optionally provide their own configuration metadat | Field | Type | Default | Description | | ----------- | -------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -| `:group` | `symbol?` | `nil` | The mvn group to use for this package. If not specified, the `:group` specified in the root `:kmono/workspace` configuration will be used. | -| `:name` | `string? \| symbol?` | `$dir` | The name of the package. If not set the name of the parent directory containing the packages' `deps.edn` file will be used as the package name | -| `:excluded` | `boolean?` | `false` | Whether or not this package is excluded from the project workspace | +| `:group` | `symbol?` | `nil` | The mvn group to use for this package. If not specified, the `:group` specified in the root `:kmono/workspace` configuration will be used. | +| `:name` | `string? \| symbol?` | `$dir` | The name of the package. If not set the name of the parent directory containing the packages' `deps.edn` file will be used as the package name | +| `:excluded` | `boolean?` | `false` | Whether or not this package is excluded from the project workspace | +| `:ignore-changes` | `[string?]` | `nil` | Override the workspace-level `:ignore-changes` patterns for this package | Example @@ -296,7 +336,9 @@ Example {:kmono/package {;; Maven artifacts group :group com.example ;; Override the default package name - :name example-lib} + :name example-lib + ;; Override workspace-level ignore-changes for this package + :ignore-changes [".*\\.md$" "^test-fixtures/"]} :paths ["src"] :deps {...} diff --git a/packages/kmono-cli/src/k16/kmono/cli/commands/exec.clj b/packages/kmono-cli/src/k16/kmono/cli/commands/exec.clj index 6e743e7..c39d772 100644 --- a/packages/kmono-cli/src/k16/kmono/cli/commands/exec.clj +++ b/packages/kmono-cli/src/k16/kmono/cli/commands/exec.clj @@ -17,18 +17,21 @@ include-dependents run-in-order concurrency] :as opts} args] - (let [{:keys [root packages]} (common.context/load-context opts) + (let [{:keys [root packages config]} (common.context/load-context opts) + ignore-changes (:ignore-changes config) + change-opts (when ignore-changes + {:ignore-changes ignore-changes}) packages (cond-> packages (or changed skip-unchanged) (->> (kmono.version/resolve-package-versions root) - (kmono.version/resolve-package-changes root) + (kmono.version/resolve-package-changes root change-opts) (core.graph/filter-by kmono.version/package-changed? {:include-dependents include-dependents})) changed-since - (->> (kmono.version/resolve-package-changes-since root changed-since) + (->> (kmono.version/resolve-package-changes-since root changed-since change-opts) (core.graph/filter-by kmono.version/package-changed? {:include-dependents include-dependents})) @@ -65,6 +68,7 @@ :skip-unchanged opts/skip-unchanged-opt :changed opts/changed-opt :changed-since opts/changed-since-opt + :ignore-changes opts/ignore-changes-opt :filter opts/package-filter-opt :include-dependents include-dependents :concurrency opts/concurrency-opt} diff --git a/packages/kmono-cli/src/k16/kmono/cli/commands/query.clj b/packages/kmono-cli/src/k16/kmono/cli/commands/query.clj index a7189ea..e076ee6 100644 --- a/packages/kmono-cli/src/k16/kmono/cli/commands/query.clj +++ b/packages/kmono-cli/src/k16/kmono/cli/commands/query.clj @@ -25,16 +25,19 @@ (log/error "Either --with-changes or --with-changes-since is required when setting --filter-unchanged") (System/exit 1)) - {:keys [root packages]} (common.context/load-context opts) + {:keys [root packages config]} (common.context/load-context opts) + ignore-changes (:ignore-changes config) + change-opts (when ignore-changes + {:ignore-changes ignore-changes}) packages (cond->> packages with-versions (kmono.version/resolve-package-versions root) with-changes - (kmono.version/resolve-package-changes root) + (kmono.version/resolve-package-changes root change-opts) with-changes-since - (kmono.version/resolve-package-changes-since root with-changes-since) + (kmono.version/resolve-package-changes-since root with-changes-since change-opts) filter-unchanged (core.graph/filter-by kmono.version/package-changed? @@ -107,6 +110,7 @@ :options {:with-versions with-versions :with-changes-since with-changes-since :with-changes with-changes + :ignore-changes opts/ignore-changes-opt :filter-unchanged filter-unchanged :include-dependents include-dependents :filter opts/package-filter-opt diff --git a/packages/kmono-cli/src/k16/kmono/cli/commands/run.clj b/packages/kmono-cli/src/k16/kmono/cli/commands/run.clj index 0ee1816..4c96ff2 100644 --- a/packages/kmono-cli/src/k16/kmono/cli/commands/run.clj +++ b/packages/kmono-cli/src/k16/kmono/cli/commands/run.clj @@ -14,20 +14,23 @@ (set! *warn-on-reflection* true) (defn- run-command [{:keys [M T X skip-unchanged changed changed-since] :as opts} args] - (let [{:keys [root packages]} (common.context/load-context opts) + (let [{:keys [root packages config]} (common.context/load-context opts) filter' (:filter opts) + ignore-changes (:ignore-changes config) + change-opts (when ignore-changes + {:ignore-changes ignore-changes}) packages (cond-> packages filter' (->> (core.graph/filter-by (core.packages/name-matches? filter'))) (or changed skip-unchanged) (->> (kmono.version/resolve-package-versions root) - (kmono.version/resolve-package-changes root) + (kmono.version/resolve-package-changes root change-opts) (core.graph/filter-by kmono.version/package-changed? {:include-dependents true})) changed-since - (->> (kmono.version/resolve-package-changes-since root changed-since) + (->> (kmono.version/resolve-package-changes-since root changed-since change-opts) (core.graph/filter-by kmono.version/package-changed? {:include-dependents true}))) @@ -68,6 +71,7 @@ :skip-unchanged opts/skip-unchanged-opt :changed opts/changed-opt :changed-since opts/changed-since-opt + :ignore-changes opts/ignore-changes-opt :concurrency opts/concurrency-opt :filter opts/package-filter-opt diff --git a/packages/kmono-cli/src/k16/kmono/cli/common/config.clj b/packages/kmono-cli/src/k16/kmono/cli/common/config.clj index 5d4aefe..dc14d10 100644 --- a/packages/kmono-cli/src/k16/kmono/cli/common/config.clj +++ b/packages/kmono-cli/src/k16/kmono/cli/common/config.clj @@ -1,7 +1,8 @@ (ns k16.kmono.cli.common.config) (defn merge-workspace-config - [workspace-config {:keys [package-aliases aliases]}] + [workspace-config {:keys [package-aliases aliases ignore-changes]}] (cond-> workspace-config package-aliases (assoc :package-aliases package-aliases) - aliases (update :aliases into aliases))) + aliases (update :aliases into aliases) + ignore-changes (assoc :ignore-changes ignore-changes))) diff --git a/packages/kmono-cli/src/k16/kmono/cli/common/opts.clj b/packages/kmono-cli/src/k16/kmono/cli/common/opts.clj index 962ebc5..3463b4f 100644 --- a/packages/kmono-cli/src/k16/kmono/cli/common/opts.clj +++ b/packages/kmono-cli/src/k16/kmono/cli/common/opts.clj @@ -68,3 +68,8 @@ {:desc "Filter packages by those that have changed since the specified git " :ref "" :coerce :string}) + +(def ignore-changes-opt + {:desc "Comma-separated regexp patterns of file paths to ignore when determining changes" + :coerce :string + :parse-fn (fn [value] (str/split value #","))}) diff --git a/packages/kmono-core/src/k16/kmono/core/packages.clj b/packages/kmono-core/src/k16/kmono/core/packages.clj index 2619d70..17539d5 100644 --- a/packages/kmono-core/src/k16/kmono/core/packages.clj +++ b/packages/kmono-core/src/k16/kmono/core/packages.clj @@ -16,8 +16,8 @@ (not (fs/same-file? project-root package-path))) (let [relative-path (str (fs/relativize project-root package-path)) package (merge {:name (symbol (fs/file-name package-path))} - (select-keys workspace-config [:group]) - (select-keys config [:group :name :deps-edn]) + (select-keys workspace-config [:group :ignore-changes]) + (select-keys config [:group :name :deps-edn :ignore-changes]) {:absolute-path (str package-path) :relative-path relative-path :depends-on #{}}) diff --git a/packages/kmono-core/src/k16/kmono/core/schema.clj b/packages/kmono-core/src/k16/kmono/core/schema.clj index 9c03875..6421f8c 100644 --- a/packages/kmono-core/src/k16/kmono/core/schema.clj +++ b/packages/kmono-core/src/k16/kmono/core/schema.clj @@ -19,14 +19,19 @@ [:aliases {:optional true} [:vector :keyword]] [:package-aliases {:optional true} - [:vector :keyword]]]) + [:vector :keyword]] + + [:ignore-changes {:optional true} + [:sequential :string]]]) (def ?PackageConfig [:map [:group {:optional true} :symbol] [:name {:optional true} [:maybe [:or :string :symbol]]] - [:excluded {:optional true} :boolean]]) + [:excluded {:optional true} :boolean] + [:ignore-changes {:optional true} + [:sequential :string]]]) (def ?Coordinate [:map @@ -56,7 +61,9 @@ [:dependents [:set :symbol]] [:absolute-path :string] - [:relative-path :string]]) + [:relative-path :string] + + [:ignore-changes {:optional true} [:sequential :string]]]) (def ?PackageMap [:map-of :symbol ?Package]) diff --git a/packages/kmono-git/src/k16/kmono/git/files.clj b/packages/kmono-git/src/k16/kmono/git/files.clj index 5ac3a1a..b320a1d 100644 --- a/packages/kmono-git/src/k16/kmono/git/files.clj +++ b/packages/kmono-git/src/k16/kmono/git/files.clj @@ -5,7 +5,8 @@ (:import [java.io ByteArrayOutputStream] [org.eclipse.jgit.diff DiffEntry DiffFormatter] - [org.eclipse.jgit.lib Constants Repository])) + [org.eclipse.jgit.lib Constants Repository] + [org.eclipse.jgit.revwalk RevCommit RevWalk])) (set! *warn-on-reflection* true) @@ -41,3 +42,30 @@ (or (nil? subdir) (str/starts-with? entry subdir))))) results)))))) + +(defn find-commit-changed-files + "Return file paths changed by a specific commit. If `subdir` is provided, only + include files within that subdir." + [^String repo-path {:keys [sha subdir]}] + (git/with-repo [repo repo-path] + (let [commit-id (Repository/.resolve repo sha) + subdir-prefix (when subdir (str subdir "/"))] + (with-open [walk (RevWalk. repo)] + (let [commit (RevWalk/.parseCommit walk commit-id) + parent-tree (when (pos? (RevCommit/.getParentCount commit)) + (let [parent (RevWalk/.parseCommit walk + (aget (RevCommit/.getParents commit) 0))] + (RevCommit/.getTree parent))) + commit-tree (RevCommit/.getTree commit)] + (with-open [out (ByteArrayOutputStream.) + df (DiffFormatter. out)] + (DiffFormatter/.setRepository df repo) + (let [diffs (DiffFormatter/.scan df parent-tree commit-tree)] + (into [] + (comp + (map #(DiffEntry/.getNewPath %)) + (remove #(= % DiffEntry/DEV_NULL)) + (filter (fn [path] + (or (nil? subdir-prefix) + (str/starts-with? path subdir-prefix))))) + diffs)))))))) diff --git a/packages/kmono-version/src/k16/kmono/version.clj b/packages/kmono-version/src/k16/kmono/version.clj index 512bf0e..3338f99 100644 --- a/packages/kmono-version/src/k16/kmono/version.clj +++ b/packages/kmono-version/src/k16/kmono/version.clj @@ -6,6 +6,7 @@ [k16.kmono.core.thread :as core.thread] [k16.kmono.git :as git] [k16.kmono.git.commit :as git.commit] + [k16.kmono.git.files :as git.files] [k16.kmono.git.tags :as git.tags] [k16.kmono.version.semver :as semver])) @@ -68,15 +69,38 @@ (transient {})) persistent!))) +(defn- file-ignored? + "Returns true if the file path matches any of the ignore patterns." + [patterns file-path] + (boolean (some #(re-find (re-pattern %) file-path) patterns))) + +(defn- commit-has-meaningful-changes? + "Returns true if the commit has changed files that don't all match ignore + patterns. Files are matched relative to the package root." + [project-root pkg ignore-changes commit] + (let [files (git.files/find-commit-changed-files + project-root {:sha (:sha commit) + :subdir (:relative-path pkg)}) + pkg-prefix (str (:relative-path pkg) "/") + relative-files (map #(str/replace-first % pkg-prefix "") files)] + (boolean (seq (remove #(file-ignored? ignore-changes %) relative-files))))) + (defn- -resolve-package-changes-since - [project-root packages rev-fn] + [project-root packages rev-fn {:keys [ignore-changes]}] (git/with-repo [_ project-root] (into {} (core.thread/batch (fn find-commits [[pkg-name pkg]] - (let [commits (git.commit/find-commits-since - project-root {:ref (rev-fn pkg) + (let [ref (rev-fn pkg) + commits (git.commit/find-commits-since + project-root {:ref ref :subdir (:relative-path pkg)}) + pkg-ignore-changes (or (:ignore-changes pkg) ignore-changes) + commits (if (and (seq pkg-ignore-changes) (seq commits) ref) + (filterv #(commit-has-meaningful-changes? + project-root pkg pkg-ignore-changes %) + commits) + commits) pkg (assoc pkg :commits (vec commits))] [pkg-name pkg])) 32) @@ -90,25 +114,39 @@ and version. See `k16.kmono.version/resolve-package-versions` for a description on how this tag is expected to be formatted. - Any commits found will be appended to the packages `:commits` key." + Any commits found will be appended to the packages `:commits` key. + + An optional `opts` map may be provided with `:ignore-changes` - a sequence of + regexp patterns. Commits where all changed files match these patterns are + filtered out." {:malli/schema [:-> :string core.schema/?PackageMap core.schema/?PackageMap]} - [project-root packages] - (-resolve-package-changes-since project-root - packages - (fn [pkg] - (when (:version pkg) - (create-package-version-tag pkg))))) + ([project-root packages] + (resolve-package-changes project-root nil packages)) + ([project-root opts packages] + (-resolve-package-changes-since project-root + packages + (fn [pkg] + (when (:version pkg) + (create-package-version-tag pkg))) + opts))) (defn resolve-package-changes-since "For each package try find all commits that modified files in the package subdirectory since the given rev. - Any commits found will be appended to the packages `:commits` key." + Any commits found will be appended to the packages `:commits` key. + + An optional `opts` map may be provided with `:ignore-changes` - a sequence of + regexp patterns. Commits where all changed files match these patterns are + filtered out." {:malli/schema [:-> :string :string core.schema/?PackageMap core.schema/?PackageMap]} - [project-root rev packages] - (-resolve-package-changes-since project-root - packages - (constantly rev))) + ([project-root rev packages] + (resolve-package-changes-since project-root rev nil packages)) + ([project-root rev opts packages] + (-resolve-package-changes-since project-root + packages + (constantly rev) + opts))) (defn package-changed? "A filter function designed to be used with `k16.kmono.core.graph/filter-by`. diff --git a/packages/kmono-version/test/k16/kmono/changes_test.clj b/packages/kmono-version/test/k16/kmono/changes_test.clj index 29e4b65..a92ea73 100644 --- a/packages/kmono-version/test/k16/kmono/changes_test.clj +++ b/packages/kmono-version/test/k16/kmono/changes_test.clj @@ -57,3 +57,127 @@ :message "Change package b" :body ""}]}} packages)))) + +(deftest ignore-changes-all-files-match-test + (git.tags/create-tags *repo* {:tags ["com.kepler16/a@1.0.0" + "com.kepler16/b@1.1.0"]}) + + (fs/create-file (fs/file *repo* "packages/a/README.md")) + (commit *repo* "docs: add readme to package a") + + (let [config (core.config/resolve-workspace-config *repo*) + packages (->> (core.packages/resolve-packages *repo* config) + (kmono.version/resolve-package-versions *repo*) + (kmono.version/resolve-package-changes *repo* {:ignore-changes [".*\\.md$"]}))] + (is (match? {'com.kepler16/a {:version "1.0.0" + :commits []} + 'com.kepler16/b {:version "1.1.0" + :commits []}} + packages)))) + +(deftest ignore-changes-partial-match-test + (git.tags/create-tags *repo* {:tags ["com.kepler16/a@1.0.0" + "com.kepler16/b@1.1.0"]}) + + (fs/create-file (fs/file *repo* "packages/a/README.md")) + (fs/create-dirs (fs/file *repo* "packages/a/src")) + (fs/create-file (fs/file *repo* "packages/a/src/core.clj")) + (commit *repo* "feat: add code and docs to package a") + + (let [config (core.config/resolve-workspace-config *repo*) + packages (->> (core.packages/resolve-packages *repo* config) + (kmono.version/resolve-package-versions *repo*) + (kmono.version/resolve-package-changes *repo* {:ignore-changes [".*\\.md$"]}))] + (is (match? {'com.kepler16/a {:version "1.0.0" + :commits [{:message "feat: add code and docs to package a" + :body ""}]} + 'com.kepler16/b {:version "1.1.0" + :commits []}} + packages)))) + +(deftest ignore-changes-multiple-patterns-test + (git.tags/create-tags *repo* {:tags ["com.kepler16/a@1.0.0" + "com.kepler16/b@1.1.0"]}) + + (fs/create-file (fs/file *repo* "packages/a/README.md")) + (fs/create-file (fs/file *repo* "packages/a/LICENSE")) + (commit *repo* "docs: add readme and license") + + (let [config (core.config/resolve-workspace-config *repo*) + packages (->> (core.packages/resolve-packages *repo* config) + (kmono.version/resolve-package-versions *repo*) + (kmono.version/resolve-package-changes *repo* {:ignore-changes [".*\\.md$" "LICENSE"]}))] + (is (match? {'com.kepler16/a {:version "1.0.0" + :commits []} + 'com.kepler16/b {:version "1.1.0" + :commits []}} + packages)))) + +(deftest ignore-changes-since-rev-test + (let [start-commit (get-current-commit *repo*) + + _ (fs/create-file (fs/file *repo* "packages/b/CHANGELOG.md")) + + _ (commit *repo* "docs: add changelog to package b") + + config (core.config/resolve-workspace-config *repo*) + packages (->> (core.packages/resolve-packages *repo* config) + (kmono.version/resolve-package-changes-since *repo* start-commit {:ignore-changes [".*\\.md$"]}))] + + (is (match? {'com.kepler16/a {:commits []} + 'com.kepler16/b {:commits []}} + packages)))) + +(deftest ignore-changes-package-override-test + ;; Package a declares its own :ignore-changes that overrides workspace-level + (spit (str (fs/file *repo* "packages/a/deps.edn")) + (pr-str {:kmono/package {:ignore-changes [".*\\.txt$"]} + :aliases {:test {:extra-paths ["test"] + :extra-deps {'local/excluded {:local/root "../excluded"}}}}})) + (commit *repo* "configure package a ignore-changes") + + (git.tags/create-tags *repo* {:tags ["com.kepler16/a@1.0.0" + "com.kepler16/b@1.1.0"]}) + + ;; Add .md files to both packages + (fs/create-file (fs/file *repo* "packages/a/README.md")) + (fs/create-file (fs/file *repo* "packages/b/README.md")) + (commit *repo* "docs: add readmes") + + (let [config (core.config/resolve-workspace-config *repo*) + packages (->> (core.packages/resolve-packages *repo* config) + (kmono.version/resolve-package-versions *repo*) + ;; Workspace-level ignores .md files + (kmono.version/resolve-package-changes *repo* {:ignore-changes [".*\\.md$"]}))] + ;; Package a uses its own patterns (*.txt), so .md is NOT ignored → changed + (is (match? {'com.kepler16/a {:version "1.0.0" + :commits [{:message "docs: add readmes" + :body ""}]}} + packages)) + ;; Package b has no override, uses workspace patterns (*.md) → unchanged + (is (match? {'com.kepler16/b {:version "1.1.0" + :commits []}} + packages)))) + +(deftest ignore-changes-per-commit-filtering-test + (git.tags/create-tags *repo* {:tags ["com.kepler16/a@1.0.0" + "com.kepler16/b@1.1.0"]}) + + ;; Commit 1: only a .md file (should be filtered out) + (fs/create-file (fs/file *repo* "packages/a/README.md")) + (commit *repo* "docs: add readme") + + ;; Commit 2: a .clj file (should be kept) + (fs/create-dirs (fs/file *repo* "packages/a/src")) + (fs/create-file (fs/file *repo* "packages/a/src/core.clj")) + (commit *repo* "feat: add core module") + + (let [config (core.config/resolve-workspace-config *repo*) + packages (->> (core.packages/resolve-packages *repo* config) + (kmono.version/resolve-package-versions *repo*) + (kmono.version/resolve-package-changes *repo* {:ignore-changes [".*\\.md$"]}))] + ;; Only the second commit should remain + (is (match? {'com.kepler16/a {:version "1.0.0" + :commits [{:message "feat: add core module" + :body ""}]}} + packages))))