Zephyr for Jira(Cloud) REST API Examples


JIRA(a tool developed by Atlassian) is used for bug tracking, issue tracking, and project
management. Zephyr for Jira provides a fully featured and sophisticated test management
solution. The Zephyr for Jira(ZFJ) Server allows you to access test assets through RESTful API and it is pretty well documented.

You can find the documentation here

Before we begin, you should have :
-> A basic knowledge of how to use REST APIs, e.g. requests, responses, headers and authentication.
-> A basic understanding of JIRA.
-> Maven (3.x), and recent Java version (e.g. Oracle JDK 1.8).
-> Retrieved API keys from your JIRA instance (Access Key, Secret Key)
-> Microsoft Excel

In our examples we write our retrieved test data to Microsoft Excel worksheet using Apache POI library.
You can find the tutorial here.

Let's get started with our examples.

Update the pom.xml to include required dependencies.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.Blog</groupId>
 <artifactId>Jira_Integration</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <dependencies>
  <dependency>
   <groupId>org.json</groupId>
   <artifactId>json</artifactId>
   <version>20180130</version>
  </dependency>
  
  <dependency>
   <groupId>org.apache.poi</groupId>
   <artifactId>poi</artifactId>
   <version>3.15</version>
  </dependency>

  <dependency>
   <groupId>org.apache.poi</groupId>
   <artifactId>poi-ooxml</artifactId>
   <version>3.15</version>
  </dependency>

  <dependency>
   <groupId>org.apache.poi</groupId>
   <artifactId>poi-ooxml-schemas</artifactId>
   <version>3.15</version>
  </dependency>
 </dependencies>
</project>

The below Constants class contains all the variables our examples require.
package jira.Utility;

public final class Constants {

 private Constants(){
 } 

 public static String API_SEARCH_ISSUES = "{ZephyrBaseURL}/rest/api/2/search";
 public static String API_ADD_TESTS = "{ZephyrBaseURL}/public/rest/api/1.0/executions/add/cycle/";
 public static String API_GET_EXECUTIONS = "{ZephyrBaseURL}/public/rest/api/1.0/executions/search/cycle/";                  
 public static String API_GET_EXECUTIONS_WITH_FOLDER = "{ZephyrBaseURL}/public/rest/api/1.0/executions/search/folder/";
 public static String API_GET_FOLDERLIST = "{ZephyrBaseURL}/public/rest/api/1.0/folders";
 public static String API_UPDATE_EXECUTION = "{ZephyrBaseURL}/public/rest/api/1.0/execution/";
 public static  String API_ATTACHMENT = "{ZephyrBaseURL}/public/rest/api/1.0/attachment";
 public static String API_UPDATE_STEPRESULT = "{ZephyrBaseURL}/public/rest/api/1.0/stepresult/";
 
 public final static String zephyrBaseUrl = "https://prod-api.zephyr4jiracloud.com/connect";
 public final static String accessKey = "<JIRA-Access-Key>";
 public final static String secretKey = "<JIRA-Secret-Key>";
 public final static String userName = "<JIRA-Username>";
 public final static String projectId = "<Your Project-Id>";
 public final static String versionId = "<Your Project Version Id>";

}

Once the test cases are uploaded in JIRA, each test case is assigned an Execution Id which is required to execute the case programatically.
The GetExecutionIds class contains the code to retrieve test case data from JIRA including its execution Id
package jira.GetExecutionDetails;

import java.io.IOException;
import java.net.URI;
import java.util.*;

import org.apache.http.*;
import org.apache.http.client.*;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.*;

import static jira.Utility.Constants.*;

import com.thed.zephyr.cloud.rest.ZFJCloudRestClient;
import com.thed.zephyr.cloud.rest.client.JwtGenerator;

import jira.ModelData.ExecutionObject;
import jira.ModelData.FolderDetails;
import jira.Utility.ExcelUtility;

public class GetExecutionIds {

 private final static String cycleId = "<Your Test Cycle Id>";
 private final static String folderName = "<Your Test Folder Name>"; // Replace with your folderName or else place "Empty"

