@@ -4,12 +4,16 @@ use anyhow::{anyhow, Context};
4
4
5
5
use crate :: bors:: command:: Parent ;
6
6
use crate :: bors:: comment:: cant_find_last_parent_comment;
7
+ use crate :: bors:: comment:: no_try_build_in_progress_comment;
8
+ use crate :: bors:: comment:: try_build_cancelled_comment;
7
9
use crate :: bors:: comment:: try_build_in_progress_comment;
10
+ use crate :: bors:: comment:: unclean_try_build_cancelled_comment;
8
11
use crate :: bors:: handlers:: labels:: handle_label_trigger;
9
12
use crate :: bors:: Comment ;
10
13
use crate :: bors:: RepositoryState ;
11
14
use crate :: database:: RunId ;
12
- use crate :: database:: { BuildModel , BuildStatus , PullRequestModel , WorkflowStatus , WorkflowType } ;
15
+ use crate :: database:: { BuildModel , BuildStatus , PullRequestModel } ;
16
+ use crate :: github:: api:: client:: GithubRepositoryClient ;
13
17
use crate :: github:: GithubRepoName ;
14
18
use crate :: github:: {
15
19
CommitSha , GithubUser , LabelTrigger , MergeError , PullRequest , PullRequestNumber ,
@@ -44,6 +48,8 @@ pub(super) async fn command_try_build(
44
48
return Ok ( ( ) ) ;
45
49
}
46
50
51
+ // Create pr model based on CI repo, so we can retrieve the pr later when
52
+ // the CI repo emits events
47
53
let pr_model = db
48
54
. get_or_create_pull_request ( repo. client . repository ( ) , pr. number )
49
55
. await
@@ -62,66 +68,94 @@ pub(super) async fn command_try_build(
62
68
}
63
69
} ;
64
70
71
+ match attempt_merge (
72
+ & repo. client ,
73
+ & pr. head . sha ,
74
+ & base_sha,
75
+ & auto_merge_commit_message ( pr, repo. client . repository ( ) , "<try>" , jobs) ,
76
+ )
77
+ . await ?
78
+ {
79
+ MergeResult :: Success ( merge_sha) => {
80
+ // If the merge was succesful, run CI with merged commit
81
+ run_try_build ( & repo. client , & db, pr_model, merge_sha. clone ( ) , base_sha) . await ?;
82
+
83
+ handle_label_trigger ( repo, pr. number , LabelTrigger :: TryBuildStarted ) . await ?;
84
+
85
+ repo. client
86
+ . post_comment ( pr. number , trying_build_comment ( & pr. head . sha , & merge_sha) )
87
+ . await
88
+ }
89
+ MergeResult :: Conflict => {
90
+ repo. client
91
+ . post_comment ( pr. number , merge_conflict_comment ( & pr. head . name ) )
92
+ . await
93
+ }
94
+ }
95
+ }
96
+
97
+ async fn attempt_merge (
98
+ client : & GithubRepositoryClient ,
99
+ head_sha : & CommitSha ,
100
+ base_sha : & CommitSha ,
101
+ merge_message : & str ,
102
+ ) -> anyhow:: Result < MergeResult > {
65
103
tracing:: debug!( "Attempting to merge with base SHA {base_sha}" ) ;
66
104
67
105
// First set the try branch to our base commit (either the selected parent or the main branch).
68
- repo . client
69
- . set_branch_to_sha ( TRY_MERGE_BRANCH_NAME , & base_sha)
106
+ client
107
+ . set_branch_to_sha ( TRY_MERGE_BRANCH_NAME , base_sha)
70
108
. await
71
109
. map_err ( |error| anyhow ! ( "Cannot set try merge branch to {}: {error:?}" , base_sha. 0 ) ) ?;
72
110
73
111
// Then merge the PR commit into the try branch
74
- match repo
75
- . client
76
- . merge_branches (
77
- TRY_MERGE_BRANCH_NAME ,
78
- & pr. head . sha ,
79
- & auto_merge_commit_message ( pr, repo. client . repository ( ) , "<try>" , jobs) ,
80
- )
112
+ match client
113
+ . merge_branches ( TRY_MERGE_BRANCH_NAME , head_sha, merge_message)
81
114
. await
82
115
{
83
116
Ok ( merge_sha) => {
84
117
tracing:: debug!( "Merge successful, SHA: {merge_sha}" ) ;
85
- // If the merge was succesful, then set the actual try branch that will run CI to the
86
- // merged commit.
87
- repo. client
88
- . set_branch_to_sha ( TRY_BRANCH_NAME , & merge_sha)
89
- . await
90
- . map_err ( |error| anyhow ! ( "Cannot set try branch to main branch: {error:?}" ) ) ?;
91
-
92
- db. attach_try_build (
93
- pr_model,
94
- TRY_BRANCH_NAME . to_string ( ) ,
95
- merge_sha. clone ( ) ,
96
- base_sha. clone ( ) ,
97
- )
98
- . await ?;
99
- tracing:: info!( "Try build started" ) ;
100
-
101
- handle_label_trigger ( repo, pr. number , LabelTrigger :: TryBuildStarted ) . await ?;
102
118
103
- let comment = Comment :: new ( format ! (
104
- ":hourglass: Trying commit {} with merge {}…" ,
105
- pr. head. sha. clone( ) ,
106
- merge_sha
107
- ) ) ;
108
- repo. client . post_comment ( pr. number , comment) . await ?;
109
- Ok ( ( ) )
119
+ Ok ( MergeResult :: Success ( merge_sha) )
110
120
}
111
121
Err ( MergeError :: Conflict ) => {
112
122
tracing:: warn!( "Merge conflict" ) ;
113
- repo. client
114
- . post_comment (
115
- pr. number ,
116
- Comment :: new ( merge_conflict_message ( & pr. head . name ) ) ,
117
- )
118
- . await ?;
119
- Ok ( ( ) )
123
+
124
+ Ok ( MergeResult :: Conflict )
120
125
}
121
126
Err ( error) => Err ( error. into ( ) ) ,
122
127
}
123
128
}
124
129
130
+ async fn run_try_build (
131
+ client : & GithubRepositoryClient ,
132
+ db : & PgDbClient ,
133
+ pr_model : PullRequestModel ,
134
+ commit_sha : CommitSha ,
135
+ parent_sha : CommitSha ,
136
+ ) -> anyhow:: Result < ( ) > {
137
+ client
138
+ . set_branch_to_sha ( TRY_BRANCH_NAME , & commit_sha)
139
+ . await
140
+ . map_err ( |error| anyhow ! ( "Cannot set try branch to main branch: {error:?}" ) ) ?;
141
+
142
+ db. attach_try_build (
143
+ pr_model,
144
+ TRY_BRANCH_NAME . to_string ( ) ,
145
+ commit_sha,
146
+ parent_sha,
147
+ )
148
+ . await ?;
149
+
150
+ tracing:: info!( "Try build started" ) ;
151
+ Ok ( ( ) )
152
+ }
153
+
154
+ enum MergeResult {
155
+ Success ( CommitSha ) ,
156
+ Conflict ,
157
+ }
158
+
125
159
fn get_base_sha (
126
160
pr_model : & PullRequestModel ,
127
161
parent : Option < Parent > ,
@@ -168,17 +202,12 @@ pub(super) async fn command_try_cancel(
168
202
let Some ( build) = get_pending_build ( pr) else {
169
203
tracing:: warn!( "No build found" ) ;
170
204
repo. client
171
- . post_comment (
172
- pr_number,
173
- Comment :: new (
174
- ":exclamation: There is currently no try build in progress." . to_string ( ) ,
175
- ) ,
176
- )
205
+ . post_comment ( pr_number, no_try_build_in_progress_comment ( ) )
177
206
. await ?;
178
207
return Ok ( ( ) ) ;
179
208
} ;
180
209
181
- match cancel_build_workflows ( repo, db. as_ref ( ) , & build) . await {
210
+ match cancel_build_workflows ( & repo. client , db. as_ref ( ) , & build) . await {
182
211
Err ( error) => {
183
212
tracing:: error!(
184
213
"Could not cancel workflows for SHA {}: {error:?}" ,
@@ -187,30 +216,21 @@ pub(super) async fn command_try_cancel(
187
216
db. update_build_status ( & build, BuildStatus :: Cancelled )
188
217
. await ?;
189
218
repo. client
190
- . post_comment (
191
- pr_number,
192
- Comment :: new (
193
- "Try build was cancelled. It was not possible to cancel some workflows."
194
- . to_string ( ) ,
195
- ) ,
196
- )
219
+ . post_comment ( pr_number, unclean_try_build_cancelled_comment ( ) )
197
220
. await ?
198
221
}
199
222
Ok ( workflow_ids) => {
200
223
db. update_build_status ( & build, BuildStatus :: Cancelled )
201
224
. await ?;
202
225
tracing:: info!( "Try build cancelled" ) ;
203
226
204
- let mut try_build_cancelled_comment = r#"Try build cancelled.
205
- Cancelled workflows:"#
206
- . to_string ( ) ;
207
- for id in workflow_ids {
208
- let url = repo. client . get_workflow_url ( id) ;
209
- try_build_cancelled_comment += format ! ( "\n - {}" , url) . as_str ( ) ;
210
- }
211
-
212
227
repo. client
213
- . post_comment ( pr_number, Comment :: new ( try_build_cancelled_comment) )
228
+ . post_comment (
229
+ pr_number,
230
+ try_build_cancelled_comment (
231
+ repo. client . get_workflow_urls ( workflow_ids. into_iter ( ) ) ,
232
+ ) ,
233
+ )
214
234
. await ?
215
235
}
216
236
} ;
@@ -219,20 +239,14 @@ Cancelled workflows:"#
219
239
}
220
240
221
241
pub async fn cancel_build_workflows (
222
- repo : & RepositoryState ,
242
+ client : & GithubRepositoryClient ,
223
243
db : & PgDbClient ,
224
244
build : & BuildModel ,
225
245
) -> anyhow:: Result < Vec < RunId > > {
226
- let pending_workflows = db
227
- . get_workflows_for_build ( build)
228
- . await ?
229
- . into_iter ( )
230
- . filter ( |w| w. status == WorkflowStatus :: Pending && w. workflow_type == WorkflowType :: Github )
231
- . map ( |w| w. run_id )
232
- . collect :: < Vec < _ > > ( ) ;
246
+ let pending_workflows = db. get_pending_workflows_for_build ( build) . await ?;
233
247
234
248
tracing:: info!( "Cancelling workflows {:?}" , pending_workflows) ;
235
- repo . client . cancel_workflows ( & pending_workflows) . await ?;
249
+ client. cancel_workflows ( & pending_workflows) . await ?;
236
250
Ok ( pending_workflows)
237
251
}
238
252
@@ -267,8 +281,14 @@ fn auto_merge_commit_message(
267
281
message
268
282
}
269
283
270
- fn merge_conflict_message ( branch : & str ) -> String {
271
- format ! (
284
+ fn trying_build_comment ( head_sha : & CommitSha , merge_sha : & CommitSha ) -> Comment {
285
+ Comment :: new ( format ! (
286
+ ":hourglass: Trying commit {head_sha} with merge {merge_sha}…"
287
+ ) )
288
+ }
289
+
290
+ fn merge_conflict_comment ( branch : & str ) -> Comment {
291
+ let message = format ! (
272
292
r#":lock: Merge conflict
273
293
274
294
This pull request and the master branch diverged in a way that cannot
@@ -298,7 +318,8 @@ handled during merge and rebase. This is normal, and you should still perform st
298
318
299
319
</details>
300
320
"#
301
- )
321
+ ) ;
322
+ Comment :: new ( message)
302
323
}
303
324
304
325
async fn check_try_permissions (
0 commit comments