summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2021-04-22 10:34:34 +0200
committerMatthias Beyer <mail@beyermatthias.de>2021-04-22 10:34:34 +0200
commitd86d6ff045725bb313ca68652f76ec7f1f82714f (patch)
tree690911ed45a22d93d51bdfb5c9d16f2d43422789
parentdfeb8312ebf34479ccb82faae116ed242d372f86 (diff)
parentf6229edd41292e19d8c18a81a86542741260e938 (diff)
Merge branch 'subcommand-submit'
-rw-r--r--src/cli.rs13
-rw-r--r--src/commands/db.rs81
-rw-r--r--src/db/models/endpoint.rs12
-rw-r--r--src/db/models/image.rs12
-rw-r--r--src/db/models/package.rs12
5 files changed, 128 insertions, 2 deletions
diff --git a/src/cli.rs b/src/cli.rs
index 6e69361..aeaa2b5 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -152,6 +152,19 @@ pub fn cli<'a>() -> App<'a> {
)
)
+ .subcommand(App::new("submit")
+ .version(crate_version!())
+ .about("Show details about one specific submit")
+ .arg(Arg::new("submit")
+ .required(true)
+ .multiple(false)
+ .index(1)
+ .takes_value(true)
+ .value_name("SUBMIT")
+ .about("The Submit to show details about")
+ )
+ )
+
.subcommand(App::new("submits")
.version(crate_version!())
.about("List submits from the DB")
diff --git a/src/commands/db.rs b/src/commands/db.rs
index ba66c14..0481ab1 100644
--- a/src/commands/db.rs
+++ b/src/commands/db.rs
@@ -46,6 +46,7 @@ pub fn db(
Some(("artifacts", matches)) => artifacts(db_connection_config, matches),
Some(("envvars", matches)) => envvars(db_connection_config, matches),
Some(("images", matches)) => images(db_connection_config, matches),
+ Some(("submit", matches)) => submit(db_connection_config, matches),
Some(("submits", matches)) => submits(db_connection_config, matches),
Some(("jobs", matches)) => jobs(db_connection_config, matches),
Some(("job", matches)) => job(db_connection_config, config, matches),
@@ -229,6 +230,76 @@ fn images(conn_cfg: DbConnectionConfig, matches: &ArgMatches) -> Result<()> {
Ok(())
}
+fn submit(conn_cfg: DbConnectionConfig, matches: &ArgMatches) -> Result<()> {
+ let conn = crate::db::establish_connection(conn_cfg)?;
+ let submit_id = matches.value_of("submit")
+ .map(uuid::Uuid::from_str)
+ .transpose()
+ .context("Parsing submit UUID")?
+ .unwrap(); // safe by clap
+
+ let submit = models::Submit::with_id(&conn, &submit_id)
+ .with_context(|| anyhow!("Loading submit '{}' from DB", submit_id))?;
+
+ let jobs = schema::submits::table
+ .inner_join(schema::jobs::table)
+ .filter(schema::submits::uuid.eq(&submit_id))
+ .select(schema::jobs::all_columns)
+ .load::<models::Job>(&conn)
+ .with_context(|| anyhow!("Loading jobs for submit = {}", submit_id))?;
+
+ let n_jobs = jobs.len();
+ let (jobs_success, jobs_err) = {
+ let s = jobs.iter().map(is_job_successful).fold(Ok(0), |acc, e| acc.and_then(|a| e.map(|_| a + 1)))?;
+ (s, n_jobs - s)
+ };
+
+ let out = std::io::stdout();
+ let mut outlock = out.lock();
+
+ indoc::writedoc!(outlock, r#"
+ Submit {submit_id}
+ Date: {submit_dt}
+ Jobs: {n_jobs}
+ Success: {n_jobs_success}
+ Errored: {n_jobs_err}
+
+ "#,
+ submit_id = submit.uuid.to_string().cyan(),
+ submit_dt = submit.submit_time.to_string().cyan(),
+ n_jobs = n_jobs.to_string().cyan(),
+ n_jobs_success = jobs_success.to_string().green(),
+ n_jobs_err = jobs_err.to_string().red(),
+ )?;
+
+ let header = crate::commands::util::mk_header(["Job", "Success", "Package", "Version", "Endpoint", "Container", "Image"].to_vec());
+ let data = jobs.iter()
+ .map(|job| {
+ let image = models::Image::fetch_for_job(&conn, job)?
+ .ok_or_else(|| anyhow!("Image for job {} not found", job.uuid))?;
+ let package = models::Package::fetch_for_job(&conn, job)?
+ .ok_or_else(|| anyhow!("Package for job {} not found", job.uuid))?;
+ let endpoint = models::Endpoint::fetch_for_job(&conn, job)?
+ .ok_or_else(|| anyhow!("Endpoint for job {} not found", job.uuid))?;
+
+ Ok(vec![
+ job.uuid.to_string().cyan(),
+ match is_job_successful(job)? {
+ Some(true) => "Success".green(),
+ Some(false) => "Error".red(),
+ None => "Unknown".yellow(),
+ },
+ package.name.cyan(),
+ package.version.cyan(),
+ job.container_hash.normal(),
+ endpoint.name.normal(),
+ image.name.normal(),
+ ])
+ })
+ .collect::<Result<Vec<Vec<colored::ColoredString>>>>()?;
+ crate::commands::util::display_data(header, data, false)
+}
+
fn submits(conn_cfg: DbConnectionConfig, matches: &ArgMatches) -> Result<()> {
let csv = matches.is_present("csv");
let hdrs = crate::commands::util::mk_header(vec!["id", "time", "uuid"]);
@@ -355,8 +426,7 @@ fn jobs(conn_cfg: DbConnectionConfig, matches: &ArgMatches) -> Result<()> {
.into_iter()
.rev() // required for the --limit implementation
.map(|(job, submit, ep, package)| {
- let success = crate::log::ParsedLog::build_from(&job.log_text)?
- .is_successfull()
+ let success = is_job_successful(&job)?
.map(|b| if b { "yes" } else { "no" })
.map(String::from)
.unwrap_or_else(|| String::from("unknown"));
@@ -602,3 +672,10 @@ fn releases(conn_cfg: DbConnectionConfig, config: &Configuration, matches: &ArgM
crate::commands::util::display_data(header, data, csv)
}
+/// Check if a job is successful
+///
+/// Returns Ok(None) if cannot be decided
+fn is_job_successful(job: &models::Job) -> Result<Option<bool>> {
+ crate::log::ParsedLog::build_from(&job.log_text).map(|pl| pl.is_successfull())
+}
+
diff --git a/src/db/models/endpoint.rs b/src/db/models/endpoint.rs
index d7a7986..3909b2b 100644
--- a/src/db/models/endpoint.rs
+++ b/src/db/models/endpoint.rs
@@ -43,4 +43,16 @@ impl Endpoint {
.first::<Endpoint>(database_connection)
.map_err(Error::from)
}
+
+ pub fn fetch_for_job(database_connection: &PgConnection, j: &crate::db::models::Job) -> Result<Option<Endpoint>> {
+ Self::fetch_by_id(database_connection, j.endpoint_id)
+ }
+
+ pub fn fetch_by_id(database_connection: &PgConnection, eid: i32) -> Result<Option<Endpoint>> {
+ match dsl::endpoints.filter(id.eq(eid)).first::<Endpoint>(database_connection) {
+ Err(diesel::result::Error::NotFound) => Ok(None),
+ Err(e) => Err(Error::from(e)),
+ Ok(e) => Ok(Some(e)),
+ }
+ }
}
diff --git a/src/db/models/image.rs b/src/db/models/image.rs
index 2570dc2..600edd6 100644
--- a/src/db/models/image.rs
+++ b/src/db/models/image.rs
@@ -48,4 +48,16 @@ impl Image {
.first::<Image>(database_connection)
.map_err(Error::from)
}
+
+ pub fn fetch_for_job(database_connection: &PgConnection, j: &crate::db::models::Job) -> Result<Option<Image>> {
+ Self::fetch_by_id(database_connection, j.image_id)
+ }
+
+ pub fn fetch_by_id(database_connection: &PgConnection, iid: i32) -> Result<Option<Image>> {
+ match dsl::images.filter(id.eq(iid)).first::<Image>(database_connection) {
+ Err(diesel::result::Error::NotFound) => Ok(None),
+ Err(e) => Err(Error::from(e)),
+ Ok(i) => Ok(Some(i)),
+ }
+ }
}
diff --git a/src/db/models/package.rs b/src/db/models/package.rs
index 6a5b646..88839b6 100644
--- a/src/db/models/package.rs
+++ b/src/db/models/package.rs
@@ -57,4 +57,16 @@ impl Package {
.first::<Package>(database_connection)
.map_err(Error::from)
}
+
+ pub fn fetch_for_job(database_connection: &PgConnection, j: &crate::db::models::Job) -> Result<Option<Package>> {
+ Self::fetch_by_id(database_connection, j.package_id)
+ }
+
+ pub fn fetch_by_id(database_connection: &PgConnection, pid: i32) -> Result<Option<Package>> {
+ match dsl::packages.filter(id.eq(pid)).first::<Package>(database_connection) {
+ Err(diesel::result::Error::NotFound) => Ok(None),
+ Err(e) => Err(Error::from(e)),
+ Ok(p) => Ok(Some(p)),
+ }
+ }
}