mirror of
https://github.com/Noratrieb/does-it-build.git
synced 2026-01-16 11:15:01 +01:00
Compare commits
No commits in common. "45f784eb5c566ad4984de965a1e579df45b29e34" and "b244cf05b4eaad4b72a412d36e301df354fc87ca" have entirely different histories.
45f784eb5c
...
b244cf05b4
12 changed files with 102 additions and 213 deletions
80
Cargo.lock
generated
80
Cargo.lock
generated
|
|
@ -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",
|
||||
|
|
|
|||
24
Cargo.toml
24
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]
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
-- Add migration script here
|
||||
|
||||
ALTER TABLE notification_issues
|
||||
ADD COLUMN "last_update_date" INTEGER NULL;
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
20
src/db.rs
20
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<i64>,
|
||||
}
|
||||
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
39
src/github.rs
Normal file
39
src/github.rs
Normal file
|
|
@ -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<Self> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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(
|
|||
```
|
||||
|
||||
</details>
|
||||
|
||||
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(())
|
||||
|
|
|
|||
14
src/web.rs
14
src/web.rs
|
|
@ -101,10 +101,14 @@ async fn web_build(State(state): State<AppState>, Query(query): Query<BuildQuery
|
|||
rustflags: build.rustflags,
|
||||
version: crate::VERSION,
|
||||
status: build.status,
|
||||
build_date: build.build_date.and_then(|build_date| {
|
||||
jiff::Timestamp::from_millisecond(build_date)
|
||||
.ok()
|
||||
.map(|build_date| build_date.to_string())
|
||||
build_date: build.build_date.map(|build_date| {
|
||||
time::OffsetDateTime::from_unix_timestamp_nanos(build_date as i128 * 1000000)
|
||||
.map(|build_date| {
|
||||
build_date
|
||||
.format(&time::format_description::well_known::Rfc3339)
|
||||
.unwrap()
|
||||
})
|
||||
.unwrap()
|
||||
}),
|
||||
build_duration_s: build
|
||||
.build_duration_ms
|
||||
|
|
@ -286,7 +290,6 @@ async fn web_root(State(state): State<AppState>) -> impl IntoResponse {
|
|||
nightlies: Vec<String>,
|
||||
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<AppState>) -> impl IntoResponse {
|
|||
nightlies,
|
||||
version: crate::VERSION,
|
||||
build_count,
|
||||
notification_pr_url: notification::notification_pr_url(),
|
||||
};
|
||||
|
||||
Ok(Html(page.render().unwrap()).into_response())
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
|
|
@ -6,15 +6,18 @@
|
|||
<title>Build {{nightly}} {{target}}</title>
|
||||
<link rel="stylesheet" href="/index.css" />
|
||||
<script type="module" defer src="index.js"></script>
|
||||
<style>
|
||||
.build-indicator-big {
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>
|
||||
Build results for
|
||||
<a href="/nightly?nightly={{nightly}}">nightly-{{nightly}}</a>, target
|
||||
<a href="/target?target={{target}}">{{target}}</a> ({{mode}})
|
||||
</h1>
|
||||
<h1>Build results for nightly-{{nightly}} target {{target}} {{mode}}</h1>
|
||||
<a href="/">Home</a>
|
||||
<div class="{{status}} build-indicator-big">{{status}}</div>
|
||||
<div style="margin-top: 20px" class="{{status}} build-indicator-big">
|
||||
{{status}}
|
||||
</div>
|
||||
{% if let Some(rustflags) = rustflags %}
|
||||
<p>
|
||||
Using rustflags: <b><code>{{rustflags}}</code></b>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
|
|
@ -25,12 +25,6 @@
|
|||
history.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
🔔 does-it-build supports sending notifications to target maintainers via
|
||||
GitHub issues. You can add yourself with
|
||||
<a href="{{notification_pr_url}}">a PR</a>. 🔔
|
||||
</p>
|
||||
|
||||
<h1>Nightlies</h1>
|
||||
<ul>
|
||||
{% for nightly in nightlies.iter().take(5) %}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,11 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>{{target}} build history</title>
|
||||
<link rel="stylesheet" href="/index.css" />
|
||||
<style>
|
||||
.build-indicator-big {
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Target build history for {{target}}</h1>
|
||||
|
|
@ -28,7 +33,7 @@
|
|||
</p>
|
||||
<p>
|
||||
🔔 does-it-build supports sending notifications to target maintainers via GitHub issues.
|
||||
You can add yourself with <a href="{{notification_pr_url}}">a PR</a>. 🔔
|
||||
You can add yourself with <a href="{{notification_pr_url}}">a PR</a>.
|
||||
</p>
|
||||
{% if let Some(maintainers) = maintainers %}
|
||||
<p>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue