From c5573e917d383f034c4212ee26326a14b9e7629a Mon Sep 17 00:00:00 2001 From: Denis Cornehl Date: Mon, 24 Jun 2024 11:35:40 +0200 Subject: [PATCH 1/8] show in-progress builds on build queue page --- ...a8ab868b6d0cc20143b176522c0791a7023c.json} | 4 +- ...42ad45269ad7aab9e9c08fdaa9cb218dbc752.json | 26 ++++++++ ...616e0171b05f09b71795af14270961fa8bd0.json} | 4 +- .../20240624085737_build-status-idx.down.sql | 1 + .../20240624085737_build-status-idx.up.sql | 1 + src/web/builds.rs | 46 +++++++------- src/web/crate_details.rs | 38 +++++------- src/web/mod.rs | 2 +- src/web/releases.rs | 30 +++++++-- templates/crate/builds.html | 9 ++- templates/releases/build_queue.html | 62 +++++++++++++------ templates/style/style.scss | 8 ++- 12 files changed, 152 insertions(+), 79 deletions(-) rename .sqlx/{query-1dae7bb925d677bb997ec28130f7de41c195510e87fa643a4cae57864552962c.json => query-162c05df1f44bb48d087b6e6e4b3a8ab868b6d0cc20143b176522c0791a7023c.json} (90%) create mode 100644 .sqlx/query-3cb4dcb5778c77148aeb8dfc7f942ad45269ad7aab9e9c08fdaa9cb218dbc752.json rename .sqlx/{query-e579486925d3d1927232675b2a03d5f8dd826d7136cdbba1331faf6e64c1f5eb.json => query-771731efe02694173d758c04a4ec616e0171b05f09b71795af14270961fa8bd0.json} (89%) create mode 100644 migrations/20240624085737_build-status-idx.down.sql create mode 100644 migrations/20240624085737_build-status-idx.up.sql diff --git a/.sqlx/query-1dae7bb925d677bb997ec28130f7de41c195510e87fa643a4cae57864552962c.json b/.sqlx/query-162c05df1f44bb48d087b6e6e4b3a8ab868b6d0cc20143b176522c0791a7023c.json similarity index 90% rename from .sqlx/query-1dae7bb925d677bb997ec28130f7de41c195510e87fa643a4cae57864552962c.json rename to .sqlx/query-162c05df1f44bb48d087b6e6e4b3a8ab868b6d0cc20143b176522c0791a7023c.json index 9fc5ed11c..a41680000 100644 --- a/.sqlx/query-1dae7bb925d677bb997ec28130f7de41c195510e87fa643a4cae57864552962c.json +++ b/.sqlx/query-162c05df1f44bb48d087b6e6e4b3a8ab868b6d0cc20143b176522c0791a7023c.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT\n releases.id,\n releases.version,\n release_build_status.build_status as \"build_status!: BuildStatus\",\n releases.yanked,\n releases.is_library,\n releases.rustdoc_status,\n releases.target_name\n FROM releases\n INNER JOIN release_build_status ON releases.id = release_build_status.rid\n WHERE\n releases.crate_id = $1 AND\n release_build_status.build_status != 'in_progress'", + "query": "SELECT\n releases.id,\n releases.version,\n release_build_status.build_status as \"build_status!: BuildStatus\",\n releases.yanked,\n releases.is_library,\n releases.rustdoc_status,\n releases.target_name\n FROM releases\n INNER JOIN release_build_status ON releases.id = release_build_status.rid\n WHERE\n releases.crate_id = $1", "describe": { "columns": [ { @@ -65,5 +65,5 @@ true ] }, - "hash": "1dae7bb925d677bb997ec28130f7de41c195510e87fa643a4cae57864552962c" + "hash": "162c05df1f44bb48d087b6e6e4b3a8ab868b6d0cc20143b176522c0791a7023c" } diff --git a/.sqlx/query-3cb4dcb5778c77148aeb8dfc7f942ad45269ad7aab9e9c08fdaa9cb218dbc752.json b/.sqlx/query-3cb4dcb5778c77148aeb8dfc7f942ad45269ad7aab9e9c08fdaa9cb218dbc752.json new file mode 100644 index 000000000..0d8bee347 --- /dev/null +++ b/.sqlx/query-3cb4dcb5778c77148aeb8dfc7f942ad45269ad7aab9e9c08fdaa9cb218dbc752.json @@ -0,0 +1,26 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT\n crates.name,\n releases.version\n FROM builds\n INNER JOIN releases ON releases.id = builds.rid\n INNER JOIN crates ON releases.crate_id = crates.id\n WHERE\n builds.build_status = 'in_progress'\n ORDER BY builds.id ASC", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "name", + "type_info": "Text" + }, + { + "ordinal": 1, + "name": "version", + "type_info": "Text" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false + ] + }, + "hash": "3cb4dcb5778c77148aeb8dfc7f942ad45269ad7aab9e9c08fdaa9cb218dbc752" +} diff --git a/.sqlx/query-e579486925d3d1927232675b2a03d5f8dd826d7136cdbba1331faf6e64c1f5eb.json b/.sqlx/query-771731efe02694173d758c04a4ec616e0171b05f09b71795af14270961fa8bd0.json similarity index 89% rename from .sqlx/query-e579486925d3d1927232675b2a03d5f8dd826d7136cdbba1331faf6e64c1f5eb.json rename to .sqlx/query-771731efe02694173d758c04a4ec616e0171b05f09b71795af14270961fa8bd0.json index 92269065c..f4299ecaa 100644 --- a/.sqlx/query-e579486925d3d1927232675b2a03d5f8dd826d7136cdbba1331faf6e64c1f5eb.json +++ b/.sqlx/query-771731efe02694173d758c04a4ec616e0171b05f09b71795af14270961fa8bd0.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT\n builds.id,\n builds.rustc_version,\n builds.docsrs_version,\n builds.build_status as \"build_status: BuildStatus\",\n builds.build_time,\n builds.errors\n FROM builds\n INNER JOIN releases ON releases.id = builds.rid\n INNER JOIN crates ON releases.crate_id = crates.id\n WHERE\n crates.name = $1 AND\n releases.version = $2 AND\n builds.build_status != 'in_progress'\n ORDER BY id DESC", + "query": "SELECT\n builds.id,\n builds.rustc_version,\n builds.docsrs_version,\n builds.build_status as \"build_status: BuildStatus\",\n builds.build_time,\n builds.errors\n FROM builds\n INNER JOIN releases ON releases.id = builds.rid\n INNER JOIN crates ON releases.crate_id = crates.id\n WHERE\n crates.name = $1 AND\n releases.version = $2\n ORDER BY id DESC", "describe": { "columns": [ { @@ -60,5 +60,5 @@ true ] }, - "hash": "e579486925d3d1927232675b2a03d5f8dd826d7136cdbba1331faf6e64c1f5eb" + "hash": "771731efe02694173d758c04a4ec616e0171b05f09b71795af14270961fa8bd0" } diff --git a/migrations/20240624085737_build-status-idx.down.sql b/migrations/20240624085737_build-status-idx.down.sql new file mode 100644 index 000000000..a2d740337 --- /dev/null +++ b/migrations/20240624085737_build-status-idx.down.sql @@ -0,0 +1 @@ +DROP INDEX builds_build_status_idx; diff --git a/migrations/20240624085737_build-status-idx.up.sql b/migrations/20240624085737_build-status-idx.up.sql new file mode 100644 index 000000000..7525a7442 --- /dev/null +++ b/migrations/20240624085737_build-status-idx.up.sql @@ -0,0 +1 @@ +CREATE INDEX builds_build_status_idx ON builds USING btree (build_status ASC); diff --git a/src/web/builds.rs b/src/web/builds.rs index c63ef98f2..c2e4a749e 100644 --- a/src/web/builds.rs +++ b/src/web/builds.rs @@ -107,7 +107,10 @@ pub(crate) async fn build_list_json_handler( get_builds(&mut conn, &name, &version) .await? .iter() - .map(|build| { + .filter_map(|build| { + if build.build_status == BuildStatus::InProgress { + return None; + } // for backwards compatibility in this API, we // * convert the build status to a boolean // * already filter out in-progress builds @@ -115,13 +118,13 @@ pub(crate) async fn build_list_json_handler( // even when we start showing in-progress builds in the UI, // we might still not show them here for backwards // compatibility. - serde_json::json!({ + Some(serde_json::json!({ "id": build.id, "rustc_version": build.rustc_version, "docsrs_version": build.docsrs_version, "build_status": build.build_status.is_success(), "build_time": build.build_time, - }) + })) }) .collect::>(), ), @@ -245,8 +248,7 @@ async fn get_builds( INNER JOIN crates ON releases.crate_id = crates.id WHERE crates.name = $1 AND - releases.version = $2 AND - builds.build_status != 'in_progress' + releases.version = $2 ORDER BY id DESC"#, name, version.to_string(), @@ -548,29 +550,25 @@ mod tests { let response = env.frontend().get("/crate/foo/0.1.0/builds").send()?; - // FIXME: temporarily we don't show in-progress releases anywhere, which means we don't - // show releases without builds anywhere. - assert_eq!(response.status(), StatusCode::NOT_FOUND); - - // assert_cache_control(&response, CachePolicy::NoCaching, &env.config()); - // let page = kuchikiki::parse_html().one(response.text()?); + assert_cache_control(&response, CachePolicy::NoCaching, &env.config()); + let page = kuchikiki::parse_html().one(response.text()?); - // let rows: Vec<_> = page - // .select("ul > li a.release") - // .unwrap() - // .map(|row| row.text_contents()) - // .collect(); + let rows: Vec<_> = page + .select("ul > li a.release") + .unwrap() + .map(|row| row.text_contents()) + .collect(); - // assert!(rows.is_empty()); + assert!(rows.is_empty()); - // let warning = page - // .select_first(".warning") - // .expect("missing warning element") - // .text_contents(); + let warning = page + .select_first(".warning") + .expect("missing warning element") + .text_contents(); - // assert!(warning.contains("has not built")); - // assert!(warning.contains("queued")); - // assert!(warning.contains("open an issue")); + assert!(warning.contains("has not built")); + assert!(warning.contains("queued")); + assert!(warning.contains("open an issue")); Ok(()) }); diff --git a/src/web/crate_details.rs b/src/web/crate_details.rs index 214c3eaf9..0eaecb889 100644 --- a/src/web/crate_details.rs +++ b/src/web/crate_details.rs @@ -374,8 +374,7 @@ pub(crate) async fn releases_for_crate( FROM releases INNER JOIN release_build_status ON releases.id = release_build_status.rid WHERE - releases.crate_id = $1 AND - release_build_status.build_status != 'in_progress'"#, + releases.crate_id = $1"#, crate_id, ) .fetch(&mut *conn) @@ -1341,25 +1340,22 @@ mod tests { .create()?; let response = env.frontend().get("/crate/foo/latest").send()?; - // FIXME: temporarily we don't show in-progress releases anywhere, which means we don't - // show releases without builds anywhere. - assert_eq!(response.status(), StatusCode::NOT_FOUND); - - // let page = kuchikiki::parse_html().one(response.text()?); - // let link = page - // .select_first("a.pure-menu-link[href='/crate/foo/0.1.0']") - // .unwrap(); - - // assert_eq!( - // link.as_node() - // .as_element() - // .unwrap() - // .attributes - // .borrow() - // .get("title") - // .unwrap(), - // "foo-0.1.0 is currently being built" - // ); + + let page = kuchikiki::parse_html().one(response.text()?); + let link = page + .select_first("a.pure-menu-link[href='/crate/foo/0.1.0']") + .unwrap(); + + assert_eq!( + link.as_node() + .as_element() + .unwrap() + .attributes + .borrow() + .get("title") + .unwrap(), + "foo-0.1.0 is currently being built" + ); Ok(()) }); diff --git a/src/web/mod.rs b/src/web/mod.rs index 319dd9db7..3469f7bee 100644 --- a/src/web/mod.rs +++ b/src/web/mod.rs @@ -308,7 +308,7 @@ async fn match_version( }; // when matching semver requirements, we only want to look at non-yanked releases. - let flt = |r: &&Release| r.yanked == Some(false); + let flt = |r: &&Release| r.yanked.is_none() || r.yanked == Some(false); if let Some(release) = releases .iter() diff --git a/src/web/releases.rs b/src/web/releases.rs index 61c3fee1a..e8e43813f 100644 --- a/src/web/releases.rs +++ b/src/web/releases.rs @@ -784,7 +784,8 @@ pub(crate) async fn activity_handler(mut conn: DbConnection) -> AxumResult, - active_deployments: Vec, + active_cdn_deployments: Vec, + in_progress_builds: Vec<(String, String)>, csp_nonce: String, } @@ -793,8 +794,9 @@ impl_axum_webpage! { BuildQueuePage } pub(crate) async fn build_queue_handler( Extension(build_queue): Extension>, Extension(pool): Extension, + mut conn: DbConnection, ) -> AxumResult { - let (queue, active_deployments) = spawn_blocking(move || { + let (queue, active_cdn_deployments) = spawn_blocking(move || { let mut queue = build_queue.queued_crates()?; for krate in queue.iter_mut() { // The priority here is inverted: in the database if a crate has a higher priority it @@ -820,10 +822,28 @@ pub(crate) async fn build_queue_handler( }) .await?; + let in_progress_builds: Vec<(String, String)> = sqlx::query!( + r#"SELECT + crates.name, + releases.version + FROM builds + INNER JOIN releases ON releases.id = builds.rid + INNER JOIN crates ON releases.crate_id = crates.id + WHERE + builds.build_status = 'in_progress' + ORDER BY builds.id ASC"# + ) + .fetch_all(&mut *conn) + .await? + .into_iter() + .map(|rec| (rec.name, rec.version)) + .collect(); + Ok(BuildQueuePage { description: "crate documentation scheduled to build & deploy", queue, - active_deployments, + active_cdn_deployments, + in_progress_builds, csp_nonce: String::new(), }) } @@ -1695,9 +1715,9 @@ mod tests { let empty = kuchikiki::parse_html().one(web.get("/releases/queue").send()?.text()?); assert!(empty - .select(".release > strong") + .select(".release > div > strong") .expect("missing heading") - .any(|el| el.text_contents().contains("active CDN deployments"))); + .any(|el| dbg!(el.text_contents()).contains("active CDN deployments"))); let full = kuchikiki::parse_html().one(web.get("/releases/queue").send()?.text()?); let items = full diff --git a/templates/crate/builds.html b/templates/crate/builds.html index 3c7015d5f..aa8fd88da 100644 --- a/templates/crate/builds.html +++ b/templates/crate/builds.html @@ -33,7 +33,11 @@ {%- else -%} - {# FIXME: temporarily this will never be shown since we hide in-progress releases for now #}
docs.rs has not built {{ metadata.name }}-{{ metadata.version }}
diff --git a/templates/releases/build_queue.html b/templates/releases/build_queue.html index 8ce8d5d5f..39dceb0aa 100644 --- a/templates/releases/build_queue.html +++ b/templates/releases/build_queue.html @@ -15,34 +15,56 @@ {%- block body -%}
- {%- if !active_deployments.is_empty() %} -
- active CDN deployments +
+
+ currently being built +
+
+ {%- if !active_cdn_deployments.is_empty() %} + active CDN deployments + {%- endif %} +
-
    - {% for krate in active_deployments -%} -
  1. - - {{ krate }} - -
  2. - {%- endfor %} -
+ {%- if !in_progress_builds.is_empty() %} +
    + {% for release in in_progress_builds -%} +
  1. + + {{ release.0 }} {{ release.1 }} + +
  2. + {%- endfor %} +
+ {%- else %} +
+

There is nothing currently being built

+
+ {%- endif %}
-
-

- After the build finishes it may take up to 20 minutes for all documentation - pages to be up-to-date and available to everybody. -

-

Especially /latest/ URLs might be affected.

-
+ {%- if !active_cdn_deployments.is_empty() %} +
    + {% for krate in active_cdn_deployments -%} +
  1. + + {{ krate }} + +
  2. + {%- endfor %} +
+
+

+ After the build finishes it may take up to 20 minutes for all documentation + pages to be up-to-date and available to everybody. +

+

Especially /latest/ URLs might be affected.

+
+ {%- endif %}
- {%- endif %}
Build Queue diff --git a/templates/style/style.scss b/templates/style/style.scss index d5c1a7841..74cdeb921 100644 --- a/templates/style/style.scss +++ b/templates/style/style.scss @@ -280,7 +280,7 @@ div.recent-releases-container { background-color: var(--background-color); } - .release { + .release, .build-in-progress { display: block; border-bottom: 1px solid var(--color-border); padding: 0.4em $search-result-right-left-padding; @@ -297,11 +297,13 @@ div.recent-releases-container { } .release:hover, - a.release:focus { + a.release:focus, + .build-in-progress:hover { background-color: var(--color-background-code); } - li:last-of-type .release { + li:last-of-type .release, + li:last-of-type .build-in-progress { border-bottom: none; } From fc9d61a686c12940f218fe13b4c245f222e5f02e Mon Sep 17 00:00:00 2001 From: Denis Cornehl Date: Sun, 22 Sep 2024 08:28:13 +0200 Subject: [PATCH 2/8] fix icon for failed builds in build-list --- src/web/page/templates.rs | 3 ++- templates/crate/builds.html | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/web/page/templates.rs b/src/web/page/templates.rs index 7d3cffbd0..21c6c8e90 100644 --- a/src/web/page/templates.rs +++ b/src/web/page/templates.rs @@ -274,7 +274,8 @@ impl IconType { IconType::Brand => font_awesome_as_a_crate::Type::Brands, }; - let icon_file_string = font_awesome_as_a_crate::svg(type_, icon_name).unwrap_or(""); + let icon_file_string = font_awesome_as_a_crate::svg(type_, icon_name) + .map_err(|err| rinja::Error::Custom(Box::new(err)))?; let mut classes = vec!["fa-svg"]; if fw { diff --git a/templates/crate/builds.html b/templates/crate/builds.html index aa8fd88da..0d4959871 100644 --- a/templates/crate/builds.html +++ b/templates/crate/builds.html @@ -43,7 +43,7 @@ {%- if build.build_status == "success" -%} {{ "check"|fas(false, false, "") }} {%- elif build.build_status == "failure" -%} - {{ "times"|fas(false, false, "") }} + {{ "triangle-exclamation"|fas(false, false, "") }} {%- elif build.build_status == "in_progress" -%} {{ "gear"|fas(false, true, "") }} {%- else -%} From 0edb3b26da6762b77e503640876625d0275446c4 Mon Sep 17 00:00:00 2001 From: Denis Cornehl Date: Sun, 22 Sep 2024 08:28:30 +0200 Subject: [PATCH 3/8] fix HTML indentation in build-queue --- templates/releases/build_queue.html | 94 ++++++++++++++--------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/templates/releases/build_queue.html b/templates/releases/build_queue.html index 39dceb0aa..000eaf41c 100644 --- a/templates/releases/build_queue.html +++ b/templates/releases/build_queue.html @@ -15,56 +15,56 @@ {%- block body -%}
-
-
- currently being built -
-
- {%- if !active_cdn_deployments.is_empty() %} - active CDN deployments - {%- endif %} -
+
+
+ currently being built
+
+ {%- if !active_cdn_deployments.is_empty() %} + active CDN deployments + {%- endif %} +
+
-
-
- {%- if !in_progress_builds.is_empty() %} -
    - {% for release in in_progress_builds -%} -
  1. - - {{ release.0 }} {{ release.1 }} - -
  2. - {%- endfor %} -
- {%- else %} -
-

There is nothing currently being built

-
- {%- endif %} -
-
- {%- if !active_cdn_deployments.is_empty() %} -
    - {% for krate in active_cdn_deployments -%} -
  1. - - {{ krate }} - -
  2. - {%- endfor %} -
-
-

- After the build finishes it may take up to 20 minutes for all documentation - pages to be up-to-date and available to everybody. -

-

Especially /latest/ URLs might be affected.

-
- {%- endif %} -
+
+
+ {%- if !in_progress_builds.is_empty() %} +
    + {% for release in in_progress_builds -%} +
  1. + + {{ release.0 }} {{ release.1 }} + +
  2. + {%- endfor %} +
+ {%- else %} +
+

There is nothing currently being built

+
+ {%- endif %}
+
+ {%- if !active_cdn_deployments.is_empty() %} +
    + {% for krate in active_cdn_deployments -%} +
  1. + + {{ krate }} + +
  2. + {%- endfor %} +
+
+

+ After the build finishes it may take up to 20 minutes for all documentation + pages to be up-to-date and available to everybody. +

+

Especially /latest/ URLs might be affected.

+
+ {%- endif %} +
+
Build Queue From cc1f0a373f823eb486bad54882508aeeca2566f3 Mon Sep 17 00:00:00 2001 From: Denis Cornehl Date: Sun, 22 Sep 2024 08:30:53 +0200 Subject: [PATCH 4/8] remove debugging code --- src/web/releases.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/web/releases.rs b/src/web/releases.rs index e8e43813f..2cdc86f94 100644 --- a/src/web/releases.rs +++ b/src/web/releases.rs @@ -1717,7 +1717,7 @@ mod tests { assert!(empty .select(".release > div > strong") .expect("missing heading") - .any(|el| dbg!(el.text_contents()).contains("active CDN deployments"))); + .any(|el| el.text_contents().contains("active CDN deployments"))); let full = kuchikiki::parse_html().one(web.get("/releases/queue").send()?.text()?); let items = full From e0f2ed0781af1611d324d17b512c8732d98b4d74 Mon Sep 17 00:00:00 2001 From: Denis Cornehl Date: Sun, 22 Sep 2024 08:57:32 +0200 Subject: [PATCH 5/8] fix invalid font-awesome icon names --- templates/crate/source.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/crate/source.html b/templates/crate/source.html index 14da8d1c3..1dc2a62d5 100644 --- a/templates/crate/source.html +++ b/templates/crate/source.html @@ -86,11 +86,11 @@ {# Text files or files which mime starts with `text` #} {%- elif file.mime == "text/plain" || file.mime|split_first("/") == Some("text") -%} - {{ "file-alt"|far(false, false, "") }} + {{ "file-lines"|far(false, false, "") }} {# Binary files and any unrecognized types #} {% else -%} - {{ "file-archive"|far(false, false, "") }} + {{ "file"|far(false, false, "") }} {%- endif -%} {{ file.name }} From 4d37adaa56c185fd127badd2842c3d011bda0434 Mon Sep 17 00:00:00 2001 From: Denis Cornehl Date: Sun, 22 Sep 2024 12:02:06 +0200 Subject: [PATCH 6/8] semver match should skip over in progress releases when we have others --- src/web/mod.rs | 91 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 67 insertions(+), 24 deletions(-) diff --git a/src/web/mod.rs b/src/web/mod.rs index 3469f7bee..73242b532 100644 --- a/src/web/mod.rs +++ b/src/web/mod.rs @@ -236,6 +236,27 @@ impl MatchedRelease { } } +fn semver_match<'a, F: Fn(&Release) -> bool>( + releases: &'a [Release], + req: &VersionReq, + filter: F, +) -> Option<&'a Release> { + if let Some(release) = releases + .iter() + .filter(|release| filter(release)) + .find(|release| req.matches(&release.version)) + { + Some(release) + } else if req == &VersionReq::STAR { + // semver `*` does not match pre-releases. + // When someone wants the latest release and we have only pre-releases + // just return the latest prerelease. + return releases.iter().find(|release| filter(release)); + } else { + None + } +} + /// Checks the database for crate releases that match the given name and version. /// /// `version` may be an exact version number or loose semver version requirement. The return value @@ -307,14 +328,12 @@ async fn match_version( ReqVersion::Semver(version_req) => version_req.clone(), }; - // when matching semver requirements, we only want to look at non-yanked releases. - let flt = |r: &&Release| r.yanked.is_none() || r.yanked == Some(false); - - if let Some(release) = releases - .iter() - .filter(flt) - .find(|release| req_semver.matches(&release.version)) - { + // when matching semver requirements, + // we generally only want to look at non-yanked releases, + // excluding releases which just contain in-progress builds + if let Some(release) = semver_match(&releases, &req_semver, |r: &Release| { + r.build_status != BuildStatus::InProgress && (r.yanked.is_none() || r.yanked == Some(false)) + }) { return Ok(MatchedRelease { name: name.to_owned(), corrected_name, @@ -324,22 +343,17 @@ async fn match_version( }); } - // semver `*` does not match pre-releases. - // When someone wants the latest release and we have only pre-releases - // just return the latest prerelease. - if req_semver == VersionReq::STAR { - return releases - .iter() - .find(flt) - .cloned() - .map(|release| MatchedRelease { - name: name.to_owned(), - corrected_name: corrected_name.clone(), - req_version: input_version.clone(), - release, - all_releases: releases, - }) - .ok_or(AxumNope::VersionNotFound); + // when we don't find any match with "normal" releases, we also look into in-progress releases + if let Some(release) = semver_match(&releases, &req_semver, |r: &Release| { + r.yanked.is_none() || r.yanked == Some(false) + }) { + return Ok(MatchedRelease { + name: name.to_owned(), + corrected_name, + req_version: input_version.clone(), + release: release.clone(), + all_releases: releases, + }); } // Since we return with a CrateNotFound earlier if the db reply is empty, @@ -1050,6 +1064,35 @@ mod test { }); } + #[test] + fn in_progress_releases_are_ignored_when_others_match() { + async_wrapper(|env| async move { + let db = env.async_db().await; + + // normal release + release("1.0.0", &env).await; + + // in progress release + env.async_fake_release() + .await + .name("foo") + .version("1.1.0") + .builds(vec![ + FakeBuild::default().build_status(BuildStatus::InProgress) + ]) + .create_async() + .await?; + + // STAR gives me the prod release + assert_eq!(version(Some("*"), db).await, exact("1.0.0")); + + // exact-match query gives me the in progress release + assert_eq!(version(Some("=1.1.0"), db).await, exact("1.1.0")); + + Ok(()) + }) + } + #[test] // https://github.com/rust-lang/docs.rs/issues/1682 fn prereleases_are_considered_when_others_dont_match() { From c27e05ffb9ac74ba8dace2ff9a7e8aa5349afe13 Mon Sep 17 00:00:00 2001 From: Denis Cornehl Date: Sun, 22 Sep 2024 13:54:30 +0200 Subject: [PATCH 7/8] use variable for closing tag --- templates/crate/builds.html | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/templates/crate/builds.html b/templates/crate/builds.html index 0d4959871..4acc6ba5b 100644 --- a/templates/crate/builds.html +++ b/templates/crate/builds.html @@ -32,11 +32,14 @@ From 6fe7b40e03f0eb7db51813473230705890406820 Mon Sep 17 00:00:00 2001 From: Denis Cornehl Date: Sun, 22 Sep 2024 14:48:21 +0200 Subject: [PATCH 8/8] extend comment on match_version semver match --- src/web/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/web/mod.rs b/src/web/mod.rs index 73242b532..8c4443254 100644 --- a/src/web/mod.rs +++ b/src/web/mod.rs @@ -241,6 +241,7 @@ fn semver_match<'a, F: Fn(&Release) -> bool>( req: &VersionReq, filter: F, ) -> Option<&'a Release> { + // first try standard semver match using `VersionReq::match`, should handle most cases. if let Some(release) = releases .iter() .filter(|release| filter(release)) @@ -249,8 +250,9 @@ fn semver_match<'a, F: Fn(&Release) -> bool>( Some(release) } else if req == &VersionReq::STAR { // semver `*` does not match pre-releases. - // When someone wants the latest release and we have only pre-releases - // just return the latest prerelease. + // So when we only have pre-releases, `VersionReq::STAR` would lead to an + // empty result. + // In this case we just return the latest latest prerelase instead of nothing. return releases.iter().find(|release| filter(release)); } else { None