 public static void main(String[] args) throws Exception {

  // Establishing the client with valid authorizations
  ZFJCloudRestClient client = ZFJCloudRestClient.restBuilder(zephyrBaseUrl, accessKey, secretKey, userName).build();  

  // Getting all the folders from the given cycle Id  (Invoking getFolderList method from GetFolders Class)
  List<FolderDetails> folderDetailsList = GetFolders.getFolderList(client, cycleId, versionId);

  if(folderDetailsList.size() == 0) {
   // If there are no sub Folders in your Test Cycle
   getExecutionsByPagination(client, cycleId, new FolderDetails());
  } else {
   if(folderName.equalsIgnoreCase("Empty")) {
    // Iterating and retrieving the test cases from all the folders  
    for(int listIndex=0; listIndex<folderDetailsList.size(); listIndex++) {
     FolderDetails folderDetails = folderDetailsList.get(listIndex);
     getExecutionsByPagination(client, cycleId, folderDetails);
    }
   } else {
    // Getting the index of the folder from the folderDetailsList 
    int folderIndex = -1;
    for(int listIndex=0; listIndex<folderDetailsList.size(); listIndex++) {
     if((folderDetailsList.get(listIndex).getFolderName()).equalsIgnoreCase(folderName)) {
      folderIndex  = listIndex;
      break;
     }
    }
    
    if(folderIndex != -1) {
     FolderDetails folderDetails = folderDetailsList.get(folderIndex);
     getExecutionsByPagination(client, cycleId, folderDetails);
    } else {
     System.out.println(folderName + " Not Found");
    }
   } 
  }
 }

 public static void getExecutionsByPagination(ZFJCloudRestClient client, String cycleId, FolderDetails folderDetails) throws Exception {

  // List to store the executionObjects
  List<ExecutionObject> executionObjectList = new ArrayList<ExecutionObject>();

  int offset =0;
  int totalCount = offset+1;
  for(;offset<=totalCount;) {
   System.out.println("Test Cases Retrieved : " + offset);
   executionObjectList = getExecutions(client, accessKey, offset, folderDetails, cycleId);
   // Getting the total count from the response
   totalCount = executionObjectList.get(0).getTotalCount();
   offset =  offset + 50;
  }
  System.out.println("Successfully fetched records : " + totalCount);
 }

 private static List<ExecutionObject> getExecutions( ZFJCloudRestClient client, String accessKey, int offset, FolderDetails folderDetails, String cycleId) throws Exception {
  
  // Creating the dataObject List to store the values retrieved from Response body
  List<ExecutionObject> executionObjectList = new ArrayList<ExecutionObject>(); 

  // Forming the URI with query parameters
  String getExecutionsUri = null;
  if(folderDetails.getFolderId().equals(null)) {
   // URL For Getting Executions without FolderID
   getExecutionsUri = API_GET_EXECUTIONS.replace("{ZephyrBaseURL}", zephyrBaseUrl) + cycleId + "?projectId=" + projectId +
     "&versionId=" + versionId + "&offset=" + offset; 
  } else {
   // URL For Getting Executions with FolderID's
   getExecutionsUri = API_GET_EXECUTIONS_WITH_FOLDER.replace("{ZephyrBaseURL}", zephyrBaseUrl) + folderDetails.getFolderId() + "?versionId="+versionId +
     "&offset="+offset+"&cycleId="+cycleId+"&projectId="+projectId;
  }

  System.out.println("URI : "+getExecutionsUri);

  URI uri = new URI(getExecutionsUri);
  // Setting expiration time to 360 seconds
  int expirationInSec = 360;
  // Generating a JSON web token(JWT) using JwtGenerator for Authentication
  JwtGenerator jwtGenerator = client.getJwtGenerator();
  String jwt = jwtGenerator.generateJWT("GET", uri, expirationInSec);
  
  HttpResponse response = null;
  HttpClient restClient = new DefaultHttpClient();

  // Creating and Configuring HttpGet object with the authorization(i.e JSON web token) and access key
  HttpGet httpGet = new HttpGet(uri);
  httpGet.setHeader("Authorization", jwt);
  httpGet.setHeader("zapiAccessKey", accessKey);

  // Sending the request to the JIRA API and loading the response in HttpResponse object
  try {
   response = restClient.execute(httpGet);
  } catch (IOException e1) {
   e1.printStackTrace();
  } 

  int statusCode = response.getStatusLine().getStatusCode();

  if (statusCode >= 200 && statusCode < 300) {
   HttpEntity responseEntity = response.getEntity();
   String responseEntityString = null;
   try {
    responseEntityString = EntityUtils.toString(responseEntity);
   } catch (ParseException | IOException e) {
    e.printStackTrace();
   }

   // Getting the JSON Object from the Response Body 
   JSONObject allIssues = new JSONObject(responseEntityString);
   JSONArray IssuesArray = allIssues.getJSONArray("searchObjectList");

   if (IssuesArray.length() == 0) {
    return dataObjList;
   }

   // Retrieving the values required from Response JSON Object
   for (int j = 0; j <= IssuesArray.length() - 1; j++) {
    int totalCount = allIssues.getInt("totalCount");

    JSONObject jobj = IssuesArray.getJSONObject(j); 
    String testCaseId = jobj.getString("issueKey");
    String summary = jobj.getString("issueSummary");
    String labels = jobj.getString("issueLabel");

    JSONObject jobj2 = jobj.getJSONObject("execution");
    String executionId = jobj2.getString("id");
    long longIssueId = jobj2.getLong("issueId");
    String issueId = String.valueOf(longIssueId);

    JSONObject statusArray = jobj2.getJSONObject("status");
    String testStatus = statusArray.getString("name");

    // Creating and loading the object with the values obtained from response JSON.
    executionObjectList.add(new ExecutionObject(issueId, testCaseId, executionId, totalCount, summary, cycleId, testStatus, labels, folderDetails.getFolderName()));
   }   
  } else {
   System.out.println("Bad Status Code : "+statusCode);
  }
  // Writing the obtained values to Data Sheet
  ExcelUtility.writeExcelForGetExecutions(executionObjectList);
  return executionObjectList;
 }
}

The GetExecutionIds class retrieves information about the test cases along with their execution Id for the given cycle Id.
A restClient is created with the zephyrBaseUrl, accessKey, secretKey and userName which we provided in our Constants class. JWT authentication is used by zephyr and we generate a json web token(jwt) with the client library.
The client library can be downloaded from the project below.
We set authorization headers with the generated json web token and accessKey which we declared in the Constants class(which we retrieved from our JIRA instance).
We query the response JSON body using json library(org.json) and retrieve the information from the response.
The writeExcelForGetExecutions method writes the retrieved information to the excel sheet.

The ExecutionObject is a simple POJO which is used to carry some data.
package jira.ModelData;

public class ExecutionObject {

 private String issueId;
 private String executionId;
 private int totalCount;
 private String cycleId;
 private String status;
 private String folderName;
 
 public ExecutionObject(String issueId, String testCaseId, String executionId, int totalCount, String summary, String cycleId, String status, String label, String folderName) {
  this.issueId = issueId;
  this.executionId = executionId;
  this.totalCount = totalCount;
  this.cycleId = cycleId;
  this.status = status;
  this.folderName = folderName;
 }

 public String getCycleId() {
  return cycleId;
 }
 public void setCycleId(String cycleId) {
  this.cycleId = cycleId;
 }
 public String getStatus() {
  return status;
 }
 public void setStatus(String status) {
  this.status = status;
 }
 public String getIssueId() {
  return issueId;
 }
 public void setIssueId(String issueId) {
  this.issueId = issueId;
 }
 public String getExecutionId() {
  return executionId;
 }
 public void setExecutionId(String executionId) {
  this.executionId = executionId;
 }
 public int getTotalCount() {
  return totalCount;
 }
 public void setTotalCount(int totalCount) {
  this.totalCount = totalCount;
 }
 public String getFolderName(){
  return folderName;
 }
}

The GetFolders class contains the code to retrieve the sub-folder information from a Test Cycle.
package jira.GetExecutionDetails;

import java.io.IOException;
import java.net.*;
import java.util.*;
import org.json.*;
import org.apache.http.*;
import org.apache.http.client.*;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import com.thed.zephyr.cloud.rest.ZFJCloudRestClient;
import com.thed.zephyr.cloud.rest.client.JwtGenerator;
import jira.ModelData.FolderDetails;
import static jira.Utility.Constants.*;

public class GetFolders {

 public static List<FolderDetails> getFolderList(ZFJCloudRestClient client, String cycleId, String versionId) throws URISyntaxException {

  // URL for getting all folders from given CycleID
  final String getExecutionsUri = API_GET_FOLDERLIST.replace("{ZephyrBaseURL}", zephyrBaseUrl) + "?versionId="+versionId+"&cycleId="+cycleId + "&projectId="+projectId;

  URI uri = new URI(getExecutionsUri);
  int expirationInSec = 360;
  // Generating a JSON web token using JwtGenerator
  JwtGenerator jwtGenerator = client.getJwtGenerator();
  String jwt = jwtGenerator.generateJWT("GET", uri, expirationInSec);   

  // Creating and Configuring HttpGet object with the authorization(i.e JSON web token) and access key
  HttpGet httpGet = new HttpGet(uri);
  httpGet.setHeader("Authorization", jwt);  // setting the authorization header
  httpGet.setHeader("zapiAccessKey", accessKey); // setting the Zapi Access Key

  // Sending the request and loading the response in HttpResponse object
  HttpClient restClient = new DefaultHttpClient();
  HttpResponse response = null;
  try {
   response = restClient.execute(httpGet);  
  }  catch (IOException e) {
   e.printStackTrace();
  }

  // Creating the folderDetails List to store the values retrieved from Response body
  ArrayList<FolderDetails> folderDetailsList = new ArrayList<FolderDetails>();

  int statusCode = response.getStatusLine().getStatusCode();
  if (statusCode >= 200 && statusCode < 300) {
   HttpEntity responseEntity = response.getEntity();
   String entityString = null;
   try {
    entityString = EntityUtils.toString(responseEntity);
   } catch (ParseException | IOException e) {
    e.printStackTrace();
   }

   // Retrieving the folder name and folder Id from the Response Body
   JSONArray jsonArray = new JSONArray(entityString);
   for(int arrayIndex=0; arrayIndex<jsonArray.length(); arrayIndex++) {
    JSONObject jsonObj1 = jsonArray.getJSONObject(arrayIndex);
    String folderName = jsonObj1.getString("name");
    String folderId = jsonObj1.getString("id");
    folderDetailsList.add(new FolderDetails(folderName, folderId));
   }
  }
  return folderDetailsList;
 }
}

The GetFolders class retrieves information about the sub-folders(if present) for the given cycle Id.
getFolderList method queries the response JSON body and returns list of FolderDetails objects, each object containing folder details of the given cycle Id, the list is empty when no folders are present.

The FolderDetails Class is also a POJO and is used to carry some data at runtime.
package jira.ModelData;

public class FolderDetails {
 
 private String folderId;
 private String folderName;
 
 public FolderDetails(String folderName, String folderId) {
  this.folderId = folderId;
  this.folderName = folderName;
 }
 
 public FolderDetails() {
  this.folderId = null;
  this.folderName = null;
 }
 
 public String getFolderId() {
  return folderId;
 }
 public String getFolderName() {
  return folderName;
 }
}


Place an image of the excel sheet and notes about the sheet
The below method writes your retrieved data to a Excel Sheet.

public static void writeExcelForGetExecution(List<ExecutionObject> executionObjectList) throws Exception {
     
  FileInputStream fis = new FileInputStream("<FILE-PATH>");
  XSSFWorkbook srcbook = new XSSFWorkbook(fis);
  XSSFSheet sourceSheet = srcbook.getSheet("<SHEET-NAME");
    
  for(int listIndex=0; listIndex<executionObjectList.size(); listIndex++) {
   
   int rowCount = sourceSheet.getLastRowNum()-sourceSheet.getFirstRowNum();
   Row newRow = sourceSheet.createRow(rowCount+1);
   
   String a[] = {executionObjectList.get(listIndex).getStatus(), executionObjectList.get(listIndex).getCycleId(), 
     executionObjectList.get(listIndex).getFolderName(), executionObjectList.get(listIndex).getExecutionId(),
     executionObjectList.get(listIndex).getIssueId()};
   
   for(int arrayIndex=0; arrayIndex<a.length; arrayIndex++) {
    Cell cell = newRow.createCell(arrayIndex);
    cell.setCellValue(a[arrayIndex]);
   }
  }
  fis.close();
  FileOutputStream fos = new FileOutputStream("<FILE - PATH>");
  srcbook.write(fos);
  fos.close();
 }

We will be using the execution Ids we retrieved from executing GetExecutionIds class to update the test cases.
The UpdateExecutions class contains the code to update the test cases in JIRA.
package jira.UpdateExecution;

