Skip to content

Commit 957bec4

Browse files
feat: support arbitrary try build
1 parent a5471ae commit 957bec4

File tree

4 files changed

+116
-18
lines changed

4 files changed

+116
-18
lines changed

src/bors/command/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ pub enum BorsCommand {
2222
Try {
2323
/// Parent commit which should be used as the merge base.
2424
parent: Option<Parent>,
25+
/// The CI workflow to run.
26+
jobs: Option<Vec<String>>,
2527
},
2628
/// Cancel a try build.
2729
TryCancel,

src/bors/command/parser.rs

Lines changed: 88 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,15 @@ fn parser_try<'a>(command: &'a str, parts: &[CommandPart<'a>]) -> ParseResult<'a
140140
}
141141

142142
let mut parent = None;
143+
let mut jobs = None;
143144

144145
for part in parts {
145146
match part {
146147
CommandPart::Bare(key) => {
147148
return Some(Err(CommandParseError::UnknownArg(key)));
148149
}
149-
CommandPart::KeyValue { key, value } => {
150-
if *key == "parent" {
150+
CommandPart::KeyValue { key, value } => match *key {
151+
"parent" => {
151152
parent = if *value == "last" {
152153
Some(Parent::Last)
153154
} else {
@@ -160,13 +161,30 @@ fn parser_try<'a>(command: &'a str, parts: &[CommandPart<'a>]) -> ParseResult<'a
160161
}
161162
}
162163
}
163-
} else {
164+
}
165+
"jobs" => {
166+
let raw_jobs: Vec<_> = value.split(',').map(|s| s.to_string()).collect();
167+
if raw_jobs.is_empty() {
168+
return Some(Err(CommandParseError::ValidationError(format!(
169+
"Try jobs must not be empty"
170+
))));
171+
}
172+
173+
// rust ci currently allows specifying 10 jobs max
174+
if raw_jobs.len() > 10 {
175+
return Some(Err(CommandParseError::ValidationError(format!(
176+
"Try jobs must not have more than 10 jobs"
177+
))));
178+
}
179+
jobs = Some(raw_jobs);
180+
}
181+
_ => {
164182
return Some(Err(CommandParseError::UnknownArg(key)));
165183
}
166-
}
184+
},
167185
}
168186
}
169-
Some(Ok(BorsCommand::Try { parent }))
187+
Some(Ok(BorsCommand::Try { parent, jobs }))
170188
}
171189

172190
/// Parses "@bors try cancel".
@@ -262,14 +280,26 @@ line two
262280
"#,
263281
);
264282
assert_eq!(cmds.len(), 1);
265-
assert!(matches!(cmds[0], Ok(BorsCommand::Try { parent: None })));
283+
assert!(matches!(
284+
cmds[0],
285+
Ok(BorsCommand::Try {
286+
parent: None,
287+
jobs: None
288+
})
289+
));
266290
}
267291

268292
#[test]
269293
fn parse_try() {
270294
let cmds = parse_commands("@bors try");
271295
assert_eq!(cmds.len(), 1);
272-
assert!(matches!(cmds[0], Ok(BorsCommand::Try { parent: None })));
296+
assert!(matches!(
297+
cmds[0],
298+
Ok(BorsCommand::Try {
299+
parent: None,
300+
jobs: None
301+
})
302+
));
273303
}
274304

275305
#[test]
@@ -281,7 +311,8 @@ line two
281311
Ok(BorsCommand::Try {
282312
parent: Some(Parent::CommitSha(CommitSha(
283313
"ea9c1b050cc8b420c2c211d2177811e564a4dc60".to_string()
284-
)))
314+
))),
315+
jobs: None
285316
})
286317
);
287318
}
@@ -293,7 +324,8 @@ line two
293324
assert_eq!(
294325
cmds[0],
295326
Ok(BorsCommand::Try {
296-
parent: Some(Parent::Last)
327+
parent: Some(Parent::Last),
328+
jobs: None
297329
})
298330
);
299331
}
@@ -311,6 +343,46 @@ line two
311343
"###);
312344
}
313345

