forked from duckhq/duck
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
8 changed files
with
471 additions
and
1 deletion.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
use std::sync::Arc; | ||
|
||
use log::warn; | ||
use waithandle::{EventWaitHandle, WaitHandle}; | ||
|
||
use jenkins_api::{JenkinsBuilder, Jenkins}; | ||
use jenkins_api::build::{BuildStatus as JobBuildStatus, CommonBuild}; | ||
|
||
use crate::builds::{Build, BuildBuilder, BuildProvider, BuildStatus}; | ||
use crate::config::{JenkinsConfiguration, JenkinsCredentials}; | ||
use crate::providers::collectors::{Collector, CollectorInfo}; | ||
use crate::utils::{DuckResult}; | ||
|
||
mod validation; | ||
|
||
pub struct JenkinsCollector { | ||
client: Jenkins, | ||
jobs: Vec<String>, | ||
info: CollectorInfo | ||
} | ||
|
||
impl JenkinsCollector { | ||
pub fn new(config: &JenkinsConfiguration) -> Self { | ||
let mut builder = JenkinsBuilder::new(&config.server_url); | ||
let JenkinsCredentials::Basic { username, password } = &config.credentials; | ||
builder = builder.with_user(&username, Some(&password)); | ||
|
||
let jenkins = builder.build().expect("Failed to create a jenkins client"); | ||
|
||
return Self { | ||
client: jenkins, | ||
jobs: config.jobs.clone(), | ||
info: CollectorInfo { | ||
id: config.id.clone(), | ||
enabled: match config.enabled { | ||
Option::None => true, | ||
Option::Some(enabled) => enabled, | ||
}, | ||
provider: BuildProvider::Jenkins | ||
} | ||
} | ||
} | ||
} | ||
|
||
fn get_build_status(build: &CommonBuild) -> BuildStatus { | ||
if build.building { | ||
return BuildStatus::Running; | ||
} | ||
|
||
match build.result { | ||
Some(status) => { | ||
match status { | ||
JobBuildStatus::Success => BuildStatus::Success, | ||
JobBuildStatus::Aborted => BuildStatus::Canceled, | ||
JobBuildStatus::Failure => BuildStatus::Failed, | ||
JobBuildStatus::NotBuilt => BuildStatus::Queued, | ||
_ => BuildStatus::Unknown, | ||
} | ||
}, | ||
None => BuildStatus::Unknown | ||
} | ||
} | ||
|
||
impl Collector for JenkinsCollector { | ||
fn info(&self) -> &CollectorInfo { | ||
&self.info | ||
} | ||
|
||
fn collect(&self, handle: Arc<EventWaitHandle>, callback: &mut dyn FnMut(Build)) -> DuckResult<()> { | ||
|
||
for job_name in self.jobs.iter() { | ||
let job = match self.client.get_job(job_name) { | ||
Ok(j) => j, | ||
Err(_) => { | ||
warn!("Job '{}' couldn't be requested.", job_name); | ||
continue; | ||
} | ||
}; | ||
|
||
let build = match job.last_build { | ||
Some(b) => b, | ||
None => { | ||
warn!("The Job '{}' hasn't been built yet.", job_name); | ||
continue; | ||
} | ||
}; | ||
|
||
let build = match build.get_full_build(&self.client) { | ||
Ok(b) => b, | ||
Err(_) => { | ||
warn!("Failed to be full build info for build {} of '{}'", build.number, job_name); | ||
continue; | ||
} | ||
}; | ||
|
||
callback( | ||
BuildBuilder::new() | ||
.build_id(&build.id) | ||
.provider(BuildProvider::Jenkins) | ||
.collector(&self.info.id) | ||
.definition_id(job_name) | ||
.definition_name(&job.display_name) | ||
.build_number(format!("{}", &build.number)) | ||
.status(get_build_status(&build)) | ||
.url(&build.url) | ||
.build() | ||
.unwrap(), | ||
); | ||
|
||
// Wait for a little time between calls. | ||
if handle.wait(std::time::Duration::from_millis(300)).unwrap() { | ||
return Ok(()); | ||
} | ||
|
||
} | ||
|
||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
use crate::config::{JenkinsConfiguration, JenkinsCredentials, Validate}; | ||
use crate::utils::DuckResult; | ||
|
||
impl Validate for JenkinsConfiguration { | ||
fn validate(&self) -> DuckResult<()> { | ||
if self.server_url.is_empty() { | ||
return Err(format_err!("Server URL is empty.")); | ||
} | ||
|
||
match &self.credentials { | ||
JenkinsCredentials::Basic { username, password } => { | ||
if username.is_empty() { | ||
return Err(format_err!("Jenkins username is empty.")); | ||
} | ||
if password.is_empty() { | ||
return Err(format_err!("Jenkins password is empty.")); | ||
} | ||
} | ||
}; | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use crate::config::*; | ||
use crate::providers::DuckProviderCollection; | ||
use crate::utils::text::TestVariableProvider; | ||
|
||
#[test] | ||
#[should_panic(expected = "The id \\'\\' is invalid.")] | ||
fn should_return_error_if_jenkins_id_is_empty() { | ||
let config = Configuration::from_json( | ||
&TestVariableProvider::new(), | ||
r#" | ||
{ | ||
"collectors": [ | ||
{ | ||
"jenkins": { | ||
"id": "", | ||
"serverUrl": "http://jenkins:8080", | ||
"credentials": { | ||
"basic": { | ||
"username": "patrik", | ||
"password": "hunter1!" | ||
} | ||
} | ||
} | ||
} | ||
] | ||
} | ||
"#, | ||
) | ||
.unwrap(); | ||
|
||
let collection = DuckProviderCollection::new(); | ||
collection.get_collectors(&config).unwrap(); | ||
} | ||
#[test] | ||
#[should_panic(expected = "Jenkins server url is empty.")] | ||
fn should_return_error_if_jenkins_repository_is_empty() { | ||
let config = Configuration::from_json( | ||
&TestVariableProvider::new(), | ||
r#" | ||
{ | ||
"collectors": [ | ||
{ | ||
"jenkins": { | ||
"id": "duck_pipelines", | ||
"serverUrl": "", | ||
"credentials": { | ||
"basic": { | ||
"username": "patrik", | ||
"password": "hunter1!" | ||
} | ||
} | ||
} | ||
} | ||
] | ||
} | ||
"#, | ||
) | ||
.unwrap(); | ||
|
||
let collection = DuckProviderCollection::new(); | ||
collection.get_collectors(&config).unwrap(); | ||
} | ||
|
||
#[test] | ||
#[should_panic(expected = "Jenkins username is empty.")] | ||
fn should_return_error_if_jenkins_username_is_empty() { | ||
let config = Configuration::from_json( | ||
&TestVariableProvider::new(), | ||
r#" | ||
{ | ||
"collectors": [ | ||
{ | ||
"jenkins": { | ||
"id": "duck_pipelines", | ||
"serverUrl": "http://jenkins:8080", | ||
"credentials": | ||
{ | ||
"basic": { | ||
"username": "", | ||
"password": "hunter1!" | ||
} | ||
} | ||
} | ||
} | ||
] | ||
} | ||
"#, | ||
) | ||
.unwrap(); | ||
|
||
let collection = DuckProviderCollection::new(); | ||
collection.get_collectors(&config).unwrap(); | ||
} | ||
|
||
#[test] | ||
#[should_panic(expected = "Jenkins password is empty.")] | ||
fn should_return_error_if_jenkins_password_is_empty() { | ||
let config = Configuration::from_json( | ||
&TestVariableProvider::new(), | ||
r#" | ||
{ | ||
"collectors": [ | ||
{ | ||
"jenkins": { | ||
"id": "duck_pipelines", | ||
"serverUrl": "http://jenkins:8080", | ||
"credentials": | ||
{ | ||
"basic": { | ||
"username": "patriksvensson", | ||
"password": "" | ||
} | ||
} | ||
} | ||
} | ||
] | ||
} | ||
"#, | ||
) | ||
.unwrap(); | ||
|
||
let collection = DuckProviderCollection::new(); | ||
collection.get_collectors(&config).unwrap(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters