diff --git a/src/client/mod.rs b/src/client/mod.rs index 2e631d1b..20374e8c 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -1,8 +1,12 @@ +//! Jenkins Client + use failure; use regex::Regex; use reqwest::header::ContentType; use reqwest::{Body, Client, RequestBuilder, Response, StatusCode}; +use serde::{Serialize, Serializer}; use std::fmt::Debug; +use std::string::ToString; mod errors; pub use self::errors::Error; @@ -31,7 +35,82 @@ pub struct Jenkins { client: Client, user: Option, csrf_enabled: bool, - depth: u8, + pub(crate) depth: u8, +} + +/// Advanced query parameters supported by Jenkins +/// See https://www.cloudbees.com/blog/taming-jenkins-json-api-depth-and-tree +#[derive(Debug)] +pub enum AdvancedQuery { + /// depth query parameter + Depth(u8), + /// tree query parameter + Tree(TreeQueryParam), +} + +#[derive(Debug, Serialize)] +pub(crate) struct InternalAdvancedQueryParams { + depth: Option, + tree: Option, +} +impl From for InternalAdvancedQueryParams { + fn from(query: AdvancedQuery) -> Self { + match query { + AdvancedQuery::Depth(depth) => InternalAdvancedQueryParams { + depth: Some(depth), + tree: None, + }, + AdvancedQuery::Tree(tree) => InternalAdvancedQueryParams { + depth: None, + tree: Some(tree), + }, + } + } +} +/// Jenkins tree query parameter +#[derive(Debug)] +pub struct TreeQueryParam { + /// Name of the key at the root of this tree + pub keyname: String, + /// fields of this object + pub fields: Vec, + /// keys leading to child objects + pub subkeys: Vec, +} +impl Serialize for TreeQueryParam { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&self.to_string()) + } +} +impl ToString for TreeQueryParam { + fn to_string(&self) -> String { + match (self.fields.len(), self.subkeys.len()) { + (0, 0) => format!("{}", self.keyname), + (_, 0) => format!("{}[{}]", self.keyname, self.fields.join(",")), + (0, _) => format!( + "{}[{}]", + self.keyname, + self.subkeys + .iter() + .map(|t| t.to_string()) + .collect::>() + .join(",") + ), + (_, _) => format!( + "{}[{},{}]", + self.keyname, + self.fields.join(","), + self.subkeys + .iter() + .map(|t| t.to_string()) + .collect::>() + .join(",") + ), + } + } } impl Jenkins { @@ -61,13 +140,13 @@ impl Jenkins { self.get_with_params(path, &[("depth", &self.depth.to_string())]) } - pub(crate) fn get_with_params( + pub(crate) fn get_with_params( &self, path: &Path, - qps: &[(&str, &str)], + qps: T, ) -> Result { let mut query = self.client.get(&self.url_api_json(&path.to_string())); - query.query(qps); + query.query(&qps); Ok(Self::error_for_status(self.send(query)?)?) } diff --git a/src/job/mod.rs b/src/job/mod.rs index aba590ac..910db9cf 100644 --- a/src/job/mod.rs +++ b/src/job/mod.rs @@ -1,8 +1,9 @@ //! Jenkins Jobs use failure::Error; +use serde; -use client::{Name, Path}; +use client::{AdvancedQuery, InternalAdvancedQueryParams, Name, Path}; use queue::ShortQueueItem; use Jenkins; @@ -39,6 +40,27 @@ impl Jenkins { .json()?) } + /// Get a `Job` from it's `job_name`, specifying the depth or tree parameters + /// see https://www.cloudbees.com/blog/taming-jenkins-json-api-depth-and-tree + pub fn get_job_as<'a, J, T>( + &self, + job_name: J, + parameters: Option, + ) -> Result + where + J: Into>, + for<'de> T: serde::Deserialize<'de>, + { + Ok(self.get_with_params( + &Path::Job { + name: Name::Name(job_name.into().0), + configuration: None, + }, + parameters.map(InternalAdvancedQueryParams::from), + )? + .json()?) + } + /// Build a `Job` from it's `job_name` pub fn build_job<'a, J>(&self, job_name: J) -> Result where diff --git a/src/lib.rs b/src/lib.rs index 5d5c150d..1dd0dc07 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,8 +51,8 @@ extern crate regex; #[macro_use] extern crate log; -mod client; -pub use client::{error, Error, Jenkins, JenkinsBuilder}; +pub mod client; +pub use client::{Error, Jenkins, JenkinsBuilder}; #[macro_use] pub mod helpers;