Skip to content

Loading…

Extract upload functionality + small cleanups #7

Closed
wants to merge 9 commits into from

2 participants

@lacostej
Jenkins member

The original purpose of the changes was to extract the upload part into a separate class so that I could verify the uploading from the command line.

There are a couple of cleanups as well.

Let me know if you prefer me to split the commits into different pull requests.

@nheagy
Jenkins member

Definitely needs to be separate so that it's clearer what's going on and why.

@lacostej
Jenkins member
@lacostej
Jenkins member

I've merged the relevant commits and created branches so that you can see the changes
1. pull from https://github.com/lacostej/testflight-plugin/tree/misc-pom-fixes to get the misc pom fixes
2. pull from https://github.com/lacostej/testflight-plugin/tree/extract-reporter-class to get the reporter class extraction
3. pull from https://github.com/lacostej/testflight-plugin/tree/reporter-class-and-expand-envvars-in-buildnotes (depends on #2) to also get the envvars expansion for buildnotes.

Is that enough or do you want me to close this pull request and send you pull requests for the invididual branches ?

@lacostej
Jenkins member

Closing this request and sent 3 pulls instead.

@lacostej lacostej closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 31, 2012
  1. @lacostej

    Git ignore

    lacostej committed
  2. @lacostej
  3. @lacostej

    POM refactoring

    lacostej committed
  4. @lacostej
Commits on Apr 3, 2012
  1. @lacostej
  2. @lacostej

    Fix NPE

    lacostej committed
  3. @lacostej

    Cleanup: rename field

    lacostej committed
  4. @lacostej
Commits on Apr 6, 2012
  1. @lacostej

    Expand envvars in build notes

    lacostej committed
