1
+ mod cpu_usage;
2
+ mod datadog;
1
3
mod metrics;
4
+ mod utils;
2
5
3
6
use std:: collections:: BTreeMap ;
4
7
use std:: path:: { Path , PathBuf } ;
@@ -8,6 +11,10 @@ use anyhow::Context;
8
11
use clap:: Parser ;
9
12
use serde_yaml:: Value ;
10
13
14
+ use crate :: cpu_usage:: load_cpu_usage;
15
+ use crate :: datadog:: upload_datadog_metric;
16
+ use crate :: utils:: load_env_var;
17
+
11
18
use crate :: metrics:: postprocess_metrics;
12
19
13
20
const CI_DIRECTORY : & str = concat ! ( env!( "CARGO_MANIFEST_DIR" ) , "/.." ) ;
@@ -75,7 +82,7 @@ impl JobDatabase {
75
82
}
76
83
77
84
fn load_job_db ( path : & Path ) -> anyhow:: Result < JobDatabase > {
78
- let db = read_to_string ( path) ?;
85
+ let db = utils :: read_to_string ( path) ?;
79
86
let mut db: Value = serde_yaml:: from_str ( & db) ?;
80
87
81
88
// We need to expand merge keys (<<), because serde_yaml can't deal with them
@@ -148,10 +155,6 @@ impl GitHubContext {
148
155
}
149
156
}
150
157
151
- fn load_env_var ( name : & str ) -> anyhow:: Result < String > {
152
- std:: env:: var ( name) . with_context ( || format ! ( "Cannot find variable {name}" ) )
153
- }
154
-
155
158
fn load_github_ctx ( ) -> anyhow:: Result < GitHubContext > {
156
159
let event_name = load_env_var ( "GITHUB_EVENT_NAME" ) ?;
157
160
let commit_message =
@@ -325,6 +328,18 @@ fn run_workflow_locally(db: JobDatabase, job_type: JobType, name: String) -> any
325
328
if !result. success ( ) { Err ( anyhow:: anyhow!( "Job failed" ) ) } else { Ok ( ( ) ) }
326
329
}
327
330
331
+ fn upload_ci_metrics ( cpu_usage_csv : & Path ) -> anyhow:: Result < ( ) > {
332
+ let usage = load_cpu_usage ( cpu_usage_csv) . context ( "Cannot load CPU usage from input CSV" ) ?;
333
+ eprintln ! ( "CPU usage\n {usage:?}" ) ;
334
+
335
+ let avg = if !usage. is_empty ( ) { usage. iter ( ) . sum :: < f64 > ( ) / usage. len ( ) as f64 } else { 0.0 } ;
336
+ eprintln ! ( "CPU usage average: {avg}" ) ;
337
+
338
+ upload_datadog_metric ( "avg-cpu-usage" , avg) . context ( "Cannot upload Datadog metric" ) ?;
339
+
340
+ Ok ( ( ) )
341
+ }
342
+
328
343
#[ derive( clap:: Parser ) ]
329
344
enum Args {
330
345
/// Calculate a list of jobs that should be executed on CI.
@@ -350,6 +365,11 @@ enum Args {
350
365
/// Usually, this will be GITHUB_STEP_SUMMARY on CI.
351
366
summary_path : PathBuf ,
352
367
} ,
368
+ /// Upload CI metrics to Datadog.
369
+ UploadBuildMetrics {
370
+ /// Path to a CSV containing the CI job CPU usage.
371
+ cpu_usage_csv : PathBuf ,
372
+ } ,
353
373
}
354
374
355
375
#[ derive( clap:: ValueEnum , Clone ) ]
@@ -370,7 +390,7 @@ fn main() -> anyhow::Result<()> {
370
390
let jobs_path = jobs_file. as_deref ( ) . unwrap_or ( default_jobs_file) ;
371
391
let gh_ctx = load_github_ctx ( )
372
392
. context ( "Cannot load environment variables from GitHub Actions" ) ?;
373
- let channel = read_to_string ( Path :: new ( CI_DIRECTORY ) . join ( "channel" ) )
393
+ let channel = utils :: read_to_string ( Path :: new ( CI_DIRECTORY ) . join ( "channel" ) )
374
394
. context ( "Cannot read channel file" ) ?
375
395
. trim ( )
376
396
. to_string ( ) ;
@@ -379,7 +399,10 @@ fn main() -> anyhow::Result<()> {
379
399
. context ( "Failed to calculate job matrix" ) ?;
380
400
}
381
401
Args :: RunJobLocally { job_type, name } => {
382
- run_workflow_locally ( load_db ( default_jobs_file) ?, job_type, name) ?
402
+ run_workflow_locally ( load_db ( default_jobs_file) ?, job_type, name) ?;
403
+ }
404
+ Args :: UploadBuildMetrics { cpu_usage_csv } => {
405
+ upload_ci_metrics ( & cpu_usage_csv) ?;
383
406
}
384
407
Args :: PostprocessMetrics { metrics_path, summary_path } => {
385
408
postprocess_metrics ( & metrics_path, & summary_path) ?;
@@ -388,8 +411,3 @@ fn main() -> anyhow::Result<()> {
388
411
389
412
Ok ( ( ) )
390
413
}
391
-
392
- fn read_to_string < P : AsRef < Path > > ( path : P ) -> anyhow:: Result < String > {
393
- let error = format ! ( "Cannot read file {:?}" , path. as_ref( ) ) ;
394
- std:: fs:: read_to_string ( path) . context ( error)
395
- }
0 commit comments