polish error state for dependency report

fixes #10
This commit is contained in:
Sam Rijs 2018-02-11 17:22:00 +11:00
parent a540e7937d
commit ca367f54bb
4 changed files with 46 additions and 87 deletions

View file

@ -16,7 +16,6 @@ use ::models::repo::RepoPath;
#[derive(Clone, Copy, PartialEq)]
enum StatusFormat {
Html,
Json,
Svg
}
@ -49,7 +48,6 @@ impl Server {
router.add("/static/favicon.png", Route::Static(StaticFile::FaviconPng));
router.add("/repo/:site/:qual/:name", Route::Status(StatusFormat::Html));
router.add("/repo/:site/:qual/:name/status.json", Route::Status(StatusFormat::Json));
router.add("/repo/:site/:qual/:name/status.svg", Route::Status(StatusFormat::Svg));
Server { logger, engine, router: Arc::new(router) }
@ -131,19 +129,13 @@ impl Server {
future::Either::B(server.engine.analyze_dependencies(repo_path.clone()).then(move |analyze_result| {
match analyze_result {
Err(err) => {
if format != StatusFormat::Svg {
error!(logger, "error: {}", err);
let mut response = views::html::error::render("Failed to analyze repository",
"The repository you requested might be structured in an uncommon way that is not yet supported.");
response.set_status(StatusCode::InternalServerError);
future::Either::A(future::ok(response))
} else {
future::Either::A(future::ok(views::status_svg(None)))
}
let response = Server::status_format_analysis(None, format, repo_path);
future::ok(response)
},
Ok(analysis_outcome) => {
let response = Server::status_format_analysis(analysis_outcome, format, repo_path);
future::Either::B(future::ok(response))
let response = Server::status_format_analysis(Some(analysis_outcome), format, repo_path);
future::ok(response)
}
}
}))
@ -152,12 +144,10 @@ impl Server {
})
}
fn status_format_analysis(analysis_outcome: AnalyzeDependenciesOutcome, format: StatusFormat, repo_path: RepoPath) -> Response {
fn status_format_analysis(analysis_outcome: Option<AnalyzeDependenciesOutcome>, format: StatusFormat, repo_path: RepoPath) -> Response {
match format {
StatusFormat::Json =>
views::status_json(analysis_outcome),
StatusFormat::Svg =>
views::status_svg(Some(analysis_outcome)),
views::status_svg(analysis_outcome),
StatusFormat::Html =>
views::html::status::render(analysis_outcome, repo_path)
}

View file

@ -85,10 +85,35 @@ fn dependency_table(title: &str, deps: BTreeMap<CrateName, AnalyzedDependency>)
}
}
pub fn render(analysis_outcome: AnalyzeDependenciesOutcome, repo_path: RepoPath) -> Response {
fn render_failure(repo_path: RepoPath) -> Markup {
html! {
section class="hero is-light" {
div class="hero-head" (super::render_navbar())
div class="hero-body" {
div class="container" {
h1 class="title is-1" {
a href=(format!("{}/{}/{}", repo_path.site.to_base_uri(), repo_path.qual.as_ref(), repo_path.name.as_ref())) {
i class="fa fa-github" ""
(format!(" {} / {}", repo_path.qual.as_ref(), repo_path.name.as_ref()))
}
}
}
}
}
section class="section" {
div class="container" {
div class="notification is-danger" {
h2 class="title is-3" "Failed to analyze repository"
p "The repository you requested might be structured in an uncommon way that is not yet supported."
}
}
}
}
}
fn render_success(analysis_outcome: AnalyzeDependenciesOutcome, repo_path: RepoPath) -> Markup {
let self_path = format!("repo/{}/{}/{}", repo_path.site.as_ref(), repo_path.qual.as_ref(), repo_path.name.as_ref());
let status_base_url = format!("{}/{}", &super::SELF_BASE_URL as &str, self_path);
let title = format!("{} / {}", repo_path.qual.as_ref(), repo_path.name.as_ref());
let (hero_class, status_asset) = if analysis_outcome.any_outdated() {
("is-warning", assets::BADGE_OUTDATED_SVG.as_ref())
@ -98,7 +123,7 @@ pub fn render(analysis_outcome: AnalyzeDependenciesOutcome, repo_path: RepoPath)
let status_data_url = format!("data:image/svg+xml;base64,{}", Base64Display::standard(status_asset));
super::render_html(&title, html! {
html! {
section class=(format!("hero {}", hero_class)) {
div class="hero-head" (super::render_navbar())
div class="hero-body" {
@ -128,5 +153,15 @@ pub fn render(analysis_outcome: AnalyzeDependenciesOutcome, repo_path: RepoPath)
}
}
}
})
}
}
pub fn render(analysis_outcome: Option<AnalyzeDependenciesOutcome>, repo_path: RepoPath) -> Response {
let title = format!("{} / {}", repo_path.qual.as_ref(), repo_path.name.as_ref());
if let Some(outcome) = analysis_outcome {
super::render_html(&title, render_success(outcome, repo_path))
} else {
super::render_html(&title, render_failure(repo_path))
}
}

View file

@ -1,7 +1,4 @@
pub mod html;
mod status_json;
pub use self::status_json::status_json;
mod status_svg;
pub use self::status_svg::status_svg;

View file

@ -1,63 +0,0 @@
use std::collections::BTreeMap;
use hyper::Response;
use hyper::header::ContentType;
use semver::{Version, VersionReq};
use serde_json;
use ::engine::AnalyzeDependenciesOutcome;
#[derive(Debug, Serialize)]
struct AnalyzeDependenciesResponseDetail {
required: VersionReq,
latest: Option<Version>,
outdated: bool
}
#[derive(Debug, Serialize)]
struct AnalyzeDependenciesResponseSingle {
dependencies: BTreeMap<String, AnalyzeDependenciesResponseDetail>,
#[serde(rename="dev-dependencies")]
dev_dependencies: BTreeMap<String, AnalyzeDependenciesResponseDetail>,
#[serde(rename="build-dependencies")]
build_dependencies: BTreeMap<String, AnalyzeDependenciesResponseDetail>
}
#[derive(Debug, Serialize)]
struct AnalyzeDependenciesResponse {
crates: BTreeMap<String, AnalyzeDependenciesResponseSingle>
}
pub fn status_json(analysis_outcome: AnalyzeDependenciesOutcome) -> Response {
let crates = analysis_outcome.crates.into_iter().map(|(crate_name, analyzed_deps)| {
let single = AnalyzeDependenciesResponseSingle {
dependencies: analyzed_deps.main.into_iter()
.map(|(name, analyzed)| (name.into(), AnalyzeDependenciesResponseDetail {
outdated: analyzed.is_outdated(),
required: analyzed.required,
latest: analyzed.latest
})).collect(),
dev_dependencies: analyzed_deps.dev.into_iter()
.map(|(name, analyzed)| (name.into(), AnalyzeDependenciesResponseDetail {
outdated: analyzed.is_outdated(),
required: analyzed.required,
latest: analyzed.latest
})).collect(),
build_dependencies: analyzed_deps.build.into_iter()
.map(|(name, analyzed)| (name.into(), AnalyzeDependenciesResponseDetail {
outdated: analyzed.is_outdated(),
required: analyzed.required,
latest: analyzed.latest
})).collect()
};
(crate_name.into(), single)
});
let multi = AnalyzeDependenciesResponse {
crates: crates.collect()
};
Response::new()
.with_header(ContentType::json())
.with_body(serde_json::to_string(&multi).unwrap())
}