From 916965ab13d4c9273089162a04d730f3061c6d18 Mon Sep 17 00:00:00 2001 From: iximeow Date: Sat, 24 Jun 2023 20:22:21 -0700 Subject: and now the index page is useful --- src/dbctx.rs | 14 ++++++++++++ src/main.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 73 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/dbctx.rs b/src/dbctx.rs index 476c3fc..c9454fc 100644 --- a/src/dbctx.rs +++ b/src/dbctx.rs @@ -221,6 +221,20 @@ impl DbCtx { .map_err(|e| e.to_string()) } + pub fn remote_by_id(&self, id: u64) -> Result, String> { + self.conn.lock() + .unwrap() + .query_row("select * from remotes where id=?1", [id], |row| { + let (id, repo_id, remote_path, remote_api, remote_url, remote_git_url, notifier_config_path) = row.try_into().unwrap(); + + Ok(Remote { + id, repo_id, remote_path, remote_api, remote_url, remote_git_url, notifier_config_path + }) + }) + .optional() + .map_err(|e| e.to_string()) + } + pub fn repo_id_by_remote(&self, remote_id: u64) -> Result, String> { self.conn.lock() .unwrap() diff --git a/src/main.rs b/src/main.rs index 7f89ced..862e021 100644 --- a/src/main.rs +++ b/src/main.rs @@ -110,6 +110,34 @@ fn duration_as_human_string(duration_ms: u64) -> String { } } +/// try producing a url for whatever caused this job to be started, if possible +fn commit_url(job: &Job, commit_sha: &str, ctx: &Arc) -> Option { + let remote = ctx.remote_by_id(job.remote_id).expect("query succeeds").expect("existing job references existing remote"); + + match remote.remote_api.as_str() { + "github" => { + Some(format!("{}/commit/{}", remote.remote_url, commit_sha)) + }, + "email" => { + None + }, + _ => { + None + } + } +} + +/// produce a url to the ci.butactuallyin.space job details page +fn job_url(job: &Job, commit_sha: &str, ctx: &Arc) -> String { + let remote = ctx.remote_by_id(job.remote_id).expect("query succeeds").expect("existing job references existing remote"); + + if remote.remote_api != "github" { + eprintln!("job url for remote type {} can't be constructed, i think", &remote.remote_api); + } + + format!("{}/{}", &remote.remote_path, commit_sha) +} + fn parse_push_event(body: serde_json::Value) -> Result { let body = body.as_object() .ok_or(GithubHookError::BodyNotObject)?; @@ -231,13 +259,19 @@ async fn handle_ci_index(State(ctx): State>) -> impl IntoResponse { Ok(repos) => repos, Err(e) => { eprintln!("failed to get repos: {:?}", e); - return (StatusCode::INTERNAL_SERVER_ERROR, "gonna feel that one tomorrow".to_string()); + return (StatusCode::INTERNAL_SERVER_ERROR, Html("gonna feel that one tomorrow".to_string())); } }; let mut response = String::new(); response.push_str("\n"); + response.push_str("\n"); response.push_str("

builds and build accessories

\n"); match repos.len() { @@ -246,14 +280,16 @@ async fn handle_ci_index(State(ctx): State>) -> impl IntoResponse { other => { response.push_str(&format!("

{} repos configured

\n", other)); }, } - response.push_str("\n"); + response.push_str("
"); response.push_str("\n"); - let headings = ["repo", "last build", "build commit", "duration", "status", "result"]; + let headings = ["repo", "last build", "job", "build commit", "duration", "status", "result"]; for heading in headings { - response.push_str(&format!("", heading)); + response.push_str(&format!("", heading)); } response.push_str("\n"); + let mut row_num = 0; + for repo in repos { let mut most_recent_job: Option = None; @@ -269,6 +305,12 @@ async fn handle_ci_index(State(ctx): State>) -> impl IntoResponse { let row_html: String = match most_recent_job { Some(job) => { let job_commit = ctx.commit_sha(job.commit_id).expect("job has a commit"); + let commit_html = match commit_url(&job, &job_commit, &ctx) { + Some(url) => format!("{}", url, &job_commit), + None => job_commit.clone() + }; + + let job_html = format!("{}", job_url(&job, &job_commit, &ctx), job.id); let last_build_time = Utc.timestamp_millis_opt(job.created_time as i64).unwrap().to_rfc2822(); let duration = if let Some(start_time) = job.start_time { @@ -293,20 +335,18 @@ async fn handle_ci_index(State(ctx): State>) -> impl IntoResponse { Some(_) => "fail", None => match job.state { JobState::Pending => { "unstarted" }, - JobState::Started => { "in progress" }, + JobState::Started => { "in progress" }, _ => { "unreported" } } }; - let entries = [repo.name.as_str(), last_build_time.as_str(), job_commit.as_str(), &duration, &status, &result]; + let entries = [repo.name.as_str(), last_build_time.as_str(), job_html.as_str(), commit_html.as_str(), &duration, &status, &result]; let entries = entries.iter().chain(std::iter::repeat(&"")).take(headings.len()); let mut row_html = String::new(); - row_html.push_str(""); for entry in entries { - row_html.push_str(&format!("", entry)); + row_html.push_str(&format!("", entry)); } - row_html.push_str(""); row_html } None => { @@ -314,21 +354,26 @@ async fn handle_ci_index(State(ctx): State>) -> impl IntoResponse { let entries = entries.iter().chain(std::iter::repeat(&"")).take(headings.len()); let mut row_html = String::new(); - row_html.push_str(""); for entry in entries { - row_html.push_str(&format!("", entry)); + row_html.push_str(&format!("", entry)); } - row_html.push_str(""); row_html } }; + let row_index = row_num % 2; + response.push_str(&format!("", ["even-row", "odd-row"][row_index])); response.push_str(&row_html); + response.push_str(""); + response.push('\n'); + + row_num += 1; } + response.push_str("
{}{}
{}{}
{}{}
"); response.push_str(""); - (StatusCode::OK, response) + (StatusCode::OK, Html(response)) } async fn handle_commit_status(Path(path): Path<(String, String, String)>, State(ctx): State>) -> impl IntoResponse { @@ -366,7 +411,7 @@ async fn handle_commit_status(Path(path): Path<(String, String, String)>, State( let deployed = false; - let head = format!("ci.butactuallin.space - {}", repo_name); + let head = format!("ci.butactuallyin.space - {}", repo_name); let remote_commit_elem = format!("{}", &remote_path, &sha, &sha); let status_elem = match state { JobState::Pending | JobState::Started => { -- cgit v1.1