Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit aba15af

Browse files
committedMar 7, 2025··
feat(repo): get submodule repositories with commit ranges
1 parent 9babe06 commit aba15af

File tree

1 file changed

+55
-1
lines changed

1 file changed

+55
-1
lines changed
 

‎git-cliff-core/src/repo.rs

+55-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ use lazy_regex::{
2222
Regex,
2323
};
2424
use std::io;
25-
use std::path::PathBuf;
25+
use std::path::{
26+
Path,
27+
PathBuf,
28+
};
2629
use std::result::Result as StdResult;
2730
use url::Url;
2831

@@ -149,6 +152,57 @@ impl Repository {
149152
Ok(commits)
150153
}
151154

155+
/// Returns submodule repositories for a given commit range.
156+
///
157+
/// For a two given commits in this repository, a list of changed submodules
158+
/// is calculated. For each submodule a [`Repository`] object is created
159+
/// along with a commit range string
160+
/// "first_submodule_commit..last_submodule_commit". This can then be used
161+
/// to query the submodule's commits by using [`Repository::commits`].
162+
pub fn submodules_range(
163+
&self,
164+
first_commit: &Commit,
165+
last_commit: &Commit,
166+
) -> Result<Vec<(Repository, String)>> {
167+
let diff = self.inner.diff_tree_to_tree(
168+
first_commit.tree().ok().as_ref(),
169+
last_commit.tree().ok().as_ref(),
170+
None,
171+
)?;
172+
// (path, commit_range)
173+
let before_and_after_deltas = diff.deltas().filter_map(|delta| {
174+
let old_file_id = delta.old_file().id();
175+
let new_file_id = delta.new_file().id();
176+
// no changes or element added/removed
177+
if old_file_id == new_file_id ||
178+
new_file_id.is_zero() ||
179+
old_file_id.is_zero()
180+
{
181+
None
182+
} else {
183+
let range = format!(
184+
"{}..{}",
185+
old_file_id.to_string(),
186+
new_file_id.to_string()
187+
);
188+
delta
189+
.new_file()
190+
.path()
191+
.and_then(Path::to_str)
192+
.zip(Some(range))
193+
}
194+
});
195+
// (repository, commit_range)
196+
let submodule_range = before_and_after_deltas.filter_map(|(path, range)| {
197+
self.inner
198+
.find_submodule(path)
199+
.ok()
200+
.and_then(|submodule| Self::init(submodule.path().into()).ok())
201+
.zip(Some(range))
202+
});
203+
Ok(submodule_range.collect())
204+
}
205+
152206
/// Normalizes the glob pattern to match the git diff paths.
153207
///
154208
/// It removes the leading `./` and adds `**` to the end if the pattern is a

0 commit comments

Comments
 (0)
Please sign in to comment.