346+
#[test]
347+
fn parse_try_jobs() {
348+
let cmds = parse_commands("@bors try jobs=ci,lint");
349+
assert_eq!(cmds.len(), 1);
350+
assert_eq!(
351+
cmds[0],
352+
Ok(BorsCommand::Try {
353+
parent: None,
354+
jobs: Some(vec!["ci".to_string(), "lint".to_string()])
355+
})
356+
);
357+
}
358+
359+
#[test]
360+
fn parse_try_jobs_empty() {
361+
let cmds = parse_commands("@bors try jobs=");
362+
assert_eq!(cmds.len(), 1);
363+
insta::assert_debug_snapshot!(cmds[0], @r###"
364+
Err(
365+
MissingArgValue {
366+
arg: "jobs",
367+
},
368+
)
369+
"###);
370+
}
371+
372+
#[test]
373+
fn parse_try_jobs_too_many() {
374+
let cmds =
375+
parse_commands("@bors try jobs=ci,lint,foo,bar,baz,qux,quux,corge,grault,garply,waldo");
376+
assert_eq!(cmds.len(), 1);
377+
insta::assert_debug_snapshot!(cmds[0], @r###"
378+
Err(
379+
ValidationError(
380+
"Try jobs must not have more than 10 jobs",
381+
),
382+
)
383+
"###);
384+
}
385+
314386
#[test]
315387
fn parse_try_unknown_arg() {
316388
let cmds = parse_commands("@bors try a");
@@ -333,7 +405,13 @@ line two
333405
"#,
334406
);
335407
assert_eq!(cmds.len(), 1);
336-
assert!(matches!(cmds[0], Ok(BorsCommand::Try { parent: None })));
408+
assert!(matches!(
409+
cmds[0],
410+
Ok(BorsCommand::Try {
411+
parent: None,
412+
jobs: None
413+
})
414+
));
337415
}
338416

339417
#[test]

src/bors/handlers/mod.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -207,11 +207,18 @@ async fn handle_comment<Client: RepositoryClient>(
207207
let span = tracing::info_span!("Ping");
208208
command_ping(repo, &pull_request).instrument(span).await
209209
}
210-
BorsCommand::Try { parent } => {
210+
BorsCommand::Try { parent, jobs } => {
211211
let span = tracing::info_span!("Try");
212-
command_try_build(repo, database, &pull_request, &comment.author, parent)
213-
.instrument(span)
214-
.await
212+
command_try_build(
213+
repo,
214+
database,
215+
&pull_request,
216+
&comment.author,
217+
parent,
218+
jobs,
219+
)
220+
.instrument(span)
221+
.await
215222
}
216223
BorsCommand::TryCancel => {
217224
let span = tracing::info_span!("Cancel try");

src/bors/handlers/trybuild.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub(super) async fn command_try_build<Client: RepositoryClient>(
3636
pr: &PullRequest,
3737
author: &GithubUser,
3838
parent: Option<Parent>,
39+
jobs: Option<Vec<String>>,
3940
) -> anyhow::Result<()> {
4041
let repo = repo.as_ref();
4142
if !check_try_permissions(repo, pr, author).await? {
@@ -94,7 +95,7 @@ pub(super) async fn command_try_build<Client: RepositoryClient>(
9495
.merge_branches(
9596
TRY_MERGE_BRANCH_NAME,
9697
&pr.head.sha,
97-
&auto_merge_commit_message(pr, "<try>"),
98+
&auto_merge_commit_message(pr, "<try>", jobs),
9899
)
99100
.await
100101
{
@@ -232,17 +233,27 @@ fn get_pending_build(pr: PullRequestModel) -> Option<BuildModel> {
232233
.and_then(|b| (b.status == BuildStatus::Pending).then_some(b))
233234
}
234235

235-
fn auto_merge_commit_message(pr: &PullRequest, reviewer: &str) -> String {
236+
fn auto_merge_commit_message(
237+
pr: &PullRequest,
238+
reviewer: &str,
239+
jobs: Option<Vec<String>>,
240+
) -> String {
236241
let pr_number = pr.number;
237-
format!(
242+
let mut message = format!(
238243
r#"Auto merge of #{pr_number} - {pr_label}, r={reviewer}
239244
{pr_title}
240245
241246
{pr_message}"#,
242247
pr_label = pr.head_label,
243248
pr_title = pr.title,
244249
pr_message = pr.message
245-
)
250+
);
251+
if let Some(jobs) = jobs {
252+
for job in jobs {
253+
message.push_str(&format!("\nci-job: {}", job));
254+
}
255+
}
256+
message
246257
}
247258

248259
fn merge_conflict_message(branch: &str) -> String {

0 commit comments

Comments
 (0)