Skip to content

Commit bea5911

Browse files
committed
Allow using glob aliases for custom try jobs
1 parent 0412507 commit bea5911

File tree

4 files changed

+120
-33
lines changed

4 files changed

+120
-33
lines changed

src/ci/citool/Cargo.lock

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ dependencies = [
107107
"build_helper",
108108
"clap",
109109
"csv",
110+
"glob-match",
110111
"insta",
111112
"serde",
112113
"serde_json",
@@ -308,6 +309,12 @@ dependencies = [
308309
"wasi",
309310
]
310311

312+
[[package]]
313+
name = "glob-match"
314+
version = "0.2.1"
315+
source = "registry+https://github.com/rust-lang/crates.io-index"
316+
checksum = "9985c9503b412198aa4197559e9a318524ebc4519c229bfa05a535828c950b9d"
317+
311318
[[package]]
312319
name = "hashbrown"
313320
version = "0.15.2"

src/ci/citool/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ edition = "2021"
77
anyhow = "1"
88
clap = { version = "4.5", features = ["derive"] }
99
csv = "1"
10+
glob-match = "0.2"
1011
serde = { version = "1", features = ["derive"] }
1112
serde_yaml = "0.9"
1213
serde_json = "1"

src/ci/citool/src/jobs.rs

Lines changed: 101 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
use crate::{GitHubContext, utils};
2-
use serde_yaml::Value;
31
use std::collections::BTreeMap;
4-
use std::path::Path;
52

63
use serde_yaml::Value;
74

@@ -65,13 +62,19 @@ pub struct JobDatabase {
6562
}
6663

6764
impl JobDatabase {
68-
fn find_auto_job_by_name(&self, name: &str) -> Option<Job> {
69-
self.auto_jobs.iter().find(|j| j.name == name).cloned()
65+
/// Find `auto` jobs that correspond to the passed `pattern`.
66+
/// Patterns are matched using the glob syntax.
67+
/// For example `dist-*` matches all jobs starting with `dist-`.
68+
fn find_auto_jobs_by_patter(&self, pattern: &str) -> Vec<Job> {
69+
self.auto_jobs
70+
.iter()
71+
.filter(|j| glob_match::glob_match(pattern, &j.name))
72+
.cloned()
73+
.collect()
7074
}
7175
}
7276

73-
pub fn load_job_db(path: &Path) -> anyhow::Result<JobDatabase> {
74-
let db = utils::read_to_string(path)?;
77+
pub fn load_job_db(db: &str) -> anyhow::Result<JobDatabase> {
7578
let mut db: Value = serde_yaml::from_str(&db)?;
7679

7780
// We need to expand merge keys (<<), because serde_yaml can't deal with them
@@ -114,7 +117,7 @@ pub enum RunType {
114117
/// Workflows that run after a push to a PR branch
115118
PullRequest,
116119
/// Try run started with @bors try
117-
TryJob { custom_jobs: Option<Vec<String>> },
120+
TryJob { job_patterns: Option<Vec<String>> },
118121
/// Merge attempt workflow
119122
AutoJob,
120123
}
@@ -130,28 +133,29 @@ fn calculate_jobs(
130133
) -> anyhow::Result<Vec<GithubActionsJob>> {
131134
let (jobs, prefix, base_env) = match run_type {
132135
RunType::PullRequest => (db.pr_jobs.clone(), "PR", &db.envs.pr_env),
133-
RunType::TryJob { custom_jobs } => {
134-
let jobs = if let Some(custom_jobs) = custom_jobs {
135-
if custom_jobs.len() > MAX_TRY_JOBS_COUNT {
136-
return Err(anyhow::anyhow!(
137-
"It is only possible to schedule up to {MAX_TRY_JOBS_COUNT} custom jobs, received {} custom jobs",
138-
custom_jobs.len()
139-
));
140-
}
141-
136+
RunType::TryJob { job_patterns } => {
137+
let jobs = if let Some(patterns) = job_patterns {
142138
let mut jobs = vec![];
143-
let mut unknown_jobs = vec![];
144-
for custom_job in custom_jobs {
145-
if let Some(job) = db.find_auto_job_by_name(custom_job) {
146-
jobs.push(job);
139+
let mut unknown_patterns = vec![];
140+
for pattern in patterns {
141+
let matched_jobs = db.find_auto_jobs_by_patter(pattern);
142+
if matched_jobs.is_empty() {
143+
unknown_patterns.push(pattern.clone());
147144
} else {
148-
unknown_jobs.push(custom_job.clone());
145+
jobs.extend(matched_jobs);
149146
}
150147
}
151-
if !unknown_jobs.is_empty() {
148+
if !unknown_patterns.is_empty() {
149+
return Err(anyhow::anyhow!(
150+
"Patterns `{}` did not match any auto jobs",
151+
unknown_patterns.join(", ")
152+
));
153+
}
154+
if jobs.len() > MAX_TRY_JOBS_COUNT {
152155
return Err(anyhow::anyhow!(
153-
"Custom job(s) `{}` not found in auto jobs",
154-
unknown_jobs.join(", ")
156+
"It is only possible to schedule up to {MAX_TRY_JOBS_COUNT} custom jobs, received {} custom jobs expanded from {} pattern(s)",
157+
jobs.len(),
158+
patterns.len()
155159
));
156160
}
157161
jobs
@@ -231,3 +235,75 @@ pub fn find_linux_job<'a>(jobs: &'a [Job], name: &str) -> anyhow::Result<&'a Job
231235

232236
Ok(job)
233237
}
238+
239+
#[cfg(test)]
240+
mod tests {
241+
use crate::jobs::{JobDatabase, load_job_db};
242+
243+
#[test]
244+
fn lookup_job_pattern() {
245+
let db = load_job_db(
246+
r#"
247+
envs:
248+
pr:
249+
try:
250+
auto:
251+
252+
pr:
253+
try:
254+
auto:
255+
- name: dist-a
256+
os: ubuntu
257+
env: {}
258+
- name: dist-a-alt
259+
os: ubuntu
260+
env: {}
261+
- name: dist-b
262+
os: ubuntu
263+
env: {}
264+
- name: dist-b-alt
265+
os: ubuntu
266+
env: {}
267+
- name: test-a
268+
os: ubuntu
269+
env: {}
270+
- name: test-a-alt
271+
os: ubuntu
272+
env: {}
273+
- name: test-i686
274+
os: ubuntu
275+
env: {}
276+
- name: dist-i686
277+
os: ubuntu
278+
env: {}
279+
- name: test-msvc-i686-1
280+
os: ubuntu
281+
env: {}
282+
- name: test-msvc-i686-2
283+
os: ubuntu
284+
env: {}
285+
"#,
286+
)
287+
.unwrap();
288+
check_pattern(
289+
&db,
290+
"dist-*",
291+
&["dist-a", "dist-a-alt", "dist-b", "dist-b-alt", "dist-i686"],
292+
);
293+
check_pattern(&db, "*-alt", &["dist-a-alt", "dist-b-alt", "test-a-alt"]);
294+
check_pattern(&db, "dist*-alt", &["dist-a-alt", "dist-b-alt"]);
295+
check_pattern(
296+
&db,
297+
"*i686*",
298+
&["test-i686", "dist-i686", "test-msvc-i686-1", "test-msvc-i686-2"],
299+
);
300+
}
301+
302+
#[track_caller]
303+
fn check_pattern(db: &JobDatabase, pattern: &str, expected: &[&str]) {
304+
let jobs =
305+
db.find_auto_jobs_by_patter(pattern).into_iter().map(|j| j.name).collect::<Vec<_>>();
306+
307+
assert_eq!(jobs, expected);
308+
}
309+
}

src/ci/citool/src/main.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,21 @@ impl GitHubContext {
3535
fn get_run_type(&self) -> Option<RunType> {
3636
match (self.event_name.as_str(), self.branch_ref.as_str()) {
3737
("pull_request", _) => Some(RunType::PullRequest),
38-
("push", "refs/heads/try-perf") => Some(RunType::TryJob { custom_jobs: None }),
38+
("push", "refs/heads/try-perf") => Some(RunType::TryJob { job_patterns: None }),
3939
("push", "refs/heads/try" | "refs/heads/automation/bors/try") => {
40-
let custom_jobs = self.get_custom_jobs();
41-
let custom_jobs = if !custom_jobs.is_empty() { Some(custom_jobs) } else { None };
42-
Some(RunType::TryJob { custom_jobs })
40+
let patterns = self.get_try_job_patterns();
41+
let patterns = if !patterns.is_empty() { Some(patterns) } else { None };
42+
Some(RunType::TryJob { job_patterns: patterns })
4343
}
4444
("push", "refs/heads/auto") => Some(RunType::AutoJob),
4545
_ => None,
4646
}
4747
}
4848

49-
/// Tries to parse names of specific CI jobs that should be executed in the form of
50-
/// try-job: <job-name>
49+
/// Tries to parse patterns of CI jobs that should be executed in the form of
50+
/// try-job: <job-pattern>
5151
/// from the commit message of the passed GitHub context.
52-
fn get_custom_jobs(&self) -> Vec<String> {
52+
fn get_try_job_patterns(&self) -> Vec<String> {
5353
if let Some(ref msg) = self.commit_message {
5454
msg.lines()
5555
.filter_map(|line| line.trim().strip_prefix("try-job: "))
@@ -180,7 +180,10 @@ pub enum JobType {
180180
fn main() -> anyhow::Result<()> {
181181
let args = Args::parse();
182182
let default_jobs_file = Path::new(JOBS_YML_PATH);
183-
let load_db = |jobs_path| jobs::load_job_db(jobs_path).context("Cannot load jobs.yml");
183+
let load_db = |jobs_path| {
184+
let db = utils::read_to_string(jobs_path)?;
185+
Ok::<_, anyhow::Error>(jobs::load_job_db(&db).context("Cannot load jobs.yml")?)
186+
};
184187

185188
match args {
186189
Args::CalculateJobMatrix { jobs_file } => {

0 commit comments

Comments
 (0)