From patchwork Thu Jun 16 05:24:22 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Donnellan X-Patchwork-Id: 636201 X-Patchwork-Delegate: ruscur@russell.cc Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [103.22.144.68]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3rVWzt2CmFz9t0v for ; Thu, 16 Jun 2016 15:25:14 +1000 (AEST) Received: from ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 3rVWzt1T2RzDqmP for ; Thu, 16 Jun 2016 15:25:14 +1000 (AEST) X-Original-To: snowpatch@lists.ozlabs.org Delivered-To: snowpatch@lists.ozlabs.org Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 3rVWzq3BYxzDqld for ; Thu, 16 Jun 2016 15:25:10 +1000 (AEST) Received: from pps.filterd (m0098399.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.11/8.16.0.11) with SMTP id u5G5Nr8m009166 for ; Thu, 16 Jun 2016 01:25:08 -0400 Received: from e23smtp01.au.ibm.com (e23smtp01.au.ibm.com [202.81.31.143]) by mx0a-001b2d01.pphosted.com with ESMTP id 23jch6g333-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Thu, 16 Jun 2016 01:25:08 -0400 Received: from localhost by e23smtp01.au.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Thu, 16 Jun 2016 15:25:06 +1000 Received: from d23dlp03.au.ibm.com (202.81.31.214) by e23smtp01.au.ibm.com (202.81.31.207) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Thu, 16 Jun 2016 15:25:03 +1000 X-IBM-Helo: d23dlp03.au.ibm.com X-IBM-MailFrom: andrew.donnellan@au1.ibm.com X-IBM-RcptTo: snowpatch@lists.ozlabs.org Received: from d23relay09.au.ibm.com (d23relay09.au.ibm.com [9.185.63.181]) by d23dlp03.au.ibm.com (Postfix) with ESMTP id 8A6FF3578052 for ; Thu, 16 Jun 2016 15:25:02 +1000 (EST) Received: from d23av02.au.ibm.com (d23av02.au.ibm.com [9.190.235.138]) by d23relay09.au.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id u5G5P22U20709570 for ; Thu, 16 Jun 2016 15:25:02 +1000 Received: from d23av02.au.ibm.com (localhost [127.0.0.1]) by d23av02.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id u5G5P2qv023471 for ; Thu, 16 Jun 2016 15:25:02 +1000 Received: from ozlabs.au.ibm.com (ozlabs.au.ibm.com [9.192.253.14]) by d23av02.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id u5G5P25J023457 for ; Thu, 16 Jun 2016 15:25:02 +1000 Received: from ajd.ozlabs.ibm.com (haven.au.ibm.com [9.192.254.114]) (using TLSv1.2 with cipher AES128-SHA256 (128/128 bits)) (No client certificate requested) by ozlabs.au.ibm.com (Postfix) with ESMTPSA id 96BC1A0217 for ; Thu, 16 Jun 2016 15:24:31 +1000 (AEST) From: Andrew Donnellan To: snowpatch@lists.ozlabs.org Date: Thu, 16 Jun 2016 15:24:22 +1000 X-Mailer: git-send-email 2.8.1 X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 16061605-1617-0000-0000-0000012CFC35 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 16061605-1618-0000-0000-0000461480F8 Message-Id: <1466054662-31910-1-git-send-email-andrew.donnellan@au1.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2016-06-16_02:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 suspectscore=4 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1604210000 definitions=main-1606160064 Subject: [snowpatch] [PATCH v2] jenkins: refactor HTTP boilerplate X-BeenThere: snowpatch@lists.ozlabs.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: Continuous Integration for patch-based workflows List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: snowpatch-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "snowpatch" All our side-effect-free Jenkins API calls follow the same pattern of creating a hyper Client, making a GET request to the relevant JSON API endpoint, and decoding the returned JSON into a JSON Object (right now the top-level data types are all Objects). Refactor this boilerplate into a new method, get_api_json_object(). Additionally, rather than creating a new Client for every request, use the Client instantiated in main(). This also means that Jenkins will use HTTP proxy settings just like Patchwork. Signed-off-by: Andrew Donnellan --- Build tested only. V1->V2: * Use the hyper Client from main() rather than creating a new Client for every request --- src/jenkins.rs | 37 ++++++++++++++++--------------------- src/main.rs | 20 +++++++++++++------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/jenkins.rs b/src/jenkins.rs index 8ce9c3c..88297e4 100644 --- a/src/jenkins.rs +++ b/src/jenkins.rs @@ -43,6 +43,7 @@ pub trait CIBackend { // TODO: Separate out pub struct JenkinsBackend<'a> { pub base_url: &'a str, + pub hyper_client: &'a Client, // TODO: Authentication } @@ -54,12 +55,14 @@ impl<'a> CIBackend for JenkinsBackend<'a> { /// Returns Err when HTTP request fails or when no Location: header is returned fn start_test(&self, job_name: &str, params: Vec<(&str, &str)>) -> Result { - let client = Client::new(); // TODO: do we want to get this from somewhere else? let params = url::form_urlencoded::Serializer::new(String::new()) .extend_pairs(params) .finish(); - let res = client.post(&format!("{}/job/{}/buildWithParameters?{}", self.base_url, job_name, params)).send().expect("HTTP request error"); // TODO don't panic here + let res = self.hyper_client + .post(&format!("{}/job/{}/buildWithParameters?{}", + self.base_url, job_name, params)) + .send().expect("HTTP request error"); // TODO don't panic here match res.headers.get::() { Some(loc) => Ok(loc.to_string()), @@ -74,34 +77,26 @@ pub enum JenkinsBuildStatus { } impl<'a> JenkinsBackend<'a> { - pub fn get_build_url(&self, build_queue_entry: &str) -> Option { - let client = Client::new(); // TODO - let url = format!("{}api/json", build_queue_entry); - - let mut resp = client.get(&url).send().expect("HTTP request error"); // TODO don't panic here + fn get_api_json_object(&self, base_url: &str) -> rustc_serialize::json::Object { + // TODO: Don't panic on failure, fail more gracefully + let url = format!("{}api/json", base_url); + let mut resp = self.hyper_client.get(&url).send().expect("HTTP request error"); let mut result_str = String::new(); resp.read_to_string(&mut result_str) .unwrap_or_else(|err| panic!("Couldn't read from server: {}", err)); - let json = Json::from_str(&result_str).unwrap(); - let obj = json.as_object().unwrap(); - - match obj.get("executable") { + let json = Json::from_str(&result_str).unwrap_or_else(|err| panic!("Couldn't parse JSON from Jenkins: {}", err)); + json.as_object().unwrap().clone() + } + + pub fn get_build_url(&self, build_queue_entry: &str) -> Option { + match self.get_api_json_object(build_queue_entry).get("executable") { Some(exec) => Some(exec.as_object().unwrap().get("url").unwrap().as_string().unwrap().to_string()), None => None } } pub fn get_build_status(&self, build_url: &str) -> JenkinsBuildStatus { - let client = Client::new(); - let url = format!("{}api/json", build_url); - let mut resp = client.get(&url).send().expect("HTTP request error"); - let mut result_str = String::new(); - resp.read_to_string(&mut result_str) - .unwrap_or_else(|err| panic!("Couldn't read from server: {}", err)); - let json = Json::from_str(&result_str) - .unwrap_or_else(|err| panic!("Couldn't decode JSON: {}", err)); - - match json.as_object().unwrap().get("building").unwrap().as_boolean().unwrap() { + match self.get_api_json_object(build_url).get("building").unwrap().as_boolean().unwrap() { true => JenkinsBuildStatus::Running, false => JenkinsBuildStatus::Done, } diff --git a/src/main.rs b/src/main.rs index c34e165..9bb2064 100644 --- a/src/main.rs +++ b/src/main.rs @@ -89,9 +89,13 @@ struct Args { flag_project: String, } -fn run_tests(settings: &Config, project: &Project, tag: &str, branch_name: &str) -> Vec { +fn run_tests(settings: &Config, client: &Client, project: &Project, tag: &str, + branch_name: &str) -> Vec { let mut results: Vec = Vec::new(); - let jenkins = JenkinsBackend { base_url: &settings.jenkins.url }; + let jenkins = JenkinsBackend { + base_url: &settings.jenkins.url, + hyper_client: &client, + }; let project = project.clone(); for job_params in project.jobs.iter() { let job_name = job_params.get("job").unwrap(); @@ -131,7 +135,7 @@ fn run_tests(settings: &Config, project: &Project, tag: &str, branch_name: &str) results } -fn test_patch(settings: &Config, project: &Project, path: &Path) -> Vec { +fn test_patch(settings: &Config, client: &Arc, project: &Project, path: &Path) -> Vec { let repo = project.get_repo().unwrap(); let mut results: Vec = Vec::new(); if !path.is_file() { @@ -207,12 +211,14 @@ fn test_patch(settings: &Config, project: &Project, path: &Path) -> Vec panic!("Couldn't find project {}", args.flag_project), Some(project) => { - test_patch(&settings, &project, &patch); + test_patch(&settings, &client, &project, &patch); } } @@ -295,7 +301,7 @@ fn main() { None => panic!("Couldn't find project {}", &series.project.linkname), Some(project) => { let patch = patchwork.get_patch(&series); - test_patch(&settings, &project, &patch); + test_patch(&settings, &client, &project, &patch); } } @@ -324,7 +330,7 @@ fn main() { }, Some(project) => { let patch = patchwork.get_patch(&series); - let results = test_patch(&settings, &project, &patch); + let results = test_patch(&settings, &client, &project, &patch); // Delete the temporary directory with the patch in it fs::remove_dir_all(patch.parent().unwrap()).unwrap_or_else( |err| error!("Couldn't delete temp directory: {}", err));