1
- use failure:: Error ;
1
+ use failure:: { Error , format_err } ;
2
2
use reqwest:: { self , blocking:: Client , blocking:: Response } ;
3
3
use serde:: { Deserialize , Serialize } ;
4
4
5
- use crate :: Commit ;
5
+ use crate :: { Commit , GitDate , parse_to_utc_date } ;
6
6
7
7
#[ derive( Serialize , Deserialize , Debug ) ]
8
8
struct GithubCommitComparison {
@@ -26,11 +26,12 @@ struct GithubAuthor {
26
26
name : String ,
27
27
}
28
28
29
- type GitDate = chrono:: DateTime < chrono:: Utc > ;
30
-
31
29
impl GithubCommitElem {
32
30
fn date ( & self ) -> Result < GitDate , Error > {
33
- Ok ( self . commit . committer . date . parse ( ) ?)
31
+ let ( date_str, _) = self . commit . committer . date . split_once ( "T" ) . ok_or_else ( || {
32
+ format_err ! ( "commit date should folllow the ISO 8061 format, eg: 2022-05-04T09:55:51Z" )
33
+ } ) ?;
34
+ Ok ( parse_to_utc_date ( date_str) ?)
34
35
}
35
36
36
37
fn git_commit ( self ) -> Result < Commit , Error > {
@@ -74,9 +75,58 @@ pub(crate) struct CommitsQuery<'a> {
74
75
/// Returns the bors merge commits between the two specified boundaries
75
76
/// (boundaries inclusive).
76
77
77
- impl < ' a > CommitsQuery < ' a > {
78
+ impl CommitsQuery < ' _ > {
78
79
pub fn get_commits ( & self ) -> Result < Vec < Commit > , Error > {
79
- get_commits ( * self )
80
+ // build up commit sequence, by feeding in `sha` as the starting point, and
81
+ // working way backwards to max(`self.since_date`, `self.earliest_sha`).
82
+ let mut commits = Vec :: new ( ) ;
83
+
84
+ // focus on Pull Request merges, all authored and committed by bors.
85
+ let author = "bors" ;
86
+
87
+ let client = Client :: builder ( ) . default_headers ( headers ( ) ?) . build ( ) ?;
88
+ for page in 1 .. {
89
+ let url = CommitsUrl {
90
+ page,
91
+ author,
92
+ since : self . since_date ,
93
+ sha : self . most_recent_sha ,
94
+ }
95
+ . url ( ) ;
96
+
97
+ let response: Response = client. get ( & url) . send ( ) ?;
98
+
99
+ let action = parse_paged_elems ( response, |elem : GithubCommitElem | {
100
+ let date = elem. date ( ) ?;
101
+ let sha = elem. sha . clone ( ) ;
102
+ let summary = elem. commit . message ;
103
+ let commit = Commit { sha, date, summary } ;
104
+ commits. push ( commit) ;
105
+
106
+ Ok ( if elem. sha == self . earliest_sha {
107
+ eprintln ! (
108
+ "ending github query because we found starting sha: {}" ,
109
+ elem. sha
110
+ ) ;
111
+ Loop :: Break
112
+ } else {
113
+ Loop :: Next
114
+ } )
115
+ } ) ?;
116
+
117
+ if let Loop :: Break = action {
118
+ break ;
119
+ }
120
+ }
121
+
122
+ eprintln ! (
123
+ "get_commits_between returning commits, len: {}" ,
124
+ commits. len( )
125
+ ) ;
126
+
127
+ // reverse to obtain chronological order
128
+ commits. reverse ( ) ;
129
+ Ok ( commits)
80
130
}
81
131
}
82
132
@@ -97,7 +147,7 @@ struct CommitDetailsUrl<'a> {
97
147
sha : & ' a str ,
98
148
}
99
149
100
- impl < ' a > ToUrl for CommitsUrl < ' a > {
150
+ impl ToUrl for CommitsUrl < ' _ > {
101
151
fn url ( & self ) -> String {
102
152
format ! (
103
153
"https://api.github.com/repos/{OWNER}/{REPO}/commits\
@@ -114,7 +164,7 @@ impl<'a> ToUrl for CommitsUrl<'a> {
114
164
}
115
165
}
116
166
117
- impl < ' a > ToUrl for CommitDetailsUrl < ' a > {
167
+ impl ToUrl for CommitDetailsUrl < ' _ > {
118
168
fn url ( & self ) -> String {
119
169
// "origin/master" is set as `sha` when there is no `--end=` definition
120
170
// specified on the command line. We define the GitHub master branch
@@ -134,92 +184,47 @@ impl<'a> ToUrl for CommitDetailsUrl<'a> {
134
184
}
135
185
}
136
186
137
- fn get_commits ( q : CommitsQuery ) -> Result < Vec < Commit > , Error > {
138
- // build up commit sequence, by feeding in `sha` as the starting point, and
139
- // working way backwards to max(`q.since_date`, `q.earliest_sha`).
140
- let mut commits = Vec :: new ( ) ;
141
-
142
- // focus on Pull Request merges, all authored and committed by bors.
143
- let author = "bors" ;
144
-
145
- let client = Client :: builder ( ) . default_headers ( headers ( ) ?) . build ( ) ?;
146
- for page in 1 .. {
147
- let url = CommitsUrl {
148
- page,
149
- author,
150
- since : q. since_date ,
151
- sha : q. most_recent_sha ,
152
- }
153
- . url ( ) ;
154
-
155
- let response: Response = client. get ( & url) . send ( ) ?;
156
-
157
- let action = parse_paged_elems ( response, |elem : GithubCommitElem | {
158
- let date: chrono:: DateTime < chrono:: Utc > = match elem. commit . committer . date . parse ( ) {
159
- Ok ( date) => date,
160
- Err ( err) => return Loop :: Err ( err. into ( ) ) ,
161
- } ;
162
- let sha = elem. sha . clone ( ) ;
163
- let summary = elem. commit . message ;
164
- let commit = Commit { sha, date, summary } ;
165
- commits. push ( commit) ;
166
-
167
- if elem. sha == q. earliest_sha {
168
- eprintln ! (
169
- "ending github query because we found starting sha: {}" ,
170
- elem. sha
171
- ) ;
172
- return Loop :: Break ;
173
- }
174
-
175
- Loop :: Next
176
- } ) ?;
177
-
178
- if let Loop :: Break = action {
179
- break ;
180
- }
181
- }
182
-
183
- eprintln ! (
184
- "get_commits_between returning commits, len: {}" ,
185
- commits. len( )
186
- ) ;
187
-
188
- // reverse to obtain chronological order
189
- commits. reverse ( ) ;
190
- Ok ( commits)
191
- }
192
-
193
- enum Loop < E > {
187
+ enum Loop {
194
188
Break ,
195
189
Next ,
196
- Err ( E ) ,
197
190
}
198
- enum Void { }
199
191
200
- fn parse_paged_elems < Elem : for < ' a > serde :: Deserialize < ' a > > (
192
+ fn parse_paged_elems (
201
193
response : Response ,
202
- mut k : impl FnMut ( Elem ) -> Loop < Error > ,
203
- ) -> Result < Loop < Void > , Error > {
204
- // parse the JSON into an array of the expected Elem type
205
- let elems: Vec < Elem > = response. json ( ) ?;
194
+ mut k : impl FnMut ( GithubCommitElem ) -> Result < Loop , Error > ,
195
+ ) -> Result < Loop , Error > {
196
+ let elems: Vec < GithubCommitElem > = response. json ( ) ?;
206
197
207
198
if elems. is_empty ( ) {
208
199
// we've run out of useful pages to lookup
209
200
return Ok ( Loop :: Break ) ;
210
201
}
211
202
212
- for elem in elems. into_iter ( ) {
213
- let act = k ( elem) ;
203
+ for elem in elems {
204
+ let act = k ( elem) ? ;
214
205
215
206
// the callback will tell us if we should terminate loop early (e.g. due to matching `sha`)
216
207
match act {
217
208
Loop :: Break => return Ok ( Loop :: Break ) ,
218
- Loop :: Err ( e) => return Err ( e) ,
219
209
Loop :: Next => continue ,
220
210
}
221
211
}
222
212
223
213
// by default, we keep searching on next page from github.
224
214
Ok ( Loop :: Next )
225
215
}
216
+
217
+ #[ cfg( test) ]
218
+ mod tests {
219
+ use super :: * ;
220
+
221
+ #[ test]
222
+ fn test_github ( ) {
223
+ let c = get_commit ( "25674202bb7415e0c0ecd07856749cfb7f591be6" ) . unwrap ( ) ;
224
+ let expected_c = Commit { sha : "25674202bb7415e0c0ecd07856749cfb7f591be6" . to_string ( ) ,
225
+ date : parse_to_utc_date ( "2022-05-04" ) . unwrap ( ) ,
226
+ summary : "Auto merge of #96695 - JohnTitor:rollup-oo4fc1h, r=JohnTitor\n \n Rollup of 6 pull requests\n \n Successful merges:\n \n - #96597 (openbsd: unbreak build on native platform)\n - #96662 (Fix typo in lint levels doc)\n - #96668 (Fix flaky rustdoc-ui test because it did not replace time result)\n - #96679 (Quick fix for #96223.)\n - #96684 (Update `ProjectionElem::Downcast` documentation)\n - #96686 (Add some TAIT-related tests)\n \n Failed merges:\n \n r? `@ghost`\n `@rustbot` modify labels: rollup" . to_string ( )
227
+ } ;
228
+ assert_eq ! ( c, expected_c)
229
+ }
230
+ }
0 commit comments