@@ -27,14 +27,37 @@ pub mod git {
27
27
}
28
28
29
29
pub fn extract_commit_hash ( file : & str ) -> String {
30
- // input: "target/$commit_id/test_name.raw"
30
+ // input: "target/regression_artifacts/ $commit_id/test_name.raw"
31
31
// output: "$commit_id"
32
- file. split ( "target/" )
32
+ file. split ( "target/regression_artifacts/ " )
33
33
. nth ( 1 )
34
34
. and_then ( |s| s. split ( '/' ) . next ( ) )
35
35
. map ( |s| s. to_string ( ) )
36
36
. unwrap_or_default ( ) // This will return an empty string if the Option is None
37
37
}
38
+
39
+ pub fn is_mainline ( commit_hash : & str ) -> bool {
40
+ // Execute the git command to check which branches contain the given commit.
41
+ let output = Command :: new ( "git" )
42
+ . args ( [ "branch" , "--contains" , commit_hash] )
43
+ . output ( )
44
+ . expect ( "Failed to execute git branch" ) ;
45
+
46
+ // If the command fails, it indicates that the commit is either detached
47
+ // or does not exist in any branches. Meaning, it is not part of mainline.
48
+ if !output. status . success ( ) {
49
+ return false ;
50
+ }
51
+
52
+ // Convert the command output to a string and check each line.
53
+ let branches = String :: from_utf8_lossy ( & output. stdout ) ;
54
+ branches. lines ( ) . any ( |branch| {
55
+ // Trim the branch name to remove any leading or trailing whitespace.
56
+ // The branch name could be prefixed with '*', indicating the current branch.
57
+ // We check for both "main" and "* main" to account for this possibility.
58
+ branch. trim ( ) == "main" || branch. trim ( ) == "* main"
59
+ } )
60
+ }
38
61
}
39
62
40
63
#[ cfg( test) ]
@@ -117,7 +140,7 @@ mod tests {
117
140
impl RawProfile {
118
141
fn new ( test_name : & str ) -> Self {
119
142
let commit_hash = git:: get_current_commit_hash ( ) ;
120
- create_dir_all ( format ! ( "target/{commit_hash}" ) ) . unwrap ( ) ;
143
+ create_dir_all ( format ! ( "target/regression_artifacts/ {commit_hash}" ) ) . unwrap ( ) ;
121
144
122
145
let raw_profile = Self {
123
146
test_name : test_name. to_owned ( ) ,
@@ -143,7 +166,10 @@ mod tests {
143
166
}
144
167
145
168
fn path ( & self ) -> String {
146
- format ! ( "target/{}/{}.raw" , self . commit_hash, self . test_name)
169
+ format ! (
170
+ "target/regression_artifacts/{}/{}.raw" ,
171
+ self . commit_hash, self . test_name
172
+ )
147
173
}
148
174
149
175
// Returns the annotated profile associated with a raw profile
@@ -154,8 +180,9 @@ mod tests {
154
180
/// Return the raw profiles for `test_name` in "git" order. `tuple.0` is older than `tuple.1`
155
181
///
156
182
/// This method will panic if there are not two profiles.
183
+ /// This method will also panic if both commits are on different logs (not mainline).
157
184
fn query ( test_name : & str ) -> ( RawProfile , RawProfile ) {
158
- let pattern = format ! ( "target/**/*{}.raw" , test_name) ;
185
+ let pattern = format ! ( "target/regression_artifacts/ **/*{}.raw" , test_name) ;
159
186
let raw_files: Vec < String > = glob:: glob ( & pattern)
160
187
. expect ( "Failed to read glob pattern" )
161
188
. filter_map ( Result :: ok)
@@ -167,18 +194,28 @@ mod tests {
167
194
test_name : test_name. to_string ( ) ,
168
195
commit_hash : git:: extract_commit_hash ( & raw_files[ 0 ] ) ,
169
196
} ;
170
-
171
197
let profile2 = RawProfile {
172
198
test_name : test_name. to_string ( ) ,
173
199
commit_hash : git:: extract_commit_hash ( & raw_files[ 1 ] ) ,
174
200
} ;
175
201
176
- if git:: is_older_commit ( & profile1. commit_hash , & profile2. commit_hash ) {
177
- ( profile1, profile2)
178
- } else if git:: is_older_commit ( & profile2. commit_hash , & profile1. commit_hash ) {
179
- ( profile2, profile1)
202
+ // xor returns true if exactly one commit is mainline
203
+ if git:: is_mainline ( & profile1. commit_hash ) ^ git:: is_mainline ( & profile2. commit_hash ) {
204
+ // Return the mainline as first commit
205
+ if git:: is_mainline ( & profile1. commit_hash ) {
206
+ ( profile1, profile2)
207
+ } else {
208
+ ( profile2, profile1)
209
+ }
180
210
} else {
181
- panic ! ( "The commits are not in the same log" ) ;
211
+ // Neither or both profiles are on the mainline, so return the older one first
212
+ if git:: is_older_commit ( & profile1. commit_hash , & profile2. commit_hash ) {
213
+ ( profile1, profile2)
214
+ } else if git:: is_older_commit ( & profile2. commit_hash , & profile1. commit_hash ) {
215
+ ( profile2, profile1)
216
+ } else {
217
+ panic ! ( "The commits are not in the same log, are identical, or there are not two commits available" ) ;
218
+ }
182
219
}
183
220
}
184
221
}
@@ -211,7 +248,10 @@ mod tests {
211
248
}
212
249
213
250
fn path ( & self ) -> String {
214
- format ! ( "target/{}/{}.annotated" , self . commit_hash, self . test_name)
251
+ format ! (
252
+ "target/regression_artifacts/{}/{}.annotated" ,
253
+ self . commit_hash, self . test_name
254
+ )
215
255
}
216
256
217
257
fn instruction_count ( & self ) -> i64 {
@@ -240,7 +280,7 @@ mod tests {
240
280
assert_command_success ( diff_output. clone ( ) ) ;
241
281
242
282
// write the diff to disk
243
- create_dir_all ( format ! ( "target/diff" ) ) . unwrap ( ) ;
283
+ create_dir_all ( "target/regression_artifacts/ diff" ) . unwrap ( ) ;
244
284
let diff_content = String :: from_utf8 ( diff_output. stdout )
245
285
. expect ( "Invalid UTF-8 in cg_annotate --diff output" ) ;
246
286
write ( diff_profile. path ( ) , diff_content) . expect ( "Failed to write to file" ) ;
@@ -249,7 +289,7 @@ mod tests {
249
289
}
250
290
251
291
fn path ( & self ) -> String {
252
- format ! ( "target/diff/{}.diff" , self . test_name)
292
+ format ! ( "target/regression_artifacts/ diff/{}.diff" , self . test_name)
253
293
}
254
294
255
295
fn assert_performance ( & self , max_diff : f64 ) {
0 commit comments