import static jira.Utility.Constants.*;
import java.io.*;
import java.net.URI;
import java.util.*;
import org.apache.http.*;
import org.apache.http.client.*;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;
import com.thed.zephyr.cloud.rest.ZFJCloudRestClient;
import com.thed.zephyr.cloud.rest.client.JwtGenerator;
import jira.Utility.ExcelUtility;

public class UpdateExecutions {

 final static String versionId = "-1";
 static ExcelUtility excelUtil = new ExcelUtility();

 public static void main(String[] args) throws Exception {
  
  // Establishing the client with valid authorizations
  ZFJCloudRestClient client = ZFJCloudRestClient.restBuilder(zephyrBaseUrl, accessKey, secretKey, userName).build();
  
  // Creating a object of JwtGenerator with the established client object
  JwtGenerator jwtGenerator = client.getJwtGenerator();

  
  Map<String,String> executionMap = new HashMap<String,String>();

  // Creating a JSON Object and loading it with query parameters
  JSONObject executeTestObj = new JSONObject();
  executeTestObj.put("projectId", projectId);
  executeTestObj.put("comment", "Executed by PCB-QA");

  int lastRowNum = 3;  // lastRowNum gets updated at run time
  int rowNum=1;
  for(;rowNum<=lastRowNum; rowNum++) {
   // Reading from the excel sheet and storing the retrieved values in a Map with the header row values(first row values) as the keys.
   executionMap = excelUtil.readExcelForUpdateExecution(rowNum);
   
   JSONObject statusObj = new JSONObject();
   if(executionMap.get("Status").equalsIgnoreCase("PASS")) {
    statusObj.put("id", "1");
   } else if(executionMap.get("Status").equalsIgnoreCase("FAIL")) {
    statusObj.put("id", "2");
   } else if(executionMap.get("Status").equalsIgnoreCase("WIP")) {
    statusObj.put("id", "3");
   } else if(executionMap.get("Status").equalsIgnoreCase("BLOCKED")) {
    statusObj.put("id", "4");
   } else if(executionMap.get("Status").equalsIgnoreCase("DEFERRED")) {
    statusObj.put("id", "5");
   } else if(executionMap.get("Status").equalsIgnoreCase("OUT OF SCOPE")) {
    statusObj.put("id", "6");
   } else if(executionMap.get("Status").equalsIgnoreCase("UNEXECUTED")) {
    statusObj.put("id", "-1");
   }
   
   final String updateExecutionUri = API_UPDATE_EXECUTION.replace("{SERVER}", zephyrBaseUrl) + executionMap.get("DataExecutionId");
   executeTestObj.put("status", statusObj);
   executeTestObj.put("cycleId", executionMap.get("DataCycleId"));
   executeTestObj.put("versionId", versionId);
   executeTestObj.put("issueId", executionMap.get("DataIssueId"));

   StringEntity executeTestJSON = null;
   try {
    executeTestJSON = new StringEntity(executeTestObj.toString());
   } catch (UnsupportedEncodingException e1) {
    e1.printStackTrace();
   }
   
   updateExecution(updateExecutionUri, jwtGenerator, accessKey, executeTestJSON, rowNum);
   
   // Updating the Last Row
   lastRowNum = Integer.parseInt(executionMap.get("LastRowCount"));
   if(rowNum == 1) {
    System.out.println("Last Row Number is :  "+ lastRowNum);
   }
  }
  System.out.println("Successfully updated status for records: "+(rowNum-1));
 }

 private static void updateExecution(String uriStr, JwtGenerator jwtGenerator, String accessKey, StringEntity executeTestsJSON, int rowNm) throws Exception {

  URI uri = new URI(uriStr);
  int expirationInSec = 360;
  String jwt = jwtGenerator.generateJWT("PUT", uri, expirationInSec);

  HttpPut executeTest = new HttpPut(uri);
  executeTest.addHeader("Content-Type", "application/json");
  executeTest.addHeader("Authorization", jwt);
  executeTest.addHeader("zapiAccessKey", accessKey);
  executeTest.setEntity(executeTestsJSON);

  HttpResponse response = null;
  HttpClient restClient = new DefaultHttpClient();
  try {
   response = restClient.execute(executeTest);
  } catch (IOException e) {
   e.printStackTrace();
  }

  // The value of executionStatus changes if the test is executed successfully or else remains the same
  String executionStatus = "No Test Executed";
  HttpEntity responseEntity = response.getEntity();
  
  int statusCode = response.getStatusLine().getStatusCode();
  if (statusCode >= 200 && statusCode < 300) {
   String entityString = null;
   // Retrieving the values required from Response JSON Object
   try {
    entityString = EntityUtils.toString(responseEntity);
    JSONObject executionResponseObj = new JSONObject(entityString);
    JSONObject descriptionResponseObj = executionResponseObj.getJSONObject("execution");
    JSONObject statusResponseObj = descriptionResponseObj.getJSONObject("status");
    executionStatus = statusResponseObj.getString("description");
    ExcelUtility.writeExcelForUpdateExecution(executionStatus, rowNm);
    System.out.println(executionResponseObj.get("issueKey") + "--" + executionStatus);
   } catch (ParseException | IOException e) {
    e.printStackTrace();
   }
  } else {
    throw new ClientProtocolException("Unexpected response status: " + statusCode);
  }  
 }
}

The UpdateExecution class requires execution Id of the test case to assign a status to it.
The requestURI is formed with the required query parameters and headers (along with the json web token and the access key)
We query the reponse JSON body and write the necessary information to the excel sheet.

The below method reads the test data excel sheet for execution Id.
 public Map<String, String> readExcelForUpdateExecution(int rowNum) throws Exception {

    FileInputStream fis =  new FileInputStream("<File-Path>");
    XSSFWorkbook srcbook = new XSSFWorkbook(fis);
    XSSFSheet sourceSheet = srcbook.getSheet("<Sheet-Name>");
    
  XSSFRow row = sourceSheet.getRow(rowNum);

  DataFormatter fmt = new DataFormatter();
  Map<String,String> updateExecutionMap = new HashMap<String,String>();
  List<XSSFCell> cellValue = new ArrayList<XSSFCell>(); 

  for(int i=0;i<row.getLastCellNum();i++){
   cellValue.add(row.getCell(i));
  }

  updateExecutionMap.put("TestCaseId",fmt.formatCellValue(cellValue.get(0)));
  updateExecutionMap.put("Status",fmt.formatCellValue(cellValue.get(2)));
  updateExecutionMap.put("DataCycleId",fmt.formatCellValue(cellValue.get(4)));
  updateExecutionMap.put("DataExecutionId",fmt.formatCellValue(cellValue.get(5)));
  updateExecutionMap.put("DataIssueId",fmt.formatCellValue(cellValue.get(6)));
  updateExecutionMap.put("LastRowCount",String.valueOf(sourceSheet.getLastRowNum()));

  return updateExecutionMap; 
 }


Test cases need data points, so attachments can be added to a test case in JIRA. The AddAttachments class contains the code for adding attachment to a test case.
package jira.Attachments;

import static jira.Utility.Constants.*;
import java.io.*;
import java.net.URI;
import java.util.Map;
import org.apache.http.*;
import org.apache.http.client.*;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import com.thed.zephyr.cloud.rest.ZFJCloudRestClient;
import com.thed.zephyr.cloud.rest.client.JwtGenerator;
import jira.Utility.ExcelUtility;

public class AddAttachments {

 public static void main(String[] args) throws Exception {
  ExcelUtility excelUtil = new ExcelUtility();

  // Establishing the client with valid authorizations
  ZFJCloudRestClient client = ZFJCloudRestClient.restBuilder(zephyrBaseUrl, accessKey, secretKey, userName).build();

  // Instantiating JwtGenerator for Authentication
  JwtGenerator jwtGenerator = client.getJwtGenerator();

  // lastRowNum gets updated at run time
  int lastRowNum = 2;

  for(int rowNm=1; rowNm<=lastRowNum; rowNm++) {
   // Reading from the excel sheet and storing the retrieved values in a Map with the header row values(first row values) as the keys.
   Map<String,String> attachmentMap = excelUtil.readExcelForAddAttachment(rowNm);

   addAttachment(jwtGenerator, excelUtil, rowNm, attachmentMap);

   // Updating the Last Row
   lastRowNum = Integer.parseInt(attachmentMap.get("LastRowCount"));
  }      
 }