View
4 .gitignore
@@ -0,0 +1,4 @@
+.idea
+*.iml
+target
+*.log
View
27 pom.xml
@@ -13,14 +13,21 @@
<version>1.3.2-SNAPSHOT</version>
<packaging>hpi</packaging>
- <!-- get every artifact through maven.glassfish.org, which proxies all the artifacts that we need -->
+ <!-- get every artifact through repo.jenkins-ci.org, which proxies all the artifacts that we need -->
<repositories>
<repository>
- <id>m.g.o-public</id>
- <url>http://maven.glassfish.org/content/groups/public/</url>
+ <id>repo.jenkins-ci.org</id>
+ <url>http://repo.jenkins-ci.org/public/</url>
</repository>
</repositories>
+ <pluginRepositories>
+ <pluginRepository>
+ <id>repo.jenkins-ci.org</id>
+ <url>http://repo.jenkins-ci.org/public/</url>
+ </pluginRepository>
+ </pluginRepositories>
+
<scm>
<connection>scm:git:ssh://github.com/jenkinsci/testflight-plugin.git</connection>
<developerConnection>scm:git:ssh://git@github.com/jenkinsci/testflight-plugin.git</developerConnection>
@@ -37,24 +44,18 @@
<email>joshuacweinberg@gmail.com</email>
</developer>
</developers>
- <pluginRepositories>
- <pluginRepository>
- <id>m.g.o-public</id>
- <url>http://maven.glassfish.org/content/groups/public/</url>
- </pluginRepository>
- </pluginRepositories>
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
- <version>4.0.1</version>
+ <version>${httpclient.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
- <version>4.0.1</version>
+ <version>${httpclient.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -64,4 +65,8 @@
<scope>compile</scope>
</dependency>
</dependencies>
+
+ <properties>
+ <httpclient.version>4.0.1</httpclient.version>
+ </properties>
</project>
View
92 src/main/java/testflight/TestflightRecorder.java
@@ -9,23 +9,9 @@
import hudson.tasks.*;
import hudson.util.RunList;
import org.apache.commons.collections.Predicate;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpHost;
-import org.apache.http.HttpResponse;
-import org.apache.http.auth.AuthScope;
-import org.apache.http.auth.UsernamePasswordCredentials;
-import org.apache.http.client.CredentialsProvider;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.conn.params.ConnRoutePNames;
-import org.apache.http.entity.mime.MultipartEntity;
-import org.apache.http.entity.mime.content.FileBody;
-import org.apache.http.entity.mime.content.StringBody;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.json.simple.parser.JSONParser;
import org.kohsuke.stapler.DataBoundConstructor;
import java.io.*;
import java.util.*;
-import org.apache.http.auth.Credentials;
import net.sf.json.JSONObject;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
@@ -105,7 +91,7 @@ public int getProxyPort()
{
return proxyPort;
}
-
+
@DataBoundConstructor
public TestflightRecorder(String apiToken, String teamToken, Boolean notifyTeam, String buildNotes, String filePath, String dsymPath, String lists, Boolean replace, String proxyHost, String proxyUser, String proxyPass, int proxyPort)
{
@@ -160,60 +146,24 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListener lis
File file = getFileLocally(build.getWorkspace(), vars.expand(expandPath), tempDir, pathSpecified);
listener.getLogger().println(file);
-
- DefaultHttpClient httpClient = new DefaultHttpClient();
-
- // Configure the proxy if necessary
- if(proxyHost!=null && !proxyHost.isEmpty() && proxyPort>0) {
- Credentials cred = null;
- if(proxyUser!=null && !proxyUser.isEmpty())
- cred = new UsernamePasswordCredentials(proxyUser, proxyPass);
-
- httpClient.getCredentialsProvider().setCredentials(new AuthScope(proxyHost, proxyPort),cred);
- HttpHost proxy = new HttpHost(proxyHost, proxyPort);
- httpClient.getParams().setParameter( ConnRoutePNames.DEFAULT_PROXY, proxy);
- }
-
- HttpHost targetHost = new HttpHost("testflightapp.com");
- HttpPost httpPost = new HttpPost("/api/builds.json");
- FileBody fileBody = new FileBody(file);
-
- MultipartEntity entity = new MultipartEntity();
- entity.addPart("api_token", new StringBody(apiToken));
- entity.addPart("team_token", new StringBody(teamToken));
- entity.addPart("notes", new StringBody(vars.expand(buildNotes)));
- entity.addPart("file", fileBody);
+ File dsymFile = null;
if (!StringUtils.isEmpty(dsymPath)) {
- File dsymFile = getFileLocally(build.getWorkspace(), vars.expand(dsymPath), tempDir, true);
- listener.getLogger().println(dsymFile);
- FileBody dsymFileBody = new FileBody(dsymFile);
- entity.addPart("dsym", dsymFileBody);
+ dsymFile = getFileLocally(build.getWorkspace(), vars.expand(dsymPath), tempDir, true);
}
-
- if (lists.length() > 0)
- entity.addPart("distribution_lists", new StringBody(lists));
- entity.addPart("notify", new StringBody(notifyTeam ? "True" : "False"));
- entity.addPart("replace", new StringBody(replace ? "True" : "False"));
- httpPost.setEntity(entity);
-
- HttpResponse response = httpClient.execute(targetHost,httpPost);
- HttpEntity resEntity = response.getEntity();
- InputStream is = resEntity.getContent();
+ TestflightUploader uploader = new TestflightUploader();
+ TestflightUploader.UploadRequest ur = createUploadRequest(file, dsymFile, vars);
- // Improved error handling.
- if (response.getStatusLine().getStatusCode() != 200) {
- String responseBody = new Scanner(is).useDelimiter("\\A").next();
- listener.getLogger().println("Incorrect response code: " + response.getStatusLine().getStatusCode());
- listener.getLogger().println(responseBody);
+ final Map parsedMap;
+ try {
+ parsedMap = uploader.upload(ur);
+ } catch (UploadException ue) {
+ listener.getLogger().println("Incorrect response code: " + ue.getStatusCode());
+ listener.getLogger().println(ue.getResponseBody());
return false;
}
- JSONParser parser = new JSONParser();
-
- final Map parsedMap = (Map)parser.parse(new BufferedReader(new InputStreamReader(is)));
-
TestflightBuildAction installAction = new TestflightBuildAction();
installAction.displayName = "Testflight Install Link";
installAction.iconFileName = "package.gif";
@@ -229,6 +179,7 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListener lis
catch (Exception e)
{
listener.getLogger().println(e);
+ e.printStackTrace(listener.getLogger());
return false;
}
finally
@@ -252,7 +203,24 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListener lis
return true;
}
-
+
+ private TestflightUploader.UploadRequest createUploadRequest(File file, File dsymFile, EnvVars vars) {
+ TestflightUploader.UploadRequest ur = new TestflightUploader.UploadRequest();
+ ur.apiToken = apiToken;
+ ur.buildNotes = vars.expand(buildNotes);
+ ur.dsymFile = dsymFile;
+ ur.file = file;
+ ur.lists = lists;
+ ur.notifyTeam = notifyTeam;
+ ur.proxyHost = proxyHost;
+ ur.proxyPass = proxyPass;
+ ur.proxyPort = proxyPort;
+ ur.proxyUser = proxyUser;
+ ur.replace = replace;
+ ur.teamToken = teamToken;
+ return ur;
+ }
+
private File getFileLocally(FilePath workingDir, String strFile, File tempDir, boolean pathSpecified) throws IOException, InterruptedException
{
if(!pathSpecified) {
View
113 src/main/java/testflight/TestflightUploader.java
@@ -0,0 +1,113 @@
+package testflight;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpResponse;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.Credentials;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.conn.params.ConnRoutePNames;
+import org.apache.http.entity.mime.MultipartEntity;
+import org.apache.http.entity.mime.content.FileBody;
+import org.apache.http.entity.mime.content.StringBody;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.json.simple.parser.JSONParser;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Scanner;
+
+/**
+ * A testflight uploader
+ */
+public class TestflightUploader {
+ static class UploadRequest {
+ String apiToken;
+ String teamToken;
+ Boolean notifyTeam;
+ String buildNotes;
+ File file;
+ File dsymFile;
+ String lists;
+ Boolean replace;
+ String proxyHost;
+ String proxyUser;
+ String proxyPass;
+ int proxyPort;
+ }
+
+ public Map upload(UploadRequest ur) throws IOException, org.json.simple.parser.ParseException {
+
+ DefaultHttpClient httpClient = new DefaultHttpClient();
+
+ // Configure the proxy if necessary
+ if(ur.proxyHost!=null && !ur.proxyHost.isEmpty() && ur.proxyPort>0) {
+ Credentials cred = null;
+ if(ur.proxyUser!=null && !ur.proxyUser.isEmpty())
+ cred = new UsernamePasswordCredentials(ur.proxyUser, ur.proxyPass);
+
+ httpClient.getCredentialsProvider().setCredentials(new AuthScope(ur.proxyHost, ur.proxyPort),cred);
+ HttpHost proxy = new HttpHost(ur.proxyHost, ur.proxyPort);
+ httpClient.getParams().setParameter( ConnRoutePNames.DEFAULT_PROXY, proxy);
+ }
+
+ HttpHost targetHost = new HttpHost("testflightapp.com");
+ HttpPost httpPost = new HttpPost("/api/builds.json");
+ FileBody fileBody = new FileBody(ur.file);
+
+ MultipartEntity entity = new MultipartEntity();
+ entity.addPart("api_token", new StringBody(ur.apiToken));
+ entity.addPart("team_token", new StringBody(ur.teamToken));
+ entity.addPart("notes", new StringBody(ur.buildNotes));
+ entity.addPart("file", fileBody);
+
+ if (ur.dsymFile != null) {
+ FileBody dsymFileBody = new FileBody(ur.dsymFile);
+ entity.addPart("dsym", dsymFileBody);
+ }
+
+ if (ur.lists.length() > 0)
+ entity.addPart("distribution_lists", new StringBody(ur.lists));
+ entity.addPart("notify", new StringBody(ur.notifyTeam ? "True" : "False"));
+ entity.addPart("replace", new StringBody(ur.replace ? "True" : "False"));
+ httpPost.setEntity(entity);
+
+ HttpResponse response = httpClient.execute(targetHost,httpPost);
+ HttpEntity resEntity = response.getEntity();
+
+ InputStream is = resEntity.getContent();
+
+ // Improved error handling.
+ int statusCode = response.getStatusLine().getStatusCode();
+ if (statusCode != 200) {
+ String responseBody = new Scanner(is).useDelimiter("\\A").next();
+ throw new UploadException(statusCode, responseBody, response);
+ }
+
+ JSONParser parser = new JSONParser();
+
+ return (Map)parser.parse(new BufferedReader(new InputStreamReader(is)));
+ }
+
+ /** Useful for testing */
+ public static void main(String[] args) throws Exception {
+ TestflightUploader uploader = new TestflightUploader();
+ UploadRequest r = new UploadRequest();
+ r.apiToken = args[0];
+ r.teamToken = args[1];
+ r.buildNotes = args[2];
+ File file = new File(args[3]);
+ r.file = file;
+ r.dsymFile = null;
+ r.notifyTeam = true;
+ r.replace = true;
+ r.lists = args[4];
+
+ uploader.upload(r);
+ }
+}
View
27 src/main/java/testflight/UploadException.java
@@ -0,0 +1,27 @@
+package testflight;
+
+import org.apache.http.HttpResponse;
+
+public class UploadException extends RuntimeException {
+ private final int statusCode;
+ private final String responseBody;
+ private final HttpResponse response;
+
+ public UploadException(int statusCode, String responseBody, HttpResponse response) {
+ this.statusCode = statusCode;
+ this.responseBody = responseBody;
+ this.response = response;
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ public String getResponseBody() {
+ return responseBody;
+ }
+
+ public HttpResponse getResponse() {
+ return response;
+ }
+}
Something went wrong with that request. Please try again.