Skip to content

Commit 2e7770f

Browse files
committed
Feat; add releases to the benchmark_request queue
1 parent 1dcd547 commit 2e7770f

File tree

1 file changed

+166
-4
lines changed

1 file changed

+166
-4
lines changed

site/src/job_queue.rs

Lines changed: 166 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1-
use std::{str::FromStr, sync::Arc};
1+
use std::{
2+
path::Path,
3+
str::FromStr,
4+
sync::{Arc, LazyLock},
5+
};
26

37
use crate::load::{partition_in_place, SiteCtxt};
4-
use chrono::Utc;
8+
use chrono::{DateTime, NaiveDate, Timelike, Utc};
59
use database::{BenchmarkRequest, BenchmarkRequestStatus, BenchmarkRequestType};
610
use hashbrown::HashSet;
711
use parking_lot::RwLock;
12+
use regex::Regex;
813
use tokio::time::{self, Duration};
914

1015
/// Store the latest master commits or do nothing if all of them are
@@ -36,6 +41,93 @@ async fn create_benchmark_request_master_commits(
3641
Ok(())
3742
}
3843

44+
/// Parses strings in the following formats extracting the Date & release tag
45+
/// `static.rust-lang.org/dist/2016-05-24/channel-rust-1.9.0.toml`
46+
/// `static.rust-lang.org/dist/2016-05-31/channel-rust-nightly.toml`
47+
/// `static.rust-lang.org/dist/2016-06-01/channel-rust-beta.toml`
48+
/// `static.rust-lang.org/dist/2025-06-26/channel-rust-1.89-beta.toml`
49+
/// `static.rust-lang.org/dist/2025-06-26/channel-rust-1.89.0-beta.toml`
50+
/// `static.rust-lang.org/dist/2025-06-26/channel-rust-1.89.0-beta.2.toml`
51+
fn parse_release_string(url: &str) -> anyhow::Result<Option<(String, DateTime<Utc>)>> {
52+
static VERSION_RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(\d+\.\d+\.\d+)").unwrap());
53+
54+
// Grab ".../YYYY-MM-DD/FILE.toml" components with Path helpers.
55+
let file = Path::new(url)
56+
.file_name()
57+
.and_then(|n| n.to_str())
58+
.ok_or_else(|| anyhow::anyhow!("URL lacks a file name"))?;
59+
60+
let date_str = Path::new(url)
61+
.parent()
62+
.and_then(Path::file_name)
63+
.and_then(|n| n.to_str())
64+
.ok_or_else(|| anyhow::anyhow!("URL lacks a date segment"))?;
65+
66+
// No other beta releases are recognized as toolchains.
67+
//
68+
// We also have names like this:
69+
//
70+
// * channel-rust-1.75-beta.toml
71+
// * channel-rust-1.75.0-beta.toml
72+
// * channel-rust-1.75.0-beta.1.toml
73+
//
74+
// Which should get ignored for now, they're not consumable via rustup yet.
75+
if file.contains("beta") && file != "channel-rust-beta.toml" {
76+
return Ok(None);
77+
}
78+
79+
// Parse the YYYY-MM-DD segment and stamp it with *current* UTC time.
80+
let naive = NaiveDate::parse_from_str(date_str, "%Y-%m-%d")?;
81+
let now = Utc::now();
82+
let published = naive
83+
.and_hms_nano_opt(now.hour(), now.minute(), now.second(), now.nanosecond())
84+
.expect("valid HMS")
85+
.and_local_timezone(Utc)
86+
.single()
87+
.unwrap();
88+
89+
// Special-case the rolling beta channel.
90+
if file == "channel-rust-beta.toml" {
91+
return Ok(Some((format!("beta-{date_str}"), published)));
92+
}
93+
94+
// Otherwise pull out a semver like "1.70.0" and return it.
95+
if let Some(cap) = VERSION_RE.captures(file).and_then(|m| m.get(1)) {
96+
return Ok(Some((cap.as_str().to_owned(), published)));
97+
}
98+
99+
Ok(None)
100+
}
101+
102+
/// Store the latest release commits or do nothing if all of them are
103+
/// already in the database
104+
async fn create_benchmark_request_releases(
105+
conn: &dyn database::pool::Connection,
106+
) -> anyhow::Result<()> {
107+
let releases: String = reqwest::get("https://static.rust-lang.org/manifests.txt")
108+
.await?
109+
.text()
110+
.await?;
111+
// TODO; delete at some point in the future
112+
let cutoff: chrono::DateTime<Utc> = chrono::DateTime::from_str("2025-06-01T00:00:00.000Z")?;
113+
114+
for release_string in releases.lines() {
115+
if let Some((name, date_time)) = parse_release_string(release_string)? {
116+
if date_time >= cutoff {
117+
let release_request = BenchmarkRequest::create_release(
118+
&name,
119+
date_time,
120+
BenchmarkRequestStatus::ArtifactsReady,
121+
"",
122+
"",
123+
);
124+
conn.insert_benchmark_request(&release_request).await;
125+
}
126+
}
127+
}
128+
Ok(())
129+
}
130+
39131
/// Sorts try and master requests that are in the `ArtifactsReady` status.
40132
/// Doesn't consider in-progress requests or release artifacts.
41133
fn sort_benchmark_requests(done: &HashSet<String>, request_queue: &mut [BenchmarkRequest]) {
@@ -186,6 +278,8 @@ async fn cron_enqueue_jobs(site_ctxt: &Arc<SiteCtxt>) -> anyhow::Result<()> {
186278
let mut conn = site_ctxt.conn().await;
187279
// Put the master commits into the `benchmark_requests` queue
188280
create_benchmark_request_master_commits(site_ctxt, &*conn).await?;
281+
// Put the releases into the `benchmark_requests` queue
282+
create_benchmark_request_releases(&*conn).await?;
189283
enqueue_next_job(&mut *conn).await?;
190284
Ok(())
191285
}
@@ -213,10 +307,26 @@ pub async fn cron_main(site_ctxt: Arc<RwLock<Option<Arc<SiteCtxt>>>>, seconds: u
213307
#[cfg(test)]
214308
mod tests {
215309
use super::*;
216-
use chrono::{Datelike, Duration, TimeZone, Utc};
217-
310+
use chrono::{Datelike, Duration, NaiveDate, TimeZone, Utc};
218311
use database::tests::run_postgres_test;
219312

313+
/// Helper: unwrap the Option, panic otherwise.
314+
fn tag(url: &str) -> String {
315+
parse_release_string(url)
316+
.unwrap() // anyhow::Result<_>
317+
.expect("Some") // Option<_>
318+
.0 // take the tag
319+
}
320+
321+
/// Helper: unwrap the DateTime and keep only the YYYY-MM-DD part
322+
fn day(url: &str) -> NaiveDate {
323+
parse_release_string(url)
324+
.unwrap()
325+
.expect("Some")
326+
.1
327+
.date_naive()
328+
}
329+
220330
fn days_ago(day_str: &str) -> chrono::DateTime<Utc> {
221331
// Walk backwards until the first non-digit, then slice
222332
let days = day_str
@@ -602,4 +712,56 @@ mod tests {
602712
})
603713
.await;
604714
}
715+
716+
#[test]
717+
fn parses_stable_versions() {
718+
assert_eq!(
719+
tag("static.rust-lang.org/dist/2016-05-24/channel-rust-1.9.0.toml"),
720+
"1.9.0"
721+
);
722+
assert_eq!(
723+
day("static.rust-lang.org/dist/2016-05-24/channel-rust-1.9.0.toml"),
724+
NaiveDate::from_ymd_opt(2016, 5, 24).unwrap()
725+
);
726+
727+
assert_eq!(
728+
tag("static.rust-lang.org/dist/2025-06-26/channel-rust-1.88.0.toml"),
729+
"1.88.0"
730+
);
731+
assert_eq!(
732+
day("static.rust-lang.org/dist/2025-06-26/channel-rust-1.88.0.toml"),
733+
NaiveDate::from_ymd_opt(2025, 6, 26).unwrap()
734+
);
735+
}
736+
737+
#[test]
738+
fn parses_plain_beta_channel() {
739+
let want = "beta-2016-06-01";
740+
let url = "static.rust-lang.org/dist/2016-06-01/channel-rust-beta.toml";
741+
742+
assert_eq!(tag(url), want);
743+
assert_eq!(day(url), NaiveDate::from_ymd_opt(2016, 6, 1).unwrap());
744+
}
745+
746+
#[test]
747+
fn skips_unconsumable_channels() {
748+
// nightly never returns Anything
749+
assert!(parse_release_string(
750+
"static.rust-lang.org/dist/2016-05-31/channel-rust-nightly.toml"
751+
)
752+
.unwrap()
753+
.is_none());
754+
755+
// versioned-beta artefacts are skipped too
756+
for should_ignore in [
757+
"static.rust-lang.org/dist/2025-06-26/channel-rust-1.89-beta.toml",
758+
"static.rust-lang.org/dist/2025-06-26/channel-rust-1.89.0-beta.toml",
759+
"static.rust-lang.org/dist/2025-06-26/channel-rust-1.89.0-beta.2.toml",
760+
] {
761+
assert!(
762+
parse_release_string(should_ignore).unwrap().is_none(),
763+
"{should_ignore} should be ignored"
764+
);
765+
}
766+
}
605767
}

0 commit comments

Comments
 (0)