From 491eb1604feff9635e9f3fcdbf7f433a2add88f9 Mon Sep 17 00:00:00 2001
From: Noratrieb <48135649+Noratrieb@users.noreply.github.com>
Date: Tue, 11 Nov 2025 18:46:29 +0100
Subject: [PATCH 1/5] Only send notification update after a month of inactivity
A lower cadence was requested in https://github.com/Noratrieb/does-it-build/pull/10#issuecomment-3514228933
---
Cargo.lock | 57 +++++++++++++++++++
Cargo.toml | 1 +
...251111165945_notifications_last_update.sql | 4 ++
src/db.rs | 20 ++++++-
src/github.rs | 39 -------------
src/notification.rs | 48 +++++++++++-----
6 files changed, 115 insertions(+), 54 deletions(-)
create mode 100644 migrations/20251111165945_notifications_last_update.sql
delete mode 100644 src/github.rs
diff --git a/Cargo.lock b/Cargo.lock
index d8fd4ed..1c75241 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -451,6 +451,7 @@ dependencies = [
"axum",
"color-eyre",
"futures",
+ "jiff",
"jsonwebtoken",
"octocrab",
"reqwest",
@@ -1066,6 +1067,47 @@ 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"
@@ -1475,6 +1517,21 @@ 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"
diff --git a/Cargo.toml b/Cargo.toml
index 4227ae4..431f16d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,6 +8,7 @@ askama = "0.14.0"
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", features = [] }
octocrab = "0.47.1"
reqwest = { version = "0.12.7", features = [
diff --git a/migrations/20251111165945_notifications_last_update.sql b/migrations/20251111165945_notifications_last_update.sql
new file mode 100644
index 0000000..ada4ff7
--- /dev/null
+++ b/migrations/20251111165945_notifications_last_update.sql
@@ -0,0 +1,4 @@
+-- Add migration script here
+
+ALTER TABLE notification_issues
+ ADD COLUMN "last_update_date" INTEGER NULL;
diff --git a/src/db.rs b/src/db.rs
index b25518a..66f20f2 100644
--- a/src/db.rs
+++ b/src/db.rs
@@ -106,6 +106,7 @@ pub struct NotificationIssue {
pub status: NotificationStatus,
pub first_failed_nightly: String,
pub target: String,
+ pub last_update_date: Option,
}
impl Db {
@@ -314,13 +315,14 @@ impl Db {
pub async fn insert_notification(&self, notification: NotificationIssue) -> Result<()> {
sqlx::query(
"INSERT INTO notification_issues\
- (issue_number, status, first_failed_nightly, target)\
- VALUES (?, ?, ?, ?)",
+ (issue_number, status, first_failed_nightly, target, last_update_date)\
+ 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")?;
@@ -336,4 +338,18 @@ 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
deleted file mode 100644
index 954915b..0000000
--- a/src/github.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-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 4d8c87f..f606173 100644
--- a/src/notification.rs
+++ b/src/notification.rs
@@ -84,8 +84,6 @@ 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!(
@@ -93,14 +91,25 @@ pub async fn notify_build_failure(
);
if let Some(issue) = issue {
- // An existing issue, send a comment.
+ // An existing issue, send a comment if it's been a month 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}!
+ 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}!
<{url}>
@@ -111,14 +120,26 @@ pub async fn notify_build_failure(
```
+
+This update is sent after a month of inactivity.
"
- ),
- )
- .await
- .wrap_err("creating update comment")?;
+ ),
+ )
+ .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");
+ }
+
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 {
@@ -176,6 +197,7 @@ 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")?;
From 73098095a71b989311fb96691ff8850ad58f5d56 Mon Sep 17 00:00:00 2001
From: Noratrieb <48135649+Noratrieb@users.noreply.github.com>
Date: Tue, 11 Nov 2025 19:03:37 +0100
Subject: [PATCH 2/5] Optimize features
---
Cargo.lock | 23 +++++++++++++++++++++--
Cargo.toml | 23 +++++++++++++----------
src/web.rs | 12 ++++--------
3 files changed, 38 insertions(+), 20 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 1c75241..683f47a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -144,7 +144,6 @@ dependencies = [
"percent-encoding",
"pin-project-lite",
"serde_core",
- "serde_json",
"serde_path_to_error",
"serde_urlencoded",
"sync_wrapper",
@@ -458,7 +457,6 @@ dependencies = [
"serde",
"sqlx",
"tempfile",
- "time",
"tokio",
"tracing",
"tracing-subscriber",
@@ -714,6 +712,25 @@ 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"
@@ -835,6 +852,7 @@ dependencies = [
"bytes",
"futures-channel",
"futures-core",
+ "h2",
"http",
"http-body",
"httparse",
@@ -1729,6 +1747,7 @@ dependencies = [
"base64",
"bytes",
"futures-core",
+ "h2",
"http",
"http-body",
"http-body-util",
diff --git a/Cargo.toml b/Cargo.toml
index 431f16d..fa7bd18 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,26 +5,29 @@ edition = "2021"
[dependencies]
askama = "0.14.0"
-axum = { version = "0.8.6", features = ["macros"] }
+axum = { version = "0.8.6", default-features = false, features = [
+ "http1",
+ "matched-path",
+ "query",
+ "tokio",
+ "tower-log",
+ "tracing",
+ "macros",
+] }
color-eyre = "0.6.3"
futures = "0.3.30"
jiff = "0.2.16"
-jsonwebtoken = { version = "9.3.1", features = [] }
+jsonwebtoken = { version = "9.3.1" }
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 = [
- "macros",
- "migrate",
- "runtime-tokio",
- "sqlite",
-] }
+sqlx = { version = "0.8.2", features = ["runtime-tokio", "sqlite"] }
tempfile = "3.12.0"
-time = { version = "0.3.36", features = ["formatting", "macros", "parsing"] }
tokio = { version = "1.40.0", features = ["full"] }
-tracing = "0.1.40"
+tracing = { version = "0.1.40", features = ["attributes"] }
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
[build-dependencies]
diff --git a/src/web.rs b/src/web.rs
index 90a6408..6d93547 100644
--- a/src/web.rs
+++ b/src/web.rs
@@ -101,14 +101,10 @@ async fn web_build(State(state): State, Query(query): Query
Date: Tue, 11 Nov 2025 19:04:14 +0100
Subject: [PATCH 3/5] Cleanup
---
src/build.rs | 2 +-
src/notification.rs | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/build.rs b/src/build.rs
index 48adaf1..ea74e3b 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/notification.rs b/src/notification.rs
index f606173..7d4c449 100644
--- a/src/notification.rs
+++ b/src/notification.rs
@@ -247,7 +247,7 @@ pub async fn notify_build_pass(
.await
.wrap_err("closing issue")?;
- db.finish_notification(issue.issue_number as i64).await?;
+ db.finish_notification(issue.issue_number).await?;
}
Ok(())
From 310a24aa448a086b52c9a2f1fdc94e2a5d1e7bef Mon Sep 17 00:00:00 2001
From: Noratrieb <48135649+Noratrieb@users.noreply.github.com>
Date: Tue, 11 Nov 2025 19:26:28 +0100
Subject: [PATCH 4/5] Make it look much better
Including dark mode!
---
src/web.rs | 2 ++
static/index.css | 44 ++++++++++++++++++++++++++++++++++---------
templates/build.html | 17 +++++++----------
templates/index.html | 8 +++++++-
templates/target.html | 7 +------
5 files changed, 52 insertions(+), 26 deletions(-)
diff --git a/src/web.rs b/src/web.rs
index 6d93547..fdb5f37 100644
--- a/src/web.rs
+++ b/src/web.rs
@@ -286,6 +286,7 @@ async fn web_root(State(state): State) -> impl IntoResponse {
nightlies: Vec,
version: &'static str,
build_count: BuildStats,
+ notification_pr_url: String,
}
let targets = state.db.target_list().await?;
@@ -297,6 +298,7 @@ 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 876e7ed..a2ca57c 100644
--- a/static/index.css
+++ b/static/index.css
@@ -1,29 +1,48 @@
+:root {
+ color-scheme: light dark;
+}
html {
font-family: sans-serif;
+ margin: 20px;
+}
+
+table {
+ border-spacing: 0;
}
th,
td {
- border: 1px solid;
- margin: 0;
+ padding: 2px 5px;
+}
+
+tr:not(:last-child) {
+ th,
+ td {
+ border-bottom: 1px solid;
+ }
}
.error {
- background-color: lightcoral;
+ background-color: light-dark(lightcoral, darkred);
}
.pass {
- background-color: greenyellow;
+ background-color: light-dark(greenyellow, darkgreen);
}
.missing {
- background-color: lightgray;
+ background-color: light-dark(lightgray, rgb(85, 85, 85));
}
.target-header {
writing-mode: sideways-lr;
}
+.build-indicator-big {
+ padding: 10px;
+ margin-top: 20px;
+}
+
.build-cell {
font-size: 2rem;
}
@@ -36,13 +55,20 @@ td {
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 fb90738..8eaa010 100644
--- a/templates/build.html
+++ b/templates/build.html
@@ -1,4 +1,4 @@
-
+
@@ -6,18 +6,15 @@
Build {{nightly}} {{target}}
-
- 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 3b1702a..e6084c0 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -1,4 +1,4 @@
-
+
@@ -25,6 +25,12 @@
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 5e5a9f5..c5678ce 100644
--- a/templates/target.html
+++ b/templates/target.html
@@ -5,11 +5,6 @@
{{target}} build history
-
Target build history for {{target}}
@@ -33,7 +28,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 %}
From 45f784eb5c566ad4984de965a1e579df45b29e34 Mon Sep 17 00:00:00 2001
From: Noratrieb <48135649+Noratrieb@users.noreply.github.com>
Date: Tue, 11 Nov 2025 19:35:03 +0100
Subject: [PATCH 5/5] Improve margin on mobile
---
static/index.css | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/static/index.css b/static/index.css
index a2ca57c..90ca657 100644
--- a/static/index.css
+++ b/static/index.css
@@ -1,9 +1,15 @@
:root {
color-scheme: light dark;
}
+
html {
font-family: sans-serif;
- margin: 20px;
+}
+
+@media screen and (min-width: 768px) {
+ html {
+ margin: 20px;
+ }
}
table {