diff --git a/.sqlx/query-b2fa2e823f0f8e8fbd288cd0c102ad28a198463534efbefcf06f45c0f49872af.json b/.sqlx/query-3340b2af65824ae339c5721cd79896575c0db5049ec4d2f51181dfd4684d274c.json similarity index 76% rename from .sqlx/query-b2fa2e823f0f8e8fbd288cd0c102ad28a198463534efbefcf06f45c0f49872af.json rename to .sqlx/query-3340b2af65824ae339c5721cd79896575c0db5049ec4d2f51181dfd4684d274c.json index ade9b4eac..aab0d77b9 100644 --- a/.sqlx/query-b2fa2e823f0f8e8fbd288cd0c102ad28a198463534efbefcf06f45c0f49872af.json +++ b/.sqlx/query-3340b2af65824ae339c5721cd79896575c0db5049ec4d2f51181dfd4684d274c.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "UPDATE builds\n SET\n rustc_version = $1,\n docsrs_version = $2,\n build_status = $3,\n build_server = $4,\n errors = $5,\n build_time = NOW()\n WHERE\n id = $6\n RETURNING rid", + "query": "UPDATE builds\n SET\n rustc_version = $1,\n docsrs_version = $2,\n build_status = $3,\n build_server = $4,\n errors = $5,\n rustc_nightly_date = $6,\n build_time = NOW()\n WHERE\n id = $7\n RETURNING rid", "describe": { "columns": [ { @@ -27,6 +27,7 @@ }, "Text", "Text", + "Date", "Int4" ] }, @@ -34,5 +35,5 @@ false ] }, - "hash": "b2fa2e823f0f8e8fbd288cd0c102ad28a198463534efbefcf06f45c0f49872af" + "hash": "3340b2af65824ae339c5721cd79896575c0db5049ec4d2f51181dfd4684d274c" } diff --git a/.sqlx/query-c955871bcda914feac9cfb23fe010399c0b3f75e92ac425fa4ec337e9b250c26.json b/.sqlx/query-c955871bcda914feac9cfb23fe010399c0b3f75e92ac425fa4ec337e9b250c26.json new file mode 100644 index 000000000..61ff84b5f --- /dev/null +++ b/.sqlx/query-c955871bcda914feac9cfb23fe010399c0b3f75e92ac425fa4ec337e9b250c26.json @@ -0,0 +1,57 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT\n rustc_version,\n docsrs_version,\n build_status as \"build_status: BuildStatus\",\n errors,\n rustc_nightly_date\n FROM builds\n WHERE id = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "rustc_version", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "docsrs_version", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "build_status: BuildStatus", + "type_info": { + "Custom": { + "name": "build_status", + "kind": { + "Enum": [ + "in_progress", + "success", + "failure" + ] + } + } + } + }, + { + "ordinal": 3, + "name": "errors", + "type_info": "Text" + }, + { + "ordinal": 4, + "name": "rustc_nightly_date", + "type_info": "Date" + } + ], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [ + true, + true, + false, + true, + true + ] + }, + "hash": "c955871bcda914feac9cfb23fe010399c0b3f75e92ac425fa4ec337e9b250c26" +} diff --git a/migrations/20241018052241_builds-rustc-nightly-date.down.sql b/migrations/20241018052241_builds-rustc-nightly-date.down.sql new file mode 100644 index 000000000..1214744df --- /dev/null +++ b/migrations/20241018052241_builds-rustc-nightly-date.down.sql @@ -0,0 +1,4 @@ +DROP INDEX builds_nightly_date_idx; + +ALTER TABLE builds + DROP COLUMN rustc_nightly_date; diff --git a/migrations/20241018052241_builds-rustc-nightly-date.up.sql b/migrations/20241018052241_builds-rustc-nightly-date.up.sql new file mode 100644 index 000000000..166fae558 --- /dev/null +++ b/migrations/20241018052241_builds-rustc-nightly-date.up.sql @@ -0,0 +1,8 @@ +ALTER TABLE builds + ADD COLUMN rustc_nightly_date DATE; + +CREATE INDEX builds_nightly_date_idx ON builds USING btree (rustc_nightly_date); + +UPDATE builds + SET rustc_nightly_date = CAST(SUBSTRING(rustc_version FROM ' (\d+-\d+-\d+)\)$') AS DATE) + WHERE rustc_version IS NOT NULL; diff --git a/src/db/add_package.rs b/src/db/add_package.rs index 027691d8c..4a54b0d21 100644 --- a/src/db/add_package.rs +++ b/src/db/add_package.rs @@ -4,7 +4,7 @@ use crate::{ error::Result, registry_api::{CrateData, CrateOwner, ReleaseData}, storage::CompressionAlgorithm, - utils::MetadataPackage, + utils::{rustc_version::parse_rustc_date, MetadataPackage}, web::crate_details::{latest_release, releases_for_crate}, }; use anyhow::Context; @@ -17,7 +17,7 @@ use std::{ io::{BufRead, BufReader}, path::Path, }; -use tracing::{debug, info, instrument}; +use tracing::{debug, error, info, instrument}; /// Adds a package into database. /// @@ -244,6 +244,17 @@ pub(crate) async fn finish_build( debug!("updating build after finishing"); let hostname = hostname::get()?; + let rustc_date = match parse_rustc_date(rustc_version) { + Ok(date) => Some(date), + Err(err) => { + error!( + "Failed to parse date from rustc version \"{}\": {:?}", + rustc_version, err + ); + None + } + }; + let release_id = sqlx::query_scalar!( "UPDATE builds SET @@ -252,15 +263,17 @@ pub(crate) async fn finish_build( build_status = $3, build_server = $4, errors = $5, + rustc_nightly_date = $6, build_time = NOW() WHERE - id = $6 + id = $7 RETURNING rid", rustc_version, docsrs_version, build_status as BuildStatus, hostname.to_str().unwrap_or(""), errors, + rustc_date, build_id, ) .fetch_one(&mut *conn) @@ -606,6 +619,7 @@ mod test { use crate::registry_api::OwnerKind; use crate::test::*; use crate::utils::CargoMetadata; + use chrono::NaiveDate; use test_case::test_case; #[test] @@ -641,7 +655,55 @@ mod test { } #[test] - fn test_finish_build_success() { + fn test_finish_build_success_valid_rustc_date() { + async_wrapper(|env| async move { + let mut conn = env.async_db().await.async_conn().await; + let crate_id = initialize_crate(&mut conn, "krate").await?; + let release_id = initialize_release(&mut conn, crate_id, "0.1.0").await?; + let build_id = initialize_build(&mut conn, release_id).await?; + + finish_build( + &mut conn, + build_id, + "rustc 1.84.0-nightly (e7c0d2750 2024-10-15)", + "docsrs_version", + BuildStatus::Success, + None, + ) + .await?; + + let row = sqlx::query!( + r#"SELECT + rustc_version, + docsrs_version, + build_status as "build_status: BuildStatus", + errors, + rustc_nightly_date + FROM builds + WHERE id = $1"#, + build_id + ) + .fetch_one(&mut *conn) + .await?; + + assert_eq!( + row.rustc_version, + Some("rustc 1.84.0-nightly (e7c0d2750 2024-10-15)".into()) + ); + assert_eq!(row.docsrs_version, Some("docsrs_version".into())); + assert_eq!(row.build_status, BuildStatus::Success); + assert_eq!( + row.rustc_nightly_date, + Some(NaiveDate::from_ymd_opt(2024, 10, 15).unwrap()) + ); + assert!(row.errors.is_none()); + + Ok(()) + }) + } + + #[test] + fn test_finish_build_success_invalid_rustc_date() { async_wrapper(|env| async move { let mut conn = env.async_db().await.async_conn().await; let crate_id = initialize_crate(&mut conn, "krate").await?; @@ -663,7 +725,8 @@ mod test { rustc_version, docsrs_version, build_status as "build_status: BuildStatus", - errors + errors, + rustc_nightly_date FROM builds WHERE id = $1"#, build_id @@ -674,6 +737,7 @@ mod test { assert_eq!(row.rustc_version, Some("rustc_version".into())); assert_eq!(row.docsrs_version, Some("docsrs_version".into())); assert_eq!(row.build_status, BuildStatus::Success); + assert!(row.rustc_nightly_date.is_none()); assert!(row.errors.is_none()); Ok(()) diff --git a/src/utils/mod.rs b/src/utils/mod.rs index d591b9404..34352a483 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -21,7 +21,7 @@ pub mod daemon; mod html; mod queue; pub(crate) mod queue_builder; -mod rustc_version; +pub(crate) mod rustc_version; use anyhow::Result; use serde::de::DeserializeOwned; use serde::Serialize; diff --git a/src/utils/rustc_version.rs b/src/utils/rustc_version.rs index be318f1d6..59d201525 100644 --- a/src/utils/rustc_version.rs +++ b/src/utils/rustc_version.rs @@ -21,7 +21,7 @@ pub fn parse_rustc_version>(version: S) -> Result { )) } -fn parse_rustc_date>(version: S) -> Result { +pub(crate) fn parse_rustc_date>(version: S) -> Result { static RE: Lazy = Lazy::new(|| Regex::new(r" (\d+)-(\d+)-(\d+)\)$").unwrap()); let cap = RE