mirror of
https://github.com/Noratrieb/does-it-build.git
synced 2026-01-17 03:35:01 +01:00
Compare commits
No commits in common. "d15a7465584b5e90dc19126cc3d097683d055a63" and "25179d488df81b2d585970440b3f716717e9a8f4" have entirely different histories.
d15a746558
...
25179d488d
13 changed files with 119 additions and 261 deletions
64
Cargo.lock
generated
64
Cargo.lock
generated
|
|
@ -238,15 +238,6 @@ dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bs58"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
|
|
||||||
dependencies = [
|
|
||||||
"tinyvec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.19.0"
|
version = "3.19.0"
|
||||||
|
|
@ -457,16 +448,13 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"askama",
|
"askama",
|
||||||
"axum",
|
"axum",
|
||||||
"bs58",
|
|
||||||
"color-eyre",
|
"color-eyre",
|
||||||
"futures",
|
"futures",
|
||||||
"jiff",
|
"jiff",
|
||||||
"jsonwebtoken",
|
"jsonwebtoken",
|
||||||
"octocrab",
|
"octocrab",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"rootcause",
|
|
||||||
"serde",
|
"serde",
|
||||||
"sha2",
|
|
||||||
"sqlx",
|
"sqlx",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
|
@ -557,7 +545,7 @@ checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"spin 0.9.8",
|
"spin",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1169,7 +1157,7 @@ version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"spin 0.9.8",
|
"spin",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1803,30 +1791,6 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rootcause"
|
|
||||||
version = "0.10.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "12e6b4d9966d17c1e58cd682656e9e1551f19f421b07d7618723009445f06099"
|
|
||||||
dependencies = [
|
|
||||||
"hashbrown 0.16.0",
|
|
||||||
"indexmap",
|
|
||||||
"rootcause-internals",
|
|
||||||
"rustc-hash",
|
|
||||||
"spin 0.10.0",
|
|
||||||
"triomphe",
|
|
||||||
"unsize",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rootcause-internals"
|
|
||||||
version = "0.10.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ac64da7400123d25e3603dfd91a0ce7a78a3ad6e2d9400e6cdbb1aef0574c0d7"
|
|
||||||
dependencies = [
|
|
||||||
"triomphe",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rsa"
|
name = "rsa"
|
||||||
version = "0.9.8"
|
version = "0.9.8"
|
||||||
|
|
@ -2168,12 +2132,6 @@ dependencies = [
|
||||||
"lock_api",
|
"lock_api",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "spin"
|
|
||||||
version = "0.10.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spki"
|
name = "spki"
|
||||||
version = "0.7.3"
|
version = "0.7.3"
|
||||||
|
|
@ -2706,15 +2664,6 @@ dependencies = [
|
||||||
"tracing-log",
|
"tracing-log",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "triomphe"
|
|
||||||
version = "0.1.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dd69c5aa8f924c7519d6372789a74eac5b94fb0f8fcf0d4a97eb0bfc3e785f39"
|
|
||||||
dependencies = [
|
|
||||||
"unsize",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "try-lock"
|
name = "try-lock"
|
||||||
version = "0.2.5"
|
version = "0.2.5"
|
||||||
|
|
@ -2754,15 +2703,6 @@ version = "0.1.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
|
checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unsize"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4fa7a7a734c1a5664a662ddcea0b6c9472a21da8888c957c7f1eaa09dba7a939"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "untrusted"
|
name = "untrusted"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ axum = { version = "0.8.6", default-features = false, features = [
|
||||||
"tracing",
|
"tracing",
|
||||||
"macros",
|
"macros",
|
||||||
] }
|
] }
|
||||||
|
color-eyre = "0.6.3"
|
||||||
futures = "0.3.30"
|
futures = "0.3.30"
|
||||||
jiff = "0.2.16"
|
jiff = "0.2.16"
|
||||||
jsonwebtoken = { version = "9.3.1" }
|
jsonwebtoken = { version = "9.3.1" }
|
||||||
|
|
@ -22,7 +23,6 @@ reqwest = { version = "0.12.7", features = [
|
||||||
"rustls-tls",
|
"rustls-tls",
|
||||||
"http2",
|
"http2",
|
||||||
], default-features = false }
|
], default-features = false }
|
||||||
rootcause = "0.10.0"
|
|
||||||
serde = { version = "1.0.210", features = ["derive"] }
|
serde = { version = "1.0.210", features = ["derive"] }
|
||||||
sqlx = { version = "0.8.2", features = ["runtime-tokio", "sqlite"] }
|
sqlx = { version = "0.8.2", features = ["runtime-tokio", "sqlite"] }
|
||||||
tempfile = "3.12.0"
|
tempfile = "3.12.0"
|
||||||
|
|
@ -31,6 +31,4 @@ tracing = { version = "0.1.40", features = ["attributes"] }
|
||||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
bs58 = "0.5.1"
|
|
||||||
color-eyre = "0.6.3"
|
color-eyre = "0.6.3"
|
||||||
sha2 = "0.10.9"
|
|
||||||
|
|
|
||||||
32
build.rs
32
build.rs
|
|
@ -1,29 +1,6 @@
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use sha2::Digest;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Always rerun.
|
// Always rerun.
|
||||||
|
|
||||||
let index_css = include_str!("static/index.css");
|
|
||||||
let index_js = include_str!("static/index.js");
|
|
||||||
|
|
||||||
let index_css_name = get_file_ref("css", index_css);
|
|
||||||
let index_js_name = get_file_ref("js", index_js);
|
|
||||||
|
|
||||||
let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
|
|
||||||
|
|
||||||
std::fs::write(
|
|
||||||
out_dir.join("revs.rs"),
|
|
||||||
format!(
|
|
||||||
r#"
|
|
||||||
pub const INDEX_CSS_NAME: &str = "{index_css_name}";
|
|
||||||
pub const INDEX_JS_NAME: &str = "{index_js_name}";
|
|
||||||
"#
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let version = if let Ok(commit) = try_get_commit() {
|
let version = if let Ok(commit) = try_get_commit() {
|
||||||
match has_no_changes() {
|
match has_no_changes() {
|
||||||
Ok(true) => commit,
|
Ok(true) => commit,
|
||||||
|
|
@ -43,15 +20,6 @@ pub const INDEX_JS_NAME: &str = "{index_js_name}";
|
||||||
println!("cargo:rustc-env=GIT_COMMIT_SHORT={version_short}");
|
println!("cargo:rustc-env=GIT_COMMIT_SHORT={version_short}");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_file_ref(ext: &str, content: &str) -> String {
|
|
||||||
let mut hash = sha2::Sha256::new();
|
|
||||||
hash.update(content);
|
|
||||||
let digest = hash.finalize();
|
|
||||||
let rev = bs58::encode(digest).into_string();
|
|
||||||
let rev = &rev[..16];
|
|
||||||
format!("/{rev}.{ext}")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_get_commit() -> color_eyre::Result<String> {
|
fn try_get_commit() -> color_eyre::Result<String> {
|
||||||
if let Ok(overridden) = std::env::var("DOES_IT_BUILD_OVERRIDE_VERSION") {
|
if let Ok(overridden) = std::env::var("DOES_IT_BUILD_OVERRIDE_VERSION") {
|
||||||
return Ok(overridden);
|
return Ok(overridden);
|
||||||
|
|
|
||||||
68
src/build.rs
68
src/build.rs
|
|
@ -6,8 +6,11 @@ use std::{
|
||||||
time::{Duration, Instant, SystemTime},
|
time::{Duration, Instant, SystemTime},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use color_eyre::{
|
||||||
|
eyre::{bail, Context},
|
||||||
|
Result,
|
||||||
|
};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use rootcause::{prelude::ResultExt, report};
|
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
use tracing::{debug, error, info};
|
use tracing::{debug, error, info};
|
||||||
|
|
||||||
|
|
@ -15,7 +18,6 @@ use crate::{
|
||||||
db::{BuildMode, Db, FullBuildInfo, Status},
|
db::{BuildMode, Db, FullBuildInfo, Status},
|
||||||
nightlies::Nightlies,
|
nightlies::Nightlies,
|
||||||
notification::GitHubClient,
|
notification::GitHubClient,
|
||||||
Result,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CustomBuildFlags {
|
struct CustomBuildFlags {
|
||||||
|
|
@ -71,11 +73,11 @@ pub async fn background_builder(db: Db, github_client: GitHubClient) -> Result<(
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn background_builder_inner(db: &Db, github_client: &GitHubClient) -> Result<()> {
|
async fn background_builder_inner(db: &Db, github_client: &GitHubClient) -> Result<()> {
|
||||||
let nightlies = Nightlies::fetch().await.context("fetching nightlies")?;
|
let nightlies = Nightlies::fetch().await.wrap_err("fetching nightlies")?;
|
||||||
let already_finished = db
|
let already_finished = db
|
||||||
.finished_nightlies()
|
.finished_nightlies()
|
||||||
.await
|
.await
|
||||||
.context("fetching finished nightlies")?;
|
.wrap_err("fetching finished nightlies")?;
|
||||||
|
|
||||||
let next = nightlies.select_latest_to_build(&already_finished);
|
let next = nightlies.select_latest_to_build(&already_finished);
|
||||||
match next {
|
match next {
|
||||||
|
|
@ -83,12 +85,12 @@ async fn background_builder_inner(db: &Db, github_client: &GitHubClient) -> Resu
|
||||||
info!(%nightly, %mode, "Building next nightly");
|
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
|
.await
|
||||||
.context_with(|| format!("building targets for toolchain {nightly}"));
|
.wrap_err_with(|| format!("building targets for toolchain {nightly}"));
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
error!(%nightly, %mode, ?err, "Failed to build nightly");
|
error!(%nightly, %mode, ?err, "Failed to build nightly");
|
||||||
db.finish_nightly_as_broken(&nightly, mode, &format!("{err:?}"))
|
db.finish_nightly_as_broken(&nightly, mode, &format!("{err:?}"))
|
||||||
.await
|
.await
|
||||||
.context("marking nightly as broken")?;
|
.wrap_err("marking nightly as broken")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
|
@ -106,16 +108,16 @@ async fn targets_for_toolchain(toolchain: &Toolchain) -> Result<Vec<String>> {
|
||||||
.arg("target-list")
|
.arg("target-list")
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await
|
||||||
.context("failed to spawn rustc")?;
|
.wrap_err("failed to spawn rustc")?;
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
return Err(report!(
|
bail!(
|
||||||
"failed to get target-list from rustc: {:?}",
|
"failed to get target-list from rustc: {:?}",
|
||||||
String::from_utf8(output.stderr)
|
String::from_utf8(output.stderr)
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(String::from_utf8(output.stdout)
|
Ok(String::from_utf8(output.stdout)
|
||||||
.context("rustc target-list is invalid UTF-8")?
|
.wrap_err("rustc target-list is invalid UTF-8")?
|
||||||
.split_whitespace()
|
.split_whitespace()
|
||||||
.map(ToOwned::to_owned)
|
.map(ToOwned::to_owned)
|
||||||
.collect())
|
.collect())
|
||||||
|
|
@ -133,12 +135,9 @@ async fn install_toolchain(toolchain: &Toolchain, mode: BuildMode) -> Result<()>
|
||||||
.arg("minimal")
|
.arg("minimal")
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await
|
||||||
.context("failed to spawn rustup")?;
|
.wrap_err("failed to spawn rustup")?;
|
||||||
if !result.status.success() {
|
if !result.status.success() {
|
||||||
return Err(report!(
|
bail!("rustup failed: {:?}", String::from_utf8(result.stderr));
|
||||||
"rustup failed: {:?}",
|
|
||||||
String::from_utf8(result.stderr)
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
let result = Command::new("rustup")
|
let result = Command::new("rustup")
|
||||||
.arg("component")
|
.arg("component")
|
||||||
|
|
@ -148,12 +147,9 @@ async fn install_toolchain(toolchain: &Toolchain, mode: BuildMode) -> Result<()>
|
||||||
.arg(&toolchain.0)
|
.arg(&toolchain.0)
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await
|
||||||
.context("failed to spawn rustup")?;
|
.wrap_err("failed to spawn rustup")?;
|
||||||
if !result.status.success() {
|
if !result.status.success() {
|
||||||
return Err(report!(
|
bail!("rustup failed: {:?}", String::from_utf8(result.stderr));
|
||||||
"rustup failed: {:?}",
|
|
||||||
String::from_utf8(result.stderr)
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -169,12 +165,12 @@ async fn uninstall_toolchain(toolchain: &Toolchain) -> Result<()> {
|
||||||
.arg(&toolchain.0)
|
.arg(&toolchain.0)
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await
|
||||||
.context("failed to spawn rustup")?;
|
.wrap_err("failed to spawn rustup")?;
|
||||||
if !result.status.success() {
|
if !result.status.success() {
|
||||||
return Err(report!(
|
bail!(
|
||||||
"rustup toolchain remove failed: {:?}",
|
"rustup toolchain remove failed: {:?}",
|
||||||
String::from_utf8(result.stderr)
|
String::from_utf8(result.stderr)
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -195,7 +191,7 @@ pub async fn build_every_target_for_toolchain(
|
||||||
|
|
||||||
let targets = targets_for_toolchain(&toolchain)
|
let targets = targets_for_toolchain(&toolchain)
|
||||||
.await
|
.await
|
||||||
.context("failed to get targets")?;
|
.wrap_err("failed to get targets")?;
|
||||||
|
|
||||||
let results = futures::stream::iter(
|
let results = futures::stream::iter(
|
||||||
targets
|
targets
|
||||||
|
|
@ -212,7 +208,7 @@ pub async fn build_every_target_for_toolchain(
|
||||||
for target in targets {
|
for target in targets {
|
||||||
build_single_target(db, nightly, &target, mode, github_client)
|
build_single_target(db, nightly, &target, mode, github_client)
|
||||||
.await
|
.await
|
||||||
.context_with(|| format!("building target {target} for toolchain {toolchain}"))?;
|
.wrap_err_with(|| format!("building target {target} for toolchain {toolchain}"))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark it as finished, so we never have to build it again.
|
// Mark it as finished, so we never have to build it again.
|
||||||
|
|
@ -234,7 +230,7 @@ async fn build_single_target(
|
||||||
let existing = db
|
let existing = db
|
||||||
.build_status_full(nightly, target, mode)
|
.build_status_full(nightly, target, mode)
|
||||||
.await
|
.await
|
||||||
.context("getting existing build")?;
|
.wrap_err("getting existing build")?;
|
||||||
if existing.is_some() {
|
if existing.is_some() {
|
||||||
debug!("Build already exists");
|
debug!("Build already exists");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
@ -242,13 +238,13 @@ async fn build_single_target(
|
||||||
|
|
||||||
info!("Building target");
|
info!("Building target");
|
||||||
|
|
||||||
let tmpdir = tempfile::tempdir().context("creating temporary directory")?;
|
let tmpdir = tempfile::tempdir().wrap_err("creating temporary directory")?;
|
||||||
|
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
|
|
||||||
let result = build_target(tmpdir.path(), &Toolchain::from_nightly(nightly), target)
|
let result = build_target(tmpdir.path(), &Toolchain::from_nightly(nightly), target)
|
||||||
.await
|
.await
|
||||||
.context("running build")?;
|
.wrap_err("running build")?;
|
||||||
|
|
||||||
let full_build_info = FullBuildInfo {
|
let full_build_info = FullBuildInfo {
|
||||||
nightly: nightly.into(),
|
nightly: nightly.into(),
|
||||||
|
|
@ -302,14 +298,14 @@ async fn build_target(tmpdir: &Path, toolchain: &Toolchain, target: &str) -> Res
|
||||||
.current_dir(tmpdir)
|
.current_dir(tmpdir)
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await
|
||||||
.context("spawning cargo init")?;
|
.wrap_err("spawning cargo init")?;
|
||||||
if !init.status.success() {
|
if !init.status.success() {
|
||||||
return Err(report!("init failed: {}", String::from_utf8(init.stderr)?));
|
bail!("init failed: {}", String::from_utf8(init.stderr)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
let librs = tmpdir.join("src").join("lib.rs");
|
let librs = tmpdir.join("src").join("lib.rs");
|
||||||
std::fs::write(&librs, "#![no_std]\n")
|
std::fs::write(&librs, "#![no_std]\n")
|
||||||
.context_with(|| format!("writing to {}", librs.display()))?;
|
.wrap_err_with(|| format!("writing to {}", librs.display()))?;
|
||||||
|
|
||||||
async fn run(
|
async fn run(
|
||||||
toolchain: &Toolchain,
|
toolchain: &Toolchain,
|
||||||
|
|
@ -334,16 +330,14 @@ async fn build_target(tmpdir: &Path, toolchain: &Toolchain, target: &str) -> Res
|
||||||
*rustflags = Some(flags);
|
*rustflags = Some(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
let output = cmd
|
cmd.current_dir(tmpdir)
|
||||||
.current_dir(tmpdir)
|
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await
|
||||||
.context("spawning cargo build")?;
|
.wrap_err("spawning cargo build")
|
||||||
Ok(output)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut output = run(toolchain, target, &mut rustflags, tmpdir, "-Zbuild-std").await?;
|
let mut output = run(toolchain, target, &mut rustflags, tmpdir, "-Zbuild-std").await?;
|
||||||
let mut stderr = String::from_utf8(output.stderr).context("cargo stderr utf8")?;
|
let mut stderr = String::from_utf8(output.stderr).wrap_err("cargo stderr utf8")?;
|
||||||
|
|
||||||
let status = if output.status.success() {
|
let status = if output.status.success() {
|
||||||
Status::Pass
|
Status::Pass
|
||||||
|
|
@ -358,7 +352,7 @@ async fn build_target(tmpdir: &Path, toolchain: &Toolchain, target: &str) -> Res
|
||||||
"-Zbuild-std=core",
|
"-Zbuild-std=core",
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
stderr = String::from_utf8(output.stderr).context("cargo stderr utf8")?;
|
stderr = String::from_utf8(output.stderr).wrap_err("cargo stderr utf8")?;
|
||||||
|
|
||||||
if output.status.success() {
|
if output.status.success() {
|
||||||
Status::Pass
|
Status::Pass
|
||||||
|
|
|
||||||
78
src/db.rs
78
src/db.rs
|
|
@ -1,11 +1,12 @@
|
||||||
use std::{fmt::Display, str::FromStr};
|
use std::{fmt::Display, str::FromStr};
|
||||||
|
|
||||||
use rootcause::{prelude::ResultExt, report};
|
use color_eyre::{
|
||||||
|
eyre::{bail, Context},
|
||||||
|
Result,
|
||||||
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{migrate::Migrator, sqlite::SqliteConnectOptions, Pool, Sqlite};
|
use sqlx::{migrate::Migrator, sqlite::SqliteConnectOptions, Pool, Sqlite};
|
||||||
|
|
||||||
use crate::Result;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Db {
|
pub struct Db {
|
||||||
pub conn: Pool<Sqlite>,
|
pub conn: Pool<Sqlite>,
|
||||||
|
|
@ -111,13 +112,12 @@ pub struct NotificationIssue {
|
||||||
impl Db {
|
impl Db {
|
||||||
pub async fn open(path: &str) -> Result<Self> {
|
pub async fn open(path: &str) -> Result<Self> {
|
||||||
let db_opts = SqliteConnectOptions::from_str(path)
|
let db_opts = SqliteConnectOptions::from_str(path)
|
||||||
.context("parsing database URL")
|
.wrap_err("parsing database URL")?
|
||||||
.attach(format!("url: {path}"))?
|
|
||||||
.create_if_missing(true);
|
.create_if_missing(true);
|
||||||
|
|
||||||
let conn = Pool::connect_with(db_opts)
|
let conn = Pool::connect_with(db_opts)
|
||||||
.await
|
.await
|
||||||
.context_with(|| format!("opening db from `{path}`"))?;
|
.wrap_err_with(|| format!("opening db from `{path}`"))?;
|
||||||
Ok(Self { conn })
|
Ok(Self { conn })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -137,44 +137,38 @@ impl Db {
|
||||||
.bind(info.build_duration_ms)
|
.bind(info.build_duration_ms)
|
||||||
.execute(&self.conn)
|
.execute(&self.conn)
|
||||||
.await
|
.await
|
||||||
.context("inserting build info into database")?;
|
.wrap_err("inserting build info into database")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn history_for_target(&self, target: &str) -> Result<Vec<BuildInfo>> {
|
pub async fn history_for_target(&self, target: &str) -> Result<Vec<BuildInfo>> {
|
||||||
let history = sqlx::query_as::<_, BuildInfo>(
|
sqlx::query_as::<_, BuildInfo>(
|
||||||
"SELECT nightly, target, status, mode FROM build_info WHERE target = ?",
|
"SELECT nightly, target, status, mode FROM build_info WHERE target = ?",
|
||||||
)
|
)
|
||||||
.bind(target)
|
.bind(target)
|
||||||
.fetch_all(&self.conn)
|
.fetch_all(&self.conn)
|
||||||
.await
|
.await
|
||||||
.context("getting history for single target")
|
.wrap_err("getting history for single target")
|
||||||
.attach(format!("target: {target}"))?;
|
|
||||||
Ok(history)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn history_for_nightly(&self, nightly: &str) -> Result<Vec<BuildInfo>> {
|
pub async fn history_for_nightly(&self, nightly: &str) -> Result<Vec<BuildInfo>> {
|
||||||
let history = sqlx::query_as::<_, BuildInfo>(
|
sqlx::query_as::<_, BuildInfo>(
|
||||||
"SELECT nightly, target, status, mode FROM build_info WHERE nightly = ?",
|
"SELECT nightly, target, status, mode FROM build_info WHERE nightly = ?",
|
||||||
)
|
)
|
||||||
.bind(nightly)
|
.bind(nightly)
|
||||||
.fetch_all(&self.conn)
|
.fetch_all(&self.conn)
|
||||||
.await
|
.await
|
||||||
.context("getting history for single nightly")
|
.wrap_err("getting history for single nightly")
|
||||||
.attach(format!("nightly: {nightly}"))?;
|
|
||||||
Ok(history)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn nightly_info(&self, nightly: &str) -> Result<Vec<FinishedNightlyWithBroken>> {
|
pub async fn nightly_info(&self, nightly: &str) -> Result<Vec<FinishedNightlyWithBroken>> {
|
||||||
let info = sqlx::query_as::<_, FinishedNightlyWithBroken>(
|
sqlx::query_as::<_, FinishedNightlyWithBroken>(
|
||||||
"SELECT nightly, mode, is_broken, broken_error FROM finished_nightly WHERE nightly = ?",
|
"SELECT nightly, mode, is_broken, broken_error FROM finished_nightly WHERE nightly = ?",
|
||||||
)
|
)
|
||||||
.bind(nightly)
|
.bind(nightly)
|
||||||
.fetch_all(&self.conn)
|
.fetch_all(&self.conn)
|
||||||
.await
|
.await
|
||||||
.context("getting finished_nightly for single nightly")
|
.wrap_err("getting finished_nightly for single nightly")
|
||||||
.attach(format!("nightly: {nightly}"))?;
|
|
||||||
Ok(info)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn target_list(&self) -> Result<Vec<String>> {
|
pub async fn target_list(&self) -> Result<Vec<String>> {
|
||||||
|
|
@ -183,14 +177,11 @@ impl Db {
|
||||||
target: String,
|
target: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
let list = sqlx::query_as::<_, TargetName>(
|
sqlx::query_as::<_, TargetName>("SELECT DISTINCT target FROM build_info ORDER BY target")
|
||||||
"SELECT DISTINCT target FROM build_info ORDER BY target",
|
.fetch_all(&self.conn)
|
||||||
)
|
.await
|
||||||
.fetch_all(&self.conn)
|
.wrap_err("getting list of all targets")
|
||||||
.await
|
.map(|elems| elems.into_iter().map(|elem| elem.target).collect())
|
||||||
.context("getting list of all targets")?;
|
|
||||||
|
|
||||||
Ok(list.into_iter().map(|elem| elem.target).collect())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn nightly_list(&self) -> Result<Vec<String>> {
|
pub async fn nightly_list(&self) -> Result<Vec<String>> {
|
||||||
|
|
@ -199,14 +190,13 @@ impl Db {
|
||||||
nightly: String,
|
nightly: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
let list = sqlx::query_as::<_, NightlyName>(
|
sqlx::query_as::<_, NightlyName>(
|
||||||
"SELECT DISTINCT nightly FROM build_info ORDER BY nightly DESC",
|
"SELECT DISTINCT nightly FROM build_info ORDER BY nightly DESC",
|
||||||
)
|
)
|
||||||
.fetch_all(&self.conn)
|
.fetch_all(&self.conn)
|
||||||
.await
|
.await
|
||||||
.context("getting list of all nightlies")?;
|
.wrap_err("getting list of all targets")
|
||||||
|
.map(|elems| elems.into_iter().map(|elem| elem.nightly).collect())
|
||||||
Ok(list.into_iter().map(|elem| elem.nightly).collect())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn build_count(&self) -> Result<BuildStats> {
|
pub async fn build_count(&self) -> Result<BuildStats> {
|
||||||
|
|
@ -221,7 +211,7 @@ impl Db {
|
||||||
)
|
)
|
||||||
.fetch_all(&self.conn)
|
.fetch_all(&self.conn)
|
||||||
.await
|
.await
|
||||||
.context("getting total count of builds")?;
|
.wrap_err("getting list of all targets")?;
|
||||||
|
|
||||||
let count = |status| {
|
let count = |status| {
|
||||||
results
|
results
|
||||||
|
|
@ -252,8 +242,7 @@ impl Db {
|
||||||
.bind(mode)
|
.bind(mode)
|
||||||
.fetch_all(&self.conn)
|
.fetch_all(&self.conn)
|
||||||
.await
|
.await
|
||||||
.context("getting build status from DB")
|
.wrap_err("getting build status from DB")?;
|
||||||
.attach(format!("nightly: {nightly}, target: {target}"))?;
|
|
||||||
Ok(result.first().cloned())
|
Ok(result.first().cloned())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -262,7 +251,7 @@ impl Db {
|
||||||
sqlx::query_as::<_, FinishedNightly>("SELECT nightly, mode from finished_nightly")
|
sqlx::query_as::<_, FinishedNightly>("SELECT nightly, mode from finished_nightly")
|
||||||
.fetch_all(&self.conn)
|
.fetch_all(&self.conn)
|
||||||
.await
|
.await
|
||||||
.context("getting finished nightlies")?;
|
.wrap_err("fetching finished nightlies")?;
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
@ -275,10 +264,10 @@ impl Db {
|
||||||
.bind(mode)
|
.bind(mode)
|
||||||
.fetch_all(&self.conn)
|
.fetch_all(&self.conn)
|
||||||
.await
|
.await
|
||||||
.context("checking whether a nightly is finished")?;
|
.wrap_err("checking whether a nightly is finished")?;
|
||||||
|
|
||||||
if result.len() > 1 {
|
if result.len() > 1 {
|
||||||
return Err(report!("found more than one result for {nightly} {mode}"));
|
bail!("found more than one result for {nightly} {mode}");
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(result.len() == 1)
|
Ok(result.len() == 1)
|
||||||
|
|
@ -290,7 +279,7 @@ impl Db {
|
||||||
.bind(mode)
|
.bind(mode)
|
||||||
.execute(&self.conn)
|
.execute(&self.conn)
|
||||||
.await
|
.await
|
||||||
.context("inserting finished nightly")?;
|
.wrap_err("inserting finished nightly")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -306,7 +295,7 @@ impl Db {
|
||||||
.bind(error)
|
.bind(error)
|
||||||
.execute(&self.conn)
|
.execute(&self.conn)
|
||||||
.await
|
.await
|
||||||
.context("inserting finished broken nightly")?;
|
.wrap_err("inserting finished broken nightly")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -314,14 +303,13 @@ impl Db {
|
||||||
&self,
|
&self,
|
||||||
target: &str,
|
target: &str,
|
||||||
) -> Result<Option<NotificationIssue>> {
|
) -> Result<Option<NotificationIssue>> {
|
||||||
let notification = sqlx::query_as::<_, NotificationIssue>(
|
sqlx::query_as::<_, NotificationIssue>(
|
||||||
"SELECT * FROM notification_issues WHERE status = 'open' AND target = ?",
|
"SELECT * FROM notification_issues WHERE status = 'open' AND target = ?",
|
||||||
)
|
)
|
||||||
.bind(target)
|
.bind(target)
|
||||||
.fetch_optional(&self.conn)
|
.fetch_optional(&self.conn)
|
||||||
.await
|
.await
|
||||||
.context("finding existing notification")?;
|
.wrap_err("finding existing notification")
|
||||||
Ok(notification)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn insert_notification(&self, notification: NotificationIssue) -> Result<()> {
|
pub async fn insert_notification(&self, notification: NotificationIssue) -> Result<()> {
|
||||||
|
|
@ -337,7 +325,7 @@ impl Db {
|
||||||
.bind(notification.last_update_date)
|
.bind(notification.last_update_date)
|
||||||
.execute(&self.conn)
|
.execute(&self.conn)
|
||||||
.await
|
.await
|
||||||
.context("inserting new notification")?;
|
.wrap_err("inserting new notification")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -347,7 +335,7 @@ impl Db {
|
||||||
.bind(issue_number)
|
.bind(issue_number)
|
||||||
.execute(&self.conn)
|
.execute(&self.conn)
|
||||||
.await
|
.await
|
||||||
.context("marking notification as closed")?;
|
.wrap_err("marking notification as closed")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -361,7 +349,7 @@ impl Db {
|
||||||
.bind(issue_number)
|
.bind(issue_number)
|
||||||
.execute(&self.conn)
|
.execute(&self.conn)
|
||||||
.await
|
.await
|
||||||
.context("marking notification as closed")?;
|
.wrap_err("marking notification as closed")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
18
src/main.rs
18
src/main.rs
|
|
@ -4,15 +4,13 @@ mod nightlies;
|
||||||
mod notification;
|
mod notification;
|
||||||
mod web;
|
mod web;
|
||||||
|
|
||||||
|
use color_eyre::{eyre::WrapErr, Result};
|
||||||
use db::Db;
|
use db::Db;
|
||||||
use rootcause::{prelude::ResultExt, Report};
|
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
const VERSION: &str = env!("GIT_COMMIT");
|
const VERSION: &str = env!("GIT_COMMIT");
|
||||||
const VERSION_SHORT: &str = env!("GIT_COMMIT_SHORT");
|
const VERSION_SHORT: &str = env!("GIT_COMMIT_SHORT");
|
||||||
|
|
||||||
type Result<T, E = Report> = std::result::Result<T, E>;
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
main_inner().await
|
main_inner().await
|
||||||
|
|
@ -27,25 +25,25 @@ async fn main_inner() -> Result<()> {
|
||||||
db::MIGRATOR
|
db::MIGRATOR
|
||||||
.run(&db.conn)
|
.run(&db.conn)
|
||||||
.await
|
.await
|
||||||
.context("running migrations")?;
|
.wrap_err("running migrations")?;
|
||||||
|
|
||||||
let send_pings = std::env::var("GITHUB_SEND_PINGS")
|
let send_pings = std::env::var("GITHUB_SEND_PINGS")
|
||||||
.map(|_| true)
|
.map(|_| true)
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
let github_owner = std::env::var("GITHUB_OWNER").context("missing GITHUB_OWNER env var")?;
|
let github_owner = std::env::var("GITHUB_OWNER").wrap_err("missing GITHUB_OWNER env var")?;
|
||||||
let github_repo = std::env::var("GITHUB_REPO").context("missing GITHUB_REPO env var")?;
|
let github_repo = std::env::var("GITHUB_REPO").wrap_err("missing GITHUB_REPO env var")?;
|
||||||
let app_id = std::env::var("GITHUB_APP_ID")
|
let app_id = std::env::var("GITHUB_APP_ID")
|
||||||
.context("missing GITHUB_APP_ID env var")?
|
.wrap_err("missing GITHUB_APP_ID env var")?
|
||||||
.parse::<u64>()
|
.parse::<u64>()
|
||||||
.context("invalid GITHUB_APP_ID")?;
|
.wrap_err("invalid GITHUB_APP_ID")?;
|
||||||
let key = std::env::var("GITHUB_APP_PRIVATE_KEY")
|
let key = std::env::var("GITHUB_APP_PRIVATE_KEY")
|
||||||
.context("missing GITHUB_APP_PRIVATE_KEY env var")?;
|
.wrap_err("missing GITHUB_APP_PRIVATE_KEY env var")?;
|
||||||
let key = jsonwebtoken::EncodingKey::from_rsa_pem(key.as_bytes()).unwrap();
|
let key = jsonwebtoken::EncodingKey::from_rsa_pem(key.as_bytes()).unwrap();
|
||||||
|
|
||||||
let github_client = octocrab::Octocrab::builder()
|
let github_client = octocrab::Octocrab::builder()
|
||||||
.app(app_id.into(), key)
|
.app(app_id.into(), key)
|
||||||
.build()
|
.build()
|
||||||
.context("failed to create client")?;
|
.wrap_err("failed to create client")?;
|
||||||
|
|
||||||
let github_client = notification::GitHubClient::new(
|
let github_client = notification::GitHubClient::new(
|
||||||
send_pings,
|
send_pings,
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::hash::RandomState;
|
use std::hash::RandomState;
|
||||||
|
|
||||||
use rootcause::prelude::ResultExt;
|
use color_eyre::eyre::Context;
|
||||||
|
use color_eyre::Result;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::db::{BuildMode, FinishedNightly};
|
use crate::db::{BuildMode, FinishedNightly};
|
||||||
use crate::Result;
|
|
||||||
|
|
||||||
const EARLIEST_CUTOFF_DATE: &str = "2023-01-01";
|
const EARLIEST_CUTOFF_DATE: &str = "2023-01-01";
|
||||||
|
|
||||||
|
|
@ -15,21 +15,13 @@ pub struct Nightlies {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Nightlies {
|
impl Nightlies {
|
||||||
async fn get_body(url: &str) -> Result<String, rootcause::Report> {
|
pub async fn fetch() -> Result<Nightlies> {
|
||||||
Ok(reqwest::get(url)
|
let manifests = reqwest::get("https://static.rust-lang.org/manifests.txt")
|
||||||
.await
|
.await
|
||||||
.context("executing GET request")?
|
.wrap_err("fetching https://static.rust-lang.org/manifests.txt")?
|
||||||
.text()
|
.text()
|
||||||
.await
|
.await
|
||||||
.context("fetching body")?)
|
.wrap_err("fetching body of https://static.rust-lang.org/manifests.txt")?;
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn fetch() -> Result<Nightlies> {
|
|
||||||
let url = "https://static.rust-lang.org/manifests.txt";
|
|
||||||
let manifests = Nightlies::get_body(url)
|
|
||||||
.await
|
|
||||||
.context(format!("Fetching manifests.txt"))
|
|
||||||
.attach(format!("url: {url}"))?;
|
|
||||||
let mut all = nightlies_from_manifest(&manifests)
|
let mut all = nightlies_from_manifest(&manifests)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|date| date.as_str() > EARLIEST_CUTOFF_DATE)
|
.filter(|date| date.as_str() > EARLIEST_CUTOFF_DATE)
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
|
use color_eyre::eyre::{Context, Result};
|
||||||
use octocrab::models::issues::IssueStateReason;
|
use octocrab::models::issues::IssueStateReason;
|
||||||
use octocrab::models::IssueState;
|
use octocrab::models::IssueState;
|
||||||
use rootcause::prelude::ResultExt;
|
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
use crate::db::{Db, FullBuildInfo, NotificationIssue, NotificationStatus, Status};
|
use crate::db::{Db, FullBuildInfo, NotificationIssue, NotificationStatus, Status};
|
||||||
use crate::Result;
|
|
||||||
|
|
||||||
pub const TABLE_FILE: &str = file!();
|
pub const TABLE_FILE: &str = file!();
|
||||||
pub const TABLE_LINE: u32 = line!() + 1;
|
pub const TABLE_LINE: u32 = line!() + 1;
|
||||||
|
|
@ -56,11 +55,11 @@ impl GitHubClient {
|
||||||
.apps()
|
.apps()
|
||||||
.get_repository_installation(&owner, &repo)
|
.get_repository_installation(&owner, &repo)
|
||||||
.await
|
.await
|
||||||
.context_with(|| format!("getting installation for {owner}/{repo}"))?;
|
.wrap_err_with(|| format!("getting installation for {owner}/{repo}"))?;
|
||||||
|
|
||||||
let client = client
|
let client = client
|
||||||
.installation(installation.id)
|
.installation(installation.id)
|
||||||
.context("getting client for installation")?;
|
.wrap_err("getting client for installation")?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
send_pings,
|
send_pings,
|
||||||
|
|
@ -144,11 +143,11 @@ This update is sent after a month of inactivity.
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.context("creating update comment")?;
|
.wrap_err("creating update comment")?;
|
||||||
|
|
||||||
db.set_notification_last_update(issue.issue_number, jiff::Timestamp::now())
|
db.set_notification_last_update(issue.issue_number, jiff::Timestamp::now())
|
||||||
.await
|
.await
|
||||||
.context("updating last_update_date in DB")?;
|
.wrap_err("updating last_update_date in DB")?;
|
||||||
} else {
|
} else {
|
||||||
info!("Not sending update for {target}, since not enough time has elapsed since the last one");
|
info!("Not sending update for {target}, since not enough time has elapsed since the last one");
|
||||||
}
|
}
|
||||||
|
|
@ -167,13 +166,9 @@ This update is sent after a month of inactivity.
|
||||||
.issues()
|
.issues()
|
||||||
.create_label(target, "d73a4a", format!("Target: {target}"))
|
.create_label(target, "d73a4a", format!("Target: {target}"))
|
||||||
.await
|
.await
|
||||||
.context("creating label")?;
|
.wrap_err("creating label")?;
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
return Err(err)
|
|
||||||
.context("failed to fetch label label")
|
|
||||||
.map_err(Into::into)
|
|
||||||
}
|
}
|
||||||
|
Err(err) => return Err(err).wrap_err("failed to fetch label label"),
|
||||||
}
|
}
|
||||||
|
|
||||||
let pings = notify_usernames
|
let pings = notify_usernames
|
||||||
|
|
@ -212,7 +207,7 @@ This issue will be closed automatically when this target works again!"
|
||||||
))
|
))
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.context("failed to create issue")?;
|
.wrap_err("failed to create issue")?;
|
||||||
|
|
||||||
db.insert_notification(NotificationIssue {
|
db.insert_notification(NotificationIssue {
|
||||||
first_failed_nightly: nightly.into(),
|
first_failed_nightly: nightly.into(),
|
||||||
|
|
@ -222,7 +217,7 @@ This issue will be closed automatically when this target works again!"
|
||||||
last_update_date: Some(jiff::Timestamp::now().as_millisecond()),
|
last_update_date: Some(jiff::Timestamp::now().as_millisecond()),
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.context("inserting issue into DB")?;
|
.wrap_err("inserting issue into DB")?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -258,7 +253,7 @@ pub async fn notify_build_pass(
|
||||||
thanks for playing this round of Tier 3 rustc target breakage fixing! See y'all next time :3!\n\n<{url}>"),
|
thanks for playing this round of Tier 3 rustc target breakage fixing! See y'all next time :3!\n\n<{url}>"),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.context("creating update comment")?;
|
.wrap_err("creating update comment")?;
|
||||||
|
|
||||||
github_client
|
github_client
|
||||||
.issues()
|
.issues()
|
||||||
|
|
@ -267,7 +262,7 @@ pub async fn notify_build_pass(
|
||||||
.state_reason(IssueStateReason::Completed)
|
.state_reason(IssueStateReason::Completed)
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.context("closing issue")?;
|
.wrap_err("closing issue")?;
|
||||||
|
|
||||||
db.finish_notification(issue.issue_number).await?;
|
db.finish_notification(issue.issue_number).await?;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
57
src/web.rs
57
src/web.rs
|
|
@ -7,19 +7,15 @@ use axum::{
|
||||||
routing::get,
|
routing::get,
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
use rootcause::{prelude::ResultExt, Report};
|
use color_eyre::{eyre::Context, Result};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tracing::{error, info};
|
use tracing::{error, info};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::{BuildInfo, BuildMode, BuildStats, Db, Status},
|
db::{BuildInfo, BuildMode, BuildStats, Db, Status},
|
||||||
notification, Result,
|
notification,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod revs {
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/revs.rs"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
pub db: Db,
|
pub db: Db,
|
||||||
|
|
@ -32,8 +28,8 @@ pub async fn webserver(db: Db, notification_repo: String) -> Result<()> {
|
||||||
.route("/build", get(web_build))
|
.route("/build", get(web_build))
|
||||||
.route("/target", get(web_target))
|
.route("/target", get(web_target))
|
||||||
.route("/nightly", get(web_nightly))
|
.route("/nightly", get(web_nightly))
|
||||||
.route(revs::INDEX_CSS_NAME, get(index_css))
|
.route("/index.css", get(index_css))
|
||||||
.route(revs::INDEX_JS_NAME, get(index_js))
|
.route("/index.js", get(index_js))
|
||||||
.with_state(AppState {
|
.with_state(AppState {
|
||||||
db,
|
db,
|
||||||
notification_repo,
|
notification_repo,
|
||||||
|
|
@ -42,10 +38,7 @@ pub async fn webserver(db: Db, notification_repo: String) -> Result<()> {
|
||||||
info!("Serving website on port 3000 (commit {})", crate::VERSION);
|
info!("Serving website on port 3000 (commit {})", crate::VERSION);
|
||||||
|
|
||||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
||||||
axum::serve(listener, app)
|
axum::serve(listener, app).await.wrap_err("failed to serve")
|
||||||
.await
|
|
||||||
.context("failed to serve")?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
|
@ -332,39 +325,31 @@ async fn web_root(State(state): State<AppState>) -> impl IntoResponse {
|
||||||
Ok(Html(page.render().unwrap()).into_response())
|
Ok(Html(page.render().unwrap()).into_response())
|
||||||
}
|
}
|
||||||
|
|
||||||
render(state).await.unwrap_or_else(|err: Report| {
|
render(state)
|
||||||
error!(?err, "Error loading data for root page");
|
.await
|
||||||
StatusCode::INTERNAL_SERVER_ERROR.into_response()
|
.unwrap_or_else(|err: color_eyre::eyre::Error| {
|
||||||
})
|
error!(?err, "Error loading data for root page");
|
||||||
}
|
StatusCode::INTERNAL_SERVER_ERROR.into_response()
|
||||||
|
})
|
||||||
fn reply_static(body: &'static str, content_type: &'static str) -> impl IntoResponse {
|
|
||||||
(
|
|
||||||
[
|
|
||||||
(
|
|
||||||
axum::http::header::CONTENT_TYPE,
|
|
||||||
axum::http::HeaderValue::from_static(content_type),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
axum::http::header::CACHE_CONTROL,
|
|
||||||
axum::http::HeaderValue::from_static("public, max-age=31556952, immutable"),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
body,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn index_css() -> impl IntoResponse {
|
async fn index_css() -> impl IntoResponse {
|
||||||
reply_static(
|
(
|
||||||
|
[(
|
||||||
|
axum::http::header::CONTENT_TYPE,
|
||||||
|
axum::http::HeaderValue::from_static("text/css; charset=utf-8"),
|
||||||
|
)],
|
||||||
include_str!("../static/index.css"),
|
include_str!("../static/index.css"),
|
||||||
"text/css; charset=utf-8",
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn index_js() -> impl IntoResponse {
|
async fn index_js() -> impl IntoResponse {
|
||||||
reply_static(
|
(
|
||||||
|
[(
|
||||||
|
axum::http::header::CONTENT_TYPE,
|
||||||
|
axum::http::HeaderValue::from_static("application/javascript; charset=utf-8"),
|
||||||
|
)],
|
||||||
include_str!("../static/index.js"),
|
include_str!("../static/index.js"),
|
||||||
"application/javascript; charset=utf-8",
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Build {{nightly}} {{target}}</title>
|
<title>Build {{nightly}} {{target}}</title>
|
||||||
<link rel="stylesheet" href="{{ revs::INDEX_CSS_NAME }}" />
|
<link rel="stylesheet" href="/index.css" />
|
||||||
<script type="module" defer src="{{ revs::INDEX_JS_NAME }}"></script>
|
<script type="module" defer src="index.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>
|
<h1>
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Does it build?</title>
|
<title>Does it build?</title>
|
||||||
<link rel="stylesheet" href="{{ revs::INDEX_CSS_NAME }}" />
|
<link rel="stylesheet" href="index.css" />
|
||||||
<script type="module" defer src="{{ revs::INDEX_JS_NAME }}"></script>
|
<script type="module" defer src="index.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Does it build?</h1>
|
<h1>Does it build?</h1>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>{{nightly}} build history</title>
|
<title>{{nightly}} build history</title>
|
||||||
<link rel="stylesheet" href="{{ revs::INDEX_CSS_NAME }}" />
|
<link rel="stylesheet" href="/index.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Nightly build state for {{nightly}}</h1>
|
<h1>Nightly build state for {{nightly}}</h1>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>{{target}} build history</title>
|
<title>{{target}} build history</title>
|
||||||
<link rel="stylesheet" href="{{ revs::INDEX_CSS_NAME }}" />
|
<link rel="stylesheet" href="/index.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Target build history for {{target}}</h1>
|
<h1>Target build history for {{target}}</h1>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue