Skip to content

Commit 8ef62fc

Browse files
committed
Allow using glob aliases for custom try jobs
1 parent 9241be8 commit 8ef62fc

File tree

4 files changed

+121
-32
lines changed

4 files changed

+121
-32
lines changed

Diff for: src/ci/citool/Cargo.lock

+7
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"

Diff for: src/ci/citool/Cargo.toml

+1
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"

Diff for: src/ci/citool/src/jobs.rs

+102-24
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
use crate::{GitHubContext, utils};
1+
use crate::GitHubContext;
22
use serde_yaml::Value;
33
use std::collections::BTreeMap;
4-
use std::path::Path;
54

65
/// Representation of a job loaded from the `src/ci/github-actions/jobs.yml` file.
76
#[derive(serde::Deserialize, Debug, Clone)]
@@ -61,13 +60,19 @@ pub struct JobDatabase {
6160
}
6261

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

69-
pub fn load_job_db(path: &Path) -> anyhow::Result<JobDatabase> {
70-
let db = utils::read_to_string(path)?;
75+
pub fn load_job_db(db: &str) -> anyhow::Result<JobDatabase> {
7176
let mut db: Value = serde_yaml::from_str(&db)?;
7277

7378
// We need to expand merge keys (<<), because serde_yaml can't deal with them
@@ -110,7 +115,7 @@ pub enum RunType {
110115
/// Workflows that run after a push to a PR branch
111116
PullRequest,
112117
/// Try run started with @bors try
113-
TryJob { custom_jobs: Option<Vec<String>> },
118+
TryJob { job_patterns: Option<Vec<String>> },
114119
/// Merge attempt workflow
115120
AutoJob,
116121
}
@@ -126,28 +131,29 @@ fn calculate_jobs(
126131
) -> anyhow::Result<Vec<GithubActionsJob>> {
127132
let (jobs, prefix, base_env) = match run_type {
128133
RunType::PullRequest => (db.pr_jobs.clone(), "PR", &db.envs.pr_env),
129-
RunType::TryJob { custom_jobs } => {
130-
let jobs = if let Some(custom_jobs) = custom_jobs {
131-
if custom_jobs.len() > MAX_TRY_JOBS_COUNT {
132-
return Err(anyhow::anyhow!(
133-
"It is only possible to schedule up to {MAX_TRY_JOBS_COUNT} custom jobs, received {} custom jobs",
134-
custom_jobs.len()
135-
));
136-
}
137-
134+
RunType::TryJob { job_patterns } => {
135+
let jobs = if let Some(patterns) = job_patterns {
138136
let mut jobs = vec![];
139-
let mut unknown_jobs = vec![];
140-
for custom_job in custom_jobs {
141-
if let Some(job) = db.find_auto_job_by_name(custom_job) {
142-
jobs.push(job);
137+
let mut unknown_patterns = vec![];
138+
for pattern in patterns {
139+
let matched_jobs = db.find_auto_jobs_by_patter(pattern);
140+
if matched_jobs.is_empty() {
141+
unknown_patterns.push(pattern.clone());
143142
} else {
144-
unknown_jobs.push(custom_job.clone());
143+
jobs.extend(matched_jobs);
145144
}
146145
}
147-
if !unknown_jobs.is_empty() {
146+
if !unknown_patterns.is_empty() {
148147
return Err(anyhow::anyhow!(
149-
"Custom job(s) `{}` not found in auto jobs",
150-
unknown_jobs.join(", ")
148+
"Patterns `{}` did not match any auto jobs",
149+
unknown_patterns.join(", ")
150+
));
151+
}
152+
if jobs.len() > MAX_TRY_JOBS_COUNT {
153+
return Err(anyhow::anyhow!(
154+
"It is only possible to schedule up to {MAX_TRY_JOBS_COUNT} custom jobs, received {} custom jobs expanded from {} pattern(s)",
155+
jobs.len(),
156+
job_patterns.len()
151157
));
152158
}
153159
jobs
@@ -227,3 +233,75 @@ pub fn find_linux_job<'a>(jobs: &'a [Job], name: &str) -> anyhow::Result<&'a Job
227233

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

Diff for: src/ci/citool/src/main.rs

+11-8
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,21 @@ impl GitHubContext {
3434
fn get_run_type(&self) -> Option<RunType> {
3535
match (self.event_name.as_str(), self.branch_ref.as_str()) {
3636
("pull_request", _) => Some(RunType::PullRequest),
37-
("push", "refs/heads/try-perf") => Some(RunType::TryJob { custom_jobs: None }),
37+
("push", "refs/heads/try-perf") => Some(RunType::TryJob { job_patterns: None }),
3838
("push", "refs/heads/try" | "refs/heads/automation/bors/try") => {
39-
let custom_jobs = self.get_custom_jobs();
40-
let custom_jobs = if !custom_jobs.is_empty() { Some(custom_jobs) } else { None };
41-
Some(RunType::TryJob { custom_jobs })
39+
let job_aliases = self.get_try_job_aliases();
40+
let job_aliases = if !job_aliases.is_empty() { Some(job_aliases) } else { None };
41+
Some(RunType::TryJob { job_patterns: job_aliases })
4242
}
4343
("push", "refs/heads/auto") => Some(RunType::AutoJob),
4444
_ => None,
4545
}
4646
}
4747

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

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

0 commit comments

Comments
 (0)