From 0d00fb4cfd4164c987d0a2b40fb3b1d9230be089 Mon Sep 17 00:00:00 2001 From: "R. Tyler Croy" Date: Sun, 12 Mar 2023 19:48:54 -0700 Subject: [PATCH] Implement support for inline commands definition for projects I think this will help the task definitions that don't line up to a development project --- examples/synchronik.d/project-inline.yml | 11 ++- src/server/config.rs | 93 +++++++++++++++++++----- src/server/models/run.rs | 13 +--- src/server/routes.rs | 15 ++-- 4 files changed, 87 insertions(+), 45 deletions(-) diff --git a/examples/synchronik.d/project-inline.yml b/examples/synchronik.d/project-inline.yml index 93f4ea4..ee79a5f 100644 --- a/examples/synchronik.d/project-inline.yml +++ b/examples/synchronik.d/project-inline.yml @@ -3,9 +3,8 @@ projects: 'inline-config': description: | An inline configured project - filename: 'ci.synchronik.yml' - scm: - github: - owner: 'rtyler' - repo: 'synchronik' - ref: 'main' + inline: + needs: + - git + commands: + - 'whoami' diff --git a/src/server/config.rs b/src/server/config.rs index abddb3a..984068b 100644 --- a/src/server/config.rs +++ b/src/server/config.rs @@ -10,7 +10,7 @@ use crate::AppState; /* * Representation of the Synchronik YAML format */ -#[derive(Clone, Debug, Deserialize)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct Yml { pub needs: Vec, pub commands: Vec, @@ -19,6 +19,11 @@ pub struct Yml { #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "lowercase")] pub enum Scm { + /* + * The Nonexistent Scm is used for stubbing out the Scm properties when + * inlining configuration + */ + Nonexistent, GitHub { owner: String, repo: String, @@ -31,11 +36,22 @@ pub enum Scm { #[serde(rename_all = "lowercase")] pub struct Project { description: String, - pub filename: String, - #[serde(with = "serde_yaml::with::singleton_map")] + /* + * Used for optionally defining an inline Yml configuration + */ + inline: Option, + pub filename: Option, + #[serde(default = "default_scm", with = "serde_yaml::with::singleton_map")] pub scm: Scm, } +/* + * Simple default scm for use when nothing has been otherwise defined + */ +fn default_scm() -> Scm { + Scm::Nonexistent +} + /* * Internal representation of an Agent that has been "loaded" by the server * @@ -86,7 +102,7 @@ pub struct AgentConfig { pub url: Url, } -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Default, Deserialize, Serialize)] pub struct ServerConfig { pub agents: HashMap, pub projects: HashMap, @@ -157,21 +173,6 @@ impl ServerConfig { } } -/* - * Default trait implementation for ServerConfig, will result in an empty set of agents and - * projects - * - * Not really useful for anything other than tests - */ -impl Default for ServerConfig { - fn default() -> Self { - Self { - agents: HashMap::default(), - projects: HashMap::default(), - } - } -} - /* * Merge two Valus from */ @@ -252,4 +253,58 @@ mod tests { } } } + + #[test] + fn parse_config_with_scm() { + let conf = r#" +--- +agents: + 'Local': + url: 'http://localhost:9000' +projects: + 'synchronik': + description: | + Self-hosted project + filename: 'ci.synchronik.yml' + scm: + github: + owner: 'rtyler' + repo: 'synchronik' + ref: 'main' +"#; + let value: ServerConfig = serde_yaml::from_str(&conf).expect("Failed to parse"); + assert_eq!(value.agents.len(), 1); + } + + #[test] + fn parse_config_inline() { + let conf = r#" +--- +agents: + 'Local': + url: 'http://localhost:9000' +projects: + 'synchronik': + description: | + Self-hosted project + inline: + needs: + - git + commands: + - 'whoami' +"#; + let value: ServerConfig = serde_yaml::from_str(&conf).expect("Failed to parse"); + assert_eq!(value.agents.len(), 1); + assert_eq!(value.projects.len(), 1); + + let project = value.projects.get("synchronik").unwrap(); + match &project.inline { + Some(yml) => { + assert!(yml.commands.contains(&"whoami".to_string())); + } + None => { + assert!(false); + } + } + } } diff --git a/src/server/models/run.rs b/src/server/models/run.rs index c2730e1..4284b29 100644 --- a/src/server/models/run.rs +++ b/src/server/models/run.rs @@ -2,7 +2,7 @@ use sqlx::SqlitePool; use crate::models::*; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct Run { run: RunRow, project: Project, @@ -91,17 +91,6 @@ impl Run { } } -impl Default for Run { - fn default() -> Self { - Self { - run: RunRow::default(), - project: Project::default(), - scm_info: ScmInfo::default(), - definition: RunDefinition::default(), - } - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/src/server/routes.rs b/src/server/routes.rs index cdb7dec..6f41b5e 100644 --- a/src/server/routes.rs +++ b/src/server/routes.rs @@ -74,21 +74,20 @@ pub mod api { if let Some(project) = state.config.projects.get(&name) { match &project.scm { + Scm::Nonexistent => {} Scm::GitHub { owner, repo, scm_ref, } => { - debug!( - "Fetching the file {} from {}/{}", - &project.filename, owner, repo - ); + let filename = match &project.filename { + None => "synchronik.yml".to_string(), + Some(filename) => filename.to_string(), + }; + debug!("Fetching the file {} from {}/{}", filename, owner, repo); let res = octocrab::instance() .repos(owner, repo) - .raw_file( - octocrab::params::repos::Commitish(scm_ref.into()), - &project.filename, - ) + .raw_file(octocrab::params::repos::Commitish(scm_ref.into()), filename) .await?; let config_file: Yml = serde_yaml::from_str(&res.text().await?)?; debug!("text: {:?}", config_file);