Skip to content

Commit 3eb41f1

Browse files
authored
Merge pull request #85 from vohoanglong0107/feat-arbitrary-try-build
feat: arbitrary try build
2 parents a5471ae + 1bbc04d commit 3eb41f1

File tree

4 files changed

+116
-19
lines changed

4 files changed

+116
-19
lines changed

src/bors/command/mod.rs

+2
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: Vec<String>,
2527
},
2628
/// Cancel a try build.
2729
TryCancel,

src/bors/command/parser.rs

+92-11
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 = Vec::new();
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,18 +161,35 @@ 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(
169+
"Try jobs must not be empty".to_string(),
170+
)));
171+
}
172+
173+
// rust ci currently allows specifying 10 jobs max
174+
if raw_jobs.len() > 10 {
175+
return Some(Err(CommandParseError::ValidationError(
176+
"Try jobs must not have more than 10 jobs".to_string(),
177+
)));
178+
}
179+
jobs = 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".
173191
fn parser_try_cancel<'a>(command: &'a str, parts: &[CommandPart<'a>]) -> ParseResult<'a> {
174-
if command == "try" && parts.get(0) == Some(&CommandPart::Bare("cancel")) {
192+
if command == "try" && parts.first() == Some(&CommandPart::Bare("cancel")) {
175193
Some(Ok(BorsCommand::TryCancel))
176194
} else {
177195
None
@@ -262,14 +280,28 @@ line two
262280
"#,
263281
);
264282
assert_eq!(cmds.len(), 1);
265-
assert!(matches!(cmds[0], Ok(BorsCommand::Try { parent: None })));
283+
insta::assert_debug_snapshot!(cmds[0], @r###"
284+
Ok(
285+
Try {
286+
parent: None,
287+
jobs: [],
288+
},
289+
)
290+
"###);
266291
}
267292

268293
#[test]
269294
fn parse_try() {
270295
let cmds = parse_commands("@bors try");
271296
assert_eq!(cmds.len(), 1);
272-
assert!(matches!(cmds[0], Ok(BorsCommand::Try { parent: None })));
297+
insta::assert_debug_snapshot!(cmds[0], @r###"
298+
Ok(
299+
Try {
300+
parent: None,
301+
jobs: [],
302+
},
303+
)
304+
"###);
273305
}
274306

275307
#[test]
@@ -281,7 +313,8 @@ line two
281313
Ok(BorsCommand::Try {
282314
parent: Some(Parent::CommitSha(CommitSha(
283315
"ea9c1b050cc8b420c2c211d2177811e564a4dc60".to_string()
284-
)))
316+
))),
317+
jobs: Vec::new()
285318
})
286319
);
287320
}
@@ -293,7 +326,8 @@ line two
293326
assert_eq!(
294327
cmds[0],
295328
Ok(BorsCommand::Try {
296-
parent: Some(Parent::Last)
329+
parent: Some(Parent::Last),
330+
jobs: Vec::new()
297331
})
298332
);
299333
}
@@ -311,6 +345,46 @@ line two
311345
"###);
312346
}
313347

348+
#[test]
349+
fn parse_try_jobs() {
350+
let cmds = parse_commands("@bors try jobs=ci,lint");
351+
assert_eq!(cmds.len(), 1);
352+
assert_eq!(
353+
cmds[0],
354+
Ok(BorsCommand::Try {
355+
parent: None,
356+
jobs: vec!["ci".to_string(), "lint".to_string()]
357+
})
358+
);
359+
}
360+
361+
#[test]
362+
fn parse_try_jobs_empty() {
363+
let cmds = parse_commands("@bors try jobs=");
364+
assert_eq!(cmds.len(), 1);
365+
insta::assert_debug_snapshot!(cmds[0], @r###"
366+
Err(
367+
MissingArgValue {
368+
arg: "jobs",
369+
},
370+
)
371+
"###);
372+
}
373+
374+
#[test]
375+
fn parse_try_jobs_too_many() {
376+
let cmds =
377+
parse_commands("@bors try jobs=ci,lint,foo,bar,baz,qux,quux,corge,grault,garply,waldo");
378+
assert_eq!(cmds.len(), 1);
379+
insta::assert_debug_snapshot!(cmds[0], @r###"
380+
Err(
381+
ValidationError(
382+
"Try jobs must not have more than 10 jobs",
383+
),
384+
)
385+
"###);
386+
}
387+
314388
#[test]
315389
fn parse_try_unknown_arg() {
316390
let cmds = parse_commands("@bors try a");
@@ -333,7 +407,14 @@ line two
333407
"#,
334408
);
335409
assert_eq!(cmds.len(), 1);
336-
assert!(matches!(cmds[0], Ok(BorsCommand::Try { parent: None })));
410+
insta::assert_debug_snapshot!(cmds[0], @r###"
411+
Ok(
412+
Try {
413+
parent: None,
414+
jobs: [],
415+
},
416+
)
417+
"###)
337418
}
338419

339420
#[test]

src/bors/handlers/mod.rs

+11-4
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

+11-4
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: 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,23 @@ 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(pr: &PullRequest, reviewer: &str, jobs: Vec<String>) -> String {
236237
let pr_number = pr.number;
237-
format!(
238+
let mut message = format!(
238239
r#"Auto merge of #{pr_number} - {pr_label}, r={reviewer}
239240
{pr_title}
240241
241242
{pr_message}"#,
242243
pr_label = pr.head_label,
243244
pr_title = pr.title,
244245
pr_message = pr.message
245-
)
246+
);
247+
248+
// if jobs is empty, try-job won't be added to the message
249+
for job in jobs {
250+
message.push_str(&format!("\ntry-job: {}", job));
251+
}
252+
message
246253
}
247254

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

0 commit comments

Comments
 (0)