diff --git a/Cargo.lock b/Cargo.lock index 683f47a..d8fd4ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -144,6 +144,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "serde_core", + "serde_json", "serde_path_to_error", "serde_urlencoded", "sync_wrapper", @@ -450,13 +451,13 @@ dependencies = [ "axum", "color-eyre", "futures", - "jiff", "jsonwebtoken", "octocrab", "reqwest", "serde", "sqlx", "tempfile", + "time", "tokio", "tracing", "tracing-subscriber", @@ -712,25 +713,6 @@ version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" -[[package]] -name = "h2" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "hashbrown" version = "0.15.5" @@ -852,7 +834,6 @@ dependencies = [ "bytes", "futures-channel", "futures-core", - "h2", "http", "http-body", "httparse", @@ -1085,47 +1066,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" -[[package]] -name = "jiff" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49cce2b81f2098e7e3efc35bc2e0a6b7abec9d34128283d7a26fa8f32a6dbb35" -dependencies = [ - "jiff-static", - "jiff-tzdb-platform", - "log", - "portable-atomic", - "portable-atomic-util", - "serde_core", - "windows-sys 0.61.2", -] - -[[package]] -name = "jiff-static" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "jiff-tzdb" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1283705eb0a21404d2bfd6eef2a7593d240bc42a0bdb39db0ad6fa2ec026524" - -[[package]] -name = "jiff-tzdb-platform" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" -dependencies = [ - "jiff-tzdb", -] - [[package]] name = "js-sys" version = "0.3.82" @@ -1535,21 +1475,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" -[[package]] -name = "portable-atomic" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" - -[[package]] -name = "portable-atomic-util" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" -dependencies = [ - "portable-atomic", -] - [[package]] name = "potential_utf" version = "0.1.4" @@ -1747,7 +1672,6 @@ dependencies = [ "base64", "bytes", "futures-core", - "h2", "http", "http-body", "http-body-util", diff --git a/Cargo.toml b/Cargo.toml index fa7bd18..4227ae4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,29 +5,25 @@ edition = "2021" [dependencies] askama = "0.14.0" -axum = { version = "0.8.6", default-features = false, features = [ - "http1", - "matched-path", - "query", - "tokio", - "tower-log", - "tracing", - "macros", -] } +axum = { version = "0.8.6", features = ["macros"] } color-eyre = "0.6.3" futures = "0.3.30" -jiff = "0.2.16" -jsonwebtoken = { version = "9.3.1" } +jsonwebtoken = { version = "9.3.1", features = [] } octocrab = "0.47.1" reqwest = { version = "0.12.7", features = [ "rustls-tls", - "http2", ], default-features = false } serde = { version = "1.0.210", features = ["derive"] } -sqlx = { version = "0.8.2", features = ["runtime-tokio", "sqlite"] } +sqlx = { version = "0.8.2", features = [ + "macros", + "migrate", + "runtime-tokio", + "sqlite", +] } tempfile = "3.12.0" +time = { version = "0.3.36", features = ["formatting", "macros", "parsing"] } tokio = { version = "1.40.0", features = ["full"] } -tracing = { version = "0.1.40", features = ["attributes"] } +tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } [build-dependencies] diff --git a/migrations/20251111165945_notifications_last_update.sql b/migrations/20251111165945_notifications_last_update.sql deleted file mode 100644 index ada4ff7..0000000 --- a/migrations/20251111165945_notifications_last_update.sql +++ /dev/null @@ -1,4 +0,0 @@ --- Add migration script here - -ALTER TABLE notification_issues - ADD COLUMN "last_update_date" INTEGER NULL; diff --git a/src/build.rs b/src/build.rs index ea74e3b..48adaf1 100644 --- a/src/build.rs +++ b/src/build.rs @@ -83,7 +83,7 @@ async fn background_builder_inner(db: &Db, github_client: &GitHubClient) -> Resu match next { Some((nightly, mode)) => { info!(%nightly, %mode, "Building next nightly"); - let result = build_every_target_for_toolchain(db, &nightly, mode, github_client) + let result = build_every_target_for_toolchain(db, &nightly, mode, &github_client) .await .wrap_err_with(|| format!("building targets for toolchain {nightly}")); if let Err(err) = result { diff --git a/src/db.rs b/src/db.rs index 66f20f2..b25518a 100644 --- a/src/db.rs +++ b/src/db.rs @@ -106,7 +106,6 @@ pub struct NotificationIssue { pub status: NotificationStatus, pub first_failed_nightly: String, pub target: String, - pub last_update_date: Option, } impl Db { @@ -315,14 +314,13 @@ impl Db { pub async fn insert_notification(&self, notification: NotificationIssue) -> Result<()> { sqlx::query( "INSERT INTO notification_issues\ - (issue_number, status, first_failed_nightly, target, last_update_date)\ - VALUES (?, ?, ?, ?, ?)", + (issue_number, status, first_failed_nightly, target)\ + VALUES (?, ?, ?, ?)", ) .bind(notification.issue_number) .bind(notification.status) .bind(notification.first_failed_nightly) .bind(notification.target) - .bind(notification.last_update_date) .execute(&self.conn) .await .wrap_err("inserting new notification")?; @@ -338,18 +336,4 @@ impl Db { .wrap_err("marking notification as closed")?; Ok(()) } - - pub async fn set_notification_last_update( - &self, - issue_number: i64, - last_update: jiff::Timestamp, - ) -> Result<()> { - sqlx::query("UPDATE notification_issues SET last_update_date = ? WHERE issue_number = ?") - .bind(last_update.as_millisecond()) - .bind(issue_number) - .execute(&self.conn) - .await - .wrap_err("marking notification as closed")?; - Ok(()) - } } diff --git a/src/github.rs b/src/github.rs new file mode 100644 index 0000000..954915b --- /dev/null +++ b/src/github.rs @@ -0,0 +1,39 @@ +use color_eyre::{eyre::Context, Result}; +use octocrab::issues; + +pub struct GitHubClient { + pub send_pings: bool, + owner: String, + repo: String, + pub client: octocrab::Octocrab, +} + +impl GitHubClient { + pub async fn new( + send_pings: bool, + client: octocrab::Octocrab, + owner: String, + repo: String, + ) -> Result { + let installation = client + .apps() + .get_repository_installation(&owner, &repo) + .await + .wrap_err_with(|| format!("getting installation for {owner}/{repo}"))?; + + let client = client + .installation(installation.id) + .wrap_err("getting client for installation")?; + + Ok(Self { + send_pings, + owner, + repo, + client, + }) + } + + pub fn issues(&self) -> issues::IssueHandler<'_> { + self.client.issues(&self.owner, &self.repo) + } +} diff --git a/src/notification.rs b/src/notification.rs index 7d4c449..4d8c87f 100644 --- a/src/notification.rs +++ b/src/notification.rs @@ -84,6 +84,8 @@ pub async fn notify_build_failure( return Ok(()); }; + info!("Creating issue for target {target}, notifying {notify_usernames:?}"); + let issue = db.find_existing_notification(target).await?; let url = format!( @@ -91,25 +93,14 @@ pub async fn notify_build_failure( ); if let Some(issue) = issue { - // An existing issue, send a comment if it's been a month since the last update. + // An existing issue, send a comment. - if issue.last_update_date.is_none_or(|last_update_date| { - jiff::Timestamp::from_millisecond(last_update_date).is_ok_and(|last_update_date| { - jiff::Timestamp::now() - .since(last_update_date) - .is_ok_and(|diff| diff.get_months() > 0) - }) - }) { - info!( - "Sending update for {target}, since enough time has elapsed since the last update" - ); - - github_client - .issues() - .create_comment( - issue.issue_number as u64, - format!( - "💥 The target {target} still fails to build on the nightly {nightly}! + github_client + .issues() + .create_comment( + issue.issue_number as u64, + format!( + "💥 The target {target} still fails to build on the nightly {nightly}! <{url}> @@ -120,26 +111,14 @@ pub async fn notify_build_failure( ``` - -This update is sent after a month of inactivity. " - ), - ) - .await - .wrap_err("creating update comment")?; - - db.set_notification_last_update(issue.issue_number, jiff::Timestamp::now()) - .await - .wrap_err("updating last_update_date in DB")?; - } else { - info!("Not sending update for {target}, since not enough time has elapsed since the last one"); - } - + ), + ) + .await + .wrap_err("creating update comment")?; return Ok(()); } - info!("Creating issue for target {target}, notifying {notify_usernames:?}"); - // Ensure the labels exist. let label = github_client.issues().get_label(target).await; match label { @@ -197,7 +176,6 @@ This issue will be closed automatically when this target works again!" issue_number: issue.number as i64, status: NotificationStatus::Open, target: target.into(), - last_update_date: Some(jiff::Timestamp::now().as_millisecond()), }) .await .wrap_err("inserting issue into DB")?; @@ -247,7 +225,7 @@ pub async fn notify_build_pass( .await .wrap_err("closing issue")?; - db.finish_notification(issue.issue_number).await?; + db.finish_notification(issue.issue_number as i64).await?; } Ok(()) diff --git a/src/web.rs b/src/web.rs index fdb5f37..90a6408 100644 --- a/src/web.rs +++ b/src/web.rs @@ -101,10 +101,14 @@ async fn web_build(State(state): State, Query(query): Query) -> impl IntoResponse { nightlies: Vec, version: &'static str, build_count: BuildStats, - notification_pr_url: String, } let targets = state.db.target_list().await?; @@ -298,7 +301,6 @@ async fn web_root(State(state): State) -> impl IntoResponse { nightlies, version: crate::VERSION, build_count, - notification_pr_url: notification::notification_pr_url(), }; Ok(Html(page.render().unwrap()).into_response()) diff --git a/static/index.css b/static/index.css index 90ca657..876e7ed 100644 --- a/static/index.css +++ b/static/index.css @@ -1,54 +1,29 @@ -:root { - color-scheme: light dark; -} - html { font-family: sans-serif; } -@media screen and (min-width: 768px) { - html { - margin: 20px; - } -} - -table { - border-spacing: 0; -} - th, td { - padding: 2px 5px; -} - -tr:not(:last-child) { - th, - td { - border-bottom: 1px solid; - } + border: 1px solid; + margin: 0; } .error { - background-color: light-dark(lightcoral, darkred); + background-color: lightcoral; } .pass { - background-color: light-dark(greenyellow, darkgreen); + background-color: greenyellow; } .missing { - background-color: light-dark(lightgray, rgb(85, 85, 85)); + background-color: lightgray; } .target-header { writing-mode: sideways-lr; } -.build-indicator-big { - padding: 10px; - margin-top: 20px; -} - .build-cell { font-size: 2rem; } @@ -61,20 +36,13 @@ tr:not(:last-child) { padding: 5px; } +.target-name-col { + white-space: nowrap; +} + .footer { margin-top: 20px; display: flex; align-items: center; gap: 10px; } - -@media (prefers-color-scheme: dark) { - html { - background-color: #1b191c; - color: #e6dae9; - } - - a { - color: #e5a5c2; - } -} diff --git a/templates/build.html b/templates/build.html index 8eaa010..fb90738 100644 --- a/templates/build.html +++ b/templates/build.html @@ -1,4 +1,4 @@ - + @@ -6,15 +6,18 @@ Build {{nightly}} {{target}} + -

- Build results for - nightly-{{nightly}}, target - {{target}} ({{mode}}) -

+

Build results for nightly-{{nightly}} target {{target}} {{mode}}

Home -
{{status}}
+
+ {{status}} +
{% if let Some(rustflags) = rustflags %}

Using rustflags: {{rustflags}} diff --git a/templates/index.html b/templates/index.html index e6084c0..3b1702a 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,4 +1,4 @@ - + @@ -25,12 +25,6 @@ history.

-

- 🔔 does-it-build supports sending notifications to target maintainers via - GitHub issues. You can add yourself with - a PR. 🔔 -

-

Nightlies

    {% for nightly in nightlies.iter().take(5) %} diff --git a/templates/target.html b/templates/target.html index c5678ce..5e5a9f5 100644 --- a/templates/target.html +++ b/templates/target.html @@ -5,6 +5,11 @@ {{target}} build history +

    Target build history for {{target}}

    @@ -28,7 +33,7 @@

    🔔 does-it-build supports sending notifications to target maintainers via GitHub issues. - You can add yourself with a PR. 🔔 + You can add yourself with a PR.

    {% if let Some(maintainers) = maintainers %}