1
- use crate :: { GitHubContext , utils } ;
1
+ use crate :: GitHubContext ;
2
2
use serde_yaml:: Value ;
3
3
use std:: collections:: BTreeMap ;
4
- use std:: path:: Path ;
5
4
6
5
/// Representation of a job loaded from the `src/ci/github-actions/jobs.yml` file.
7
6
#[ derive( serde:: Deserialize , Debug , Clone ) ]
@@ -61,13 +60,19 @@ pub struct JobDatabase {
61
60
}
62
61
63
62
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 ( )
66
72
}
67
73
}
68
74
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 > {
71
76
let mut db: Value = serde_yaml:: from_str ( & db) ?;
72
77
73
78
// We need to expand merge keys (<<), because serde_yaml can't deal with them
@@ -110,7 +115,7 @@ pub enum RunType {
110
115
/// Workflows that run after a push to a PR branch
111
116
PullRequest ,
112
117
/// Try run started with @bors try
113
- TryJob { custom_jobs : Option < Vec < String > > } ,
118
+ TryJob { job_patterns : Option < Vec < String > > } ,
114
119
/// Merge attempt workflow
115
120
AutoJob ,
116
121
}
@@ -126,28 +131,29 @@ fn calculate_jobs(
126
131
) -> anyhow:: Result < Vec < GithubActionsJob > > {
127
132
let ( jobs, prefix, base_env) = match run_type {
128
133
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 {
138
136
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 ( ) ) ;
143
142
} else {
144
- unknown_jobs . push ( custom_job . clone ( ) ) ;
143
+ jobs . extend ( matched_jobs ) ;
145
144
}
146
145
}
147
- if !unknown_jobs . is_empty ( ) {
146
+ if !unknown_patterns . is_empty ( ) {
148
147
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( )
151
157
) ) ;
152
158
}
153
159
jobs
@@ -227,3 +233,75 @@ pub fn find_linux_job<'a>(jobs: &'a [Job], name: &str) -> anyhow::Result<&'a Job
227
233
228
234
Ok ( job)
229
235
}
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