 public static void addAttachment(JwtGenerator jwtGenerator, ExcelUtility excelUtil, int rowNm, Map<String,String> attachmentMap) throws Exception {

  final String comment = "<Your Comment>";
  final String cycleId = attachmentMap.get("DataCycleId");
  final String issueId = attachmentMap.get("DataIssueId");
  final String entityName = "execution";    // entityName parameter takes "execution" or "stepResult" as parameter value
  final String executionId = attachmentMap.get("DataExecutionId");
  final String fileWithAbsolutePath = attachmentMap.get("AttachmentFilePath");

  // Forming the URI with query parameters
  String attachmentUri = API_ATTACHMENT.replace("{SERVER}", zephyrBaseUrl) + "?issueId="+issueId  + "&versionId="+versionId + 
    "&entityName="+entityName + "&cycleId="+cycleId + "&entityId="+executionId + "&projectId="+projectId + "&comment="+comment;

  URI uri = new URI(attachmentUri);

  // Generating a JSON Web Token(JWT) for authentication and setting the expiration time to 360 seconds
  int expirationInSec = 360;
  String jwt = jwtGenerator.generateJWT("POST", uri, expirationInSec);

  // Loading the file
  File file = new File(fileWithAbsolutePath);
  MultipartEntity entity = new MultipartEntity();
  entity.addPart("attachment", new FileBody(file));

  // Creating and Configuring HttpGet object with the authorization(i.e JSON web token) and access key
  HttpPost addAttachmentReq = new HttpPost(uri);
  addAttachmentReq.addHeader("Authorization", jwt);
  addAttachmentReq.addHeader("zapiAccessKey", accessKey);
  addAttachmentReq.setEntity(entity);

  // Sending the request to the JIRA API and loading the response in HttpResponse object
  HttpClient restClient = new DefaultHttpClient();
  HttpResponse response = null;
  try {
   response = restClient.execute(addAttachmentReq);
  } catch (IOException e) {
   e.printStackTrace();
  }

  HttpEntity responseEntity = response.getEntity();
  int statusCode = response.getStatusLine().getStatusCode();

  if (statusCode >= 200 && statusCode < 300) {
   String attachmentResponse = "Attachment added Successfully";
   ExcelUtility.writeExcelForAddAttachment(attachmentResponse, rowNm);
  } else {
   try {
    String entityString = null;
    entityString = EntityUtils.toString(responseEntity);
    ExcelUtility.writeExcelForAddAttachment(entityString, rowNm);
   } catch (ClientProtocolException e) {
    e.printStackTrace();
   }
   throw new ClientProtocolException("Unexpected response status: " + statusCode);
  }
 }
}

The addAttachments class requires execution Id and the path of the file to be uploaded which are read from the excel sheet.
The requestUri is formed with the required query parameters, headers and the file to be uploaded.
The response JSON body is queried and the necessary information is written to the excel sheet.

The below method reads the test data excel sheet for execution Id and file path.
public Map<String,String> readExcelForAddAttachment(int rowNum) throws Exception {

  FileInputStream fis = new FileInputStream("<File-Path>");
  XSSFWorkbook srcbook = new XSSFWorkbook(fis);
  XSSFSheet sourceSheet = srcbook.getSheet("<Sheet-Name>");

  // Getting the top heading row from AddAttachment Sheet and storing it in headerCellValues List 
  XSSFRow headerRow = sourceSheet.getRow(0);
  List<XSSFCell> headerCellValues = new ArrayList<XSSFCell>();
  for(int i=0;i<headerRow.getLastCellNum();i++){
   headerCellValues.add(headerRow.getCell(i));
  }

  // Getting the top heading row from AddAttachment Sheet and storing it in dataCellValues List
  XSSFRow dataRow = sourceSheet.getRow(rowNum);
  List<XSSFCell> dataCellValues = new ArrayList<XSSFCell>();
  for(int i=0;i<headerRow.getLastCellNum();i++){
   dataCellValues.add(dataRow.getCell(i));
  }

  // Mapping the headerRowValues and dataRowValues in attachmentMap 
  Map<String,String> attachmentMap = new HashMap<String,String>();
  for(int index=0; index<headerRow.getLastCellNum(); index++) {
   String headerCellValue = fmt.formatCellValue(headerCellValues.get(index));
   String dataCellValue = fmt.formatCellValue(dataCellValues.get(index));
   attachmentMap.put(headerCellValue, dataCellValue);
  }
  return attachmentMap;
 }

You can download the source code here.

Comments

  1. Hi Aditya, this post is very good. I am currently integrating zapi cloud into my automation suite and u am running into some issues. Is there anyway to contact you, so that I could show you what I am doing.

    ReplyDelete

Post a Comment

Popular Posts