package com.door43.tools.reporting; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Build; import android.provider.Settings; import android.util.Pair; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * This class submits information to a github repository */ public class GithubReporter { private static final int MAX_TITLE_LENGTH = 50; private static final String DEFAULT_CRASH_TITLE = "crash report"; private static final String DEFAULT_BUG_TITLE = "bug report"; private final String sRepositoryUrl; private final String sGithubOauth2Token; private final Context sContext; public GithubReporter(Context context, String repositoryUrl, String githubOauth2Token) { sContext = context; sRepositoryUrl = repositoryUrl; sGithubOauth2Token = githubOauth2Token; } /** * Creates a crash issue on github. * @param notes notes supplied by the user * @param stacktraceFile the stacktrace file */ public void reportCrash(String notes, File stacktraceFile) { try { String stacktrace = FileUtils.readFileToString(stacktraceFile); reportCrash(notes, stacktrace, null); } catch (IOException e) { e.printStackTrace(); } } /** * Creates a crash issue on github. * @param notes notes supplied by the user * @param stacktraceFile the stacktrace file * @param logFile the log file */ public void reportCrash(String notes, File stacktraceFile, File logFile) { String log = null; if(logFile.exists()) { try { log = FileUtils.readFileToString(logFile); } catch (IOException e) { e.printStackTrace(); } } try { String stacktrace = FileUtils.readFileToString(stacktraceFile); reportCrash(notes, stacktrace, log); } catch (IOException e) { e.printStackTrace(); } } /** * Creates a crash issue on github. * @param notes notes supplied by the user * @param stacktrace the stracktrace * @param log information from the log */ public void reportCrash(String notes, String stacktrace, String log) throws IOException { String title = getTitle(notes, DEFAULT_CRASH_TITLE); StringBuffer bodyBuf = new StringBuffer(); bodyBuf.append(getNotesBlock(notes)); bodyBuf.append(getEnvironmentBlock()); bodyBuf.append(getStacktraceBlock(stacktrace)); bodyBuf.append(getLogBlock(log)); String[] labels = new String[]{"crash report"}; submit(generatePayload(title, bodyBuf.toString(), labels)); // TODO: 3/25/2016 handle response } /** * Creates a bug issue on github * @param notes notes supplied by the user */ public void reportBug(String notes) throws IOException { reportBug(notes, ""); // TODO: 3/25/2016 handle response } /** * Creates a bug issue on github * @param notes notes supplied by the user * @param logFile the log file */ public void reportBug(String notes, File logFile) throws IOException { String log = null; if(logFile != null && logFile.exists()) { try { log = FileUtils.readFileToString(logFile); } catch (IOException e) { e.printStackTrace(); } } reportBug(notes, log); // TODO: 3/25/2016 handle response } /** * Creates a bug issue on github * @param notes notes supplied by the user * @param log information from the log */ public void reportBug(String notes, String log) throws IOException { String title = getTitle(notes, DEFAULT_BUG_TITLE); StringBuffer bodyBuf = new StringBuffer(); bodyBuf.append(getNotesBlock(notes)); bodyBuf.append(getEnvironmentBlock()); bodyBuf.append(getLogBlock(log)); String[] labels = new String[]{"bug report"}; submit(generatePayload(title, bodyBuf.toString(), labels)); // TODO: 3/25/2016 handle response } /** * Generates the json payload that will be set to the github server. * @param title the issue title * @param body the issue body * @param labels the issue labels. These will be created automatically went sent to github * @return */ private JSONObject generatePayload(String title, String body, String[] labels) { JSONObject json = new JSONObject(); try { json.put("title", title); json.put("body",body); JSONArray labelsJson = new JSONArray(); for(String label:labels) { labelsJson.put(label); } try { PackageInfo pInfo = sContext.getPackageManager().getPackageInfo(sContext.getPackageName(), 0); labelsJson.put(pInfo.versionName); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } json.put("labels", labelsJson); } catch (JSONException e) { e.printStackTrace(); } return json; } /** * Sends the new issue request to github * @param json the payload * @return */ private String submit(JSONObject json) throws IOException { Github github = new Github(sRepositoryUrl); List<Pair<String, String>> headers = new ArrayList<>(); headers.add(new Pair<>("Authorization", "token " + sGithubOauth2Token)); headers.add(new Pair<>("Content-Type", "application/json")); return github.postRequest("", headers, json.toString()); } /** * Generates the notes block. * @param log * @return */ private String getLogBlock(String log) { StringBuffer logBuf = new StringBuffer(); if (log != null && !log.isEmpty()) { logBuf.append("Log history\n======\n"); logBuf.append("```java\n"); logBuf.append(log + "\n"); logBuf.append("```\n"); } return logBuf.toString(); } /** * Generates the stacktrace block * @param stacktrace the stacktrace text * @return */ private static String getStacktraceBlock(String stacktrace) { StringBuffer stacktraceBuf = new StringBuffer(); if(stacktrace != null && !stacktrace.isEmpty()) { stacktraceBuf.append("Stack trace\n======\n"); stacktraceBuf.append("```java\n"); stacktraceBuf.append(stacktrace + "\n"); stacktraceBuf.append("```\n"); } return stacktraceBuf.toString(); } /** * Generates the ntoes block * @param notes notes supplied by the user * @return */ private static String getNotesBlock(String notes) { StringBuffer notesBuf = new StringBuffer(); if (!notes.isEmpty()) { notesBuf.append("Notes\n======\n"); notesBuf.append(notes + "\n"); } return notesBuf.toString(); } /** * Generates the environment block * @return */ private String getEnvironmentBlock() { PackageInfo pInfo = null; StringBuffer environmentBuf = new StringBuffer(); environmentBuf.append("\nEnvironment\n======\n"); environmentBuf.append("Environment Key | Value" + "\n"); environmentBuf.append(":----: | :----:" + "\n"); try { pInfo = sContext.getPackageManager().getPackageInfo(sContext.getPackageName(), 0); environmentBuf.append("version | " + pInfo.versionName + "\n"); environmentBuf.append("build | " + pInfo.versionCode + "\n"); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } String udid = Settings.Secure.getString(sContext.getContentResolver(), Settings.Secure.ANDROID_ID); environmentBuf.append("UDID | " + udid + "\n"); environmentBuf.append("Android Release | " + Build.VERSION.RELEASE + "\n"); environmentBuf.append("Android SDK | " + Build.VERSION.SDK_INT + "\n"); environmentBuf.append("Brand | " + Build.BRAND + "\n"); environmentBuf.append("Device | " + Build.DEVICE + "\n"); return environmentBuf.toString(); } /** * Generates the title from the notes * @param notes notes supplied by the user * @param defaultTitle the title to use if the user notes are insufficient * @return */ private static String getTitle(String notes, String defaultTitle) { String title = defaultTitle; if (notes.length() < MAX_TITLE_LENGTH && !notes.isEmpty()) { title = notes; } else if (!notes.isEmpty()) { title = notes.substring(0, MAX_TITLE_LENGTH - 3) + "..."; } return title; } }