commit 68b85da189c1fa158329deb89b1b9110667f98b5
parent d7e35c1bf058b3cebb5231154b7e704bf53ebc6d
Author: Stefan Koch <programming@stefan-koch.name>
Date: Fri, 1 May 2020 10:13:21 +0200
allow cinderella to write build badges to a folder
Diffstat:
5 files changed, 109 insertions(+), 0 deletions(-)
diff --git a/assets/icon_build_error.png b/assets/icon_build_error.png
Binary files differ.
diff --git a/assets/icon_build_success.png b/assets/icon_build_success.png
Binary files differ.
diff --git a/src/config.rs b/src/config.rs
@@ -13,6 +13,7 @@ pub struct Configs<'a> {
pub struct CinderellaConfig {
pub email: Option<Email>,
pub secrets: Option<Secrets>,
+ pub dashboard: Option<Dashboard>,
}
#[derive(Deserialize, Debug)]
@@ -29,6 +30,11 @@ pub struct Secrets {
pub password: String,
}
+#[derive(Deserialize, Debug)]
+pub struct Dashboard {
+ pub folder: String,
+}
+
impl CinderellaConfig {
pub fn from_file(path: PathBuf) -> CinderellaConfig {
match fs::read_to_string(path) {
@@ -38,6 +44,7 @@ impl CinderellaConfig {
_ => CinderellaConfig {
email: None,
secrets: None,
+ dashboard: None,
}
}
}
@@ -92,6 +99,9 @@ mod tests {
password = "s"
to = "to@example.com"
from = "from@example.com"
+
+ [dashboard]
+ folder = "/var/www/cinderella"
"#;
let mut tmpfile = NamedTempFile::new().unwrap();
let f = tmpfile.as_file_mut();
@@ -105,6 +115,9 @@ mod tests {
assert_eq!(email.password, "s");
assert_eq!(email.to, "to@example.com");
assert_eq!(email.from, "from@example.com");
+
+ let dashboard = config.dashboard.unwrap();
+ assert_eq!(dashboard.folder, "/var/www/cinderella");
}
#[test]
diff --git a/src/dashboard.rs b/src/dashboard.rs
@@ -0,0 +1,74 @@
+use std::path::PathBuf;
+use std::io::prelude::Write;
+use std::fs::{self, File};
+
+pub enum BuildStatus {
+ Success,
+ Error(String),
+}
+
+static ICON_SUCCESS: &'static [u8] = include_bytes!("../assets/icon_build_success.png");
+static ICON_ERROR: &'static [u8] = include_bytes!("../assets/icon_build_error.png");
+
+pub fn generate_status_icon(project: &str, branch: &str, status: BuildStatus, dir: &PathBuf) {
+ let mut path = dir.clone();
+ path.push(project);
+
+ // ignore the AlreadyExists error
+ // other errors are also not important, because
+ // we recognize them once the file cannot be written
+ let _ = fs::create_dir(path.clone());
+
+ path.push(format!("{}.png", branch));
+
+ // TODO: Error handling
+ let mut buffer = File::create(path).unwrap();
+ match status {
+ BuildStatus::Success => buffer.write(ICON_SUCCESS).expect("Could not write to file"),
+ BuildStatus::Error(_) => buffer.write(ICON_ERROR).expect("Could not write to file"),
+ };
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use std::io::prelude::Read;
+
+ #[test]
+ fn generate_success_status_icon() {
+ let dir = tempfile::tempdir().unwrap();
+ let pathbuf = dir.path().to_path_buf();
+
+ generate_status_icon("myproject", "master", BuildStatus::Success, &pathbuf);
+
+ let mut buf = dir.path().to_path_buf();
+ buf.push("myproject");
+ buf.push("master.png");
+ assert!(buf.exists());
+
+ let mut f = File::open(buf).unwrap();
+ let mut buffer = Vec::new();
+ f.read_to_end(&mut buffer).unwrap();
+
+ assert_eq!(buffer, ICON_SUCCESS);
+ }
+
+ #[test]
+ fn generate_error_status_icon() {
+ let dir = tempfile::tempdir().unwrap();
+ let pathbuf = dir.path().to_path_buf();
+
+ generate_status_icon("my-other-project", "some-branch", BuildStatus::Error("Error Reason".to_string()), &pathbuf);
+
+ let mut buf = dir.path().to_path_buf();
+ buf.push("my-other-project");
+ buf.push("some-branch.png");
+ assert!(buf.exists());
+
+ let mut f = File::open(buf).unwrap();
+ let mut buffer = Vec::new();
+ f.read_to_end(&mut buffer).unwrap();
+
+ assert_eq!(buffer, ICON_ERROR);
+ }
+}+
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
@@ -13,6 +13,7 @@ mod execution;
mod mail;
mod crypto;
mod variables;
+mod dashboard;
pub use crate::config::ExecutionConfig;
@@ -20,6 +21,7 @@ use crate::config::{CinderellaConfig, Configs};
use crate::execution::{ExecutionResult, StepResult};
use crate::vcs::CodeSource;
use crate::vcs::WorkingCopy;
+use crate::dashboard::BuildStatus;
fn random_dir(base_path: &str) -> PathBuf {
let mut tempdir = PathBuf::from(base_path);
@@ -79,6 +81,9 @@ pub fn run(exec_config: &ExecutionConfig) {
let res = execution::execute(&pipelines, &variables);
match res {
+ ExecutionResult::Success(_) => {
+ write_build_status(BuildStatus::Success, exec_config, &cinderella_config);
+ },
ExecutionResult::Error(steps) => {
let mut output = String::new();
@@ -99,6 +104,8 @@ pub fn run(exec_config: &ExecutionConfig) {
mailer.send_mail(
&exec_config.name(),
&format!("Build failed:\n\n{}", output));
+
+ write_build_status(BuildStatus::Error("Build failed".to_string()), exec_config, &cinderella_config);
},
_ => (),
}
@@ -123,3 +130,16 @@ pub fn decrypt(cipherpath: &Path, plainpath: &Path, password: &str) {
_ => println!("Cannot decrypt, probably wrong password"),
}
}
+
+fn write_build_status(status: BuildStatus, exec_config: &ExecutionConfig, cinderella_config: &CinderellaConfig) {
+ let branch = match &exec_config.branch {
+ Some(branch) => branch,
+ None => "master",
+ };
+
+ if let Some(dashboard) = &cinderella_config.dashboard {
+ let project = &exec_config.name();
+ let outdir = PathBuf::from(&dashboard.folder);
+ dashboard::generate_status_icon(project, &branch, status, &outdir)
+ }
+}+
\ No newline at end of file