From 3f273f07a944c88587fb46263fdd4107d1ec7989 Mon Sep 17 00:00:00 2001 From: Dominik Nakamura Date: Mon, 18 Oct 2021 00:02:41 +0900 Subject: [PATCH] Provide an endpoint to create shields.io badges --- src/server/mod.rs | 10 +++++ src/server/views/mod.rs | 1 + src/server/views/shieldsio.rs | 70 +++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 src/server/views/shieldsio.rs diff --git a/src/server/mod.rs b/src/server/mod.rs index 52b5f7e..c2ba5ff 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -23,6 +23,7 @@ use crate::models::SubjectPath; enum StatusFormat { Html, Svg, + ShieldsIoJson, } #[derive(Debug, Clone, Copy)] @@ -63,6 +64,10 @@ impl App { "/repo/:site/:qual/:name/status.svg", Route::RepoStatus(StatusFormat::Svg), ); + router.add( + "/repo/:site/:qual/:name/shieldsio.json", + Route::RepoStatus(StatusFormat::ShieldsIoJson), + ); router.add("/crate/:name", Route::CrateRedirect); router.add( @@ -73,6 +78,10 @@ impl App { "/crate/:name/:version/status.svg", Route::CrateStatus(StatusFormat::Svg), ); + router.add( + "/crate/:name/:version/shieldsio.json", + Route::CrateStatus(StatusFormat::ShieldsIoJson), + ); App { logger, @@ -342,6 +351,7 @@ impl App { match format { StatusFormat::Svg => views::badge::response(analysis_outcome.as_ref()), StatusFormat::Html => views::html::status::render(analysis_outcome, subject_path), + StatusFormat::ShieldsIoJson => views::shieldsio::response(analysis_outcome.as_ref()), } } diff --git a/src/server/views/mod.rs b/src/server/views/mod.rs index efbdb0f..f6aedfa 100644 --- a/src/server/views/mod.rs +++ b/src/server/views/mod.rs @@ -1,2 +1,3 @@ pub mod badge; pub mod html; +pub mod shieldsio; diff --git a/src/server/views/shieldsio.rs b/src/server/views/shieldsio.rs new file mode 100644 index 0000000..ab74731 --- /dev/null +++ b/src/server/views/shieldsio.rs @@ -0,0 +1,70 @@ +use std::borrow::Cow; + +use hyper::header::CONTENT_TYPE; +use hyper::{Body, Response}; +use serde_json::json; + +use crate::engine::AnalyzeDependenciesOutcome; + +struct EndpointData<'a> { + message: Cow<'a, str>, + color: &'a str, +} + +fn data(analysis_outcome: Option<&AnalyzeDependenciesOutcome>) -> EndpointData<'_> { + match analysis_outcome { + Some(outcome) => { + if outcome.any_always_insecure() { + EndpointData { + message: "insecure".into(), + color: "#e05d44", + } + } else { + let (outdated, total) = outcome.outdated_ratio(); + + if outdated > 0 { + EndpointData { + message: format!("{} of {} outdated", outdated, total).into(), + color: "#dfb317", + } + } else if total > 0 { + if outcome.any_insecure() { + EndpointData { + message: "maybe insecure".into(), + color: "#88bb11", + } + } else { + EndpointData { + message: "up to date".into(), + color: "#44cc11", + } + } + } else { + EndpointData { + message: "none".into(), + color: "#44cc11", + } + } + } + } + None => EndpointData { + message: "unknown".into(), + color: "#9f9f9f", + }, + } +} + +pub fn response(analysis_outcome: Option<&AnalyzeDependenciesOutcome>) -> Response { + let data = data(analysis_outcome); + let json = json! {{ + "schemaVersion": 1, + "label": "dependencies", + "message": data.message, + "color": data.color + }}; + + Response::builder() + .header(CONTENT_TYPE, "application/json; charset=utf-8") + .body(Body::from(json.to_string())) + .unwrap() +}