@@ -22,7 +22,10 @@ use lazy_regex::{
22
22
Regex ,
23
23
} ;
24
24
use std:: io;
25
- use std:: path:: PathBuf ;
25
+ use std:: path:: {
26
+ Path ,
27
+ PathBuf ,
28
+ } ;
26
29
use std:: result:: Result as StdResult ;
27
30
use url:: Url ;
28
31
@@ -149,6 +152,57 @@ impl Repository {
149
152
Ok ( commits)
150
153
}
151
154
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
+
152
206
/// Normalizes the glob pattern to match the git diff paths.
153
207
///
154
208
/// It removes the leading `./` and adds `**` to the end if the pattern is a
0 commit comments