1- use crate :: { GitHubContext , utils } ;
1+ use crate :: GitHubContext ;
22use serde_yaml:: Value ;
33use 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
6362impl 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+ }
0 commit comments