Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
languagegroovy
titlecreate_test_execution.groovy
collapsetrue
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.link.IssueLinkManager
import com.atlassian.jira.issue.link.IssueLinkType
import com.atlassian.jira.issue.link.IssueLinkTypeManager
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.jql.builder.JqlQueryBuilder
import com.atlassian.jira.user.util.UserUtil
import com.atlassian.jira.user.util.UserManager;
import com.atlassian.jira.bc.issue.IssueService
import com.atlassian.jira.bc.issue.search.SearchService
import com.atlassian.jira.issue.search.SearchProvider
import com.atlassian.jira.issue.search.SearchResults
import com.atlassian.jira.web.bean.PagerFilter;
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.user.UserPropertyManager
import com.atlassian.jira.propertyset.JiraPropertySetFactory;
import com.google.common.collect.ImmutableMap;
import com.opensymphony.module.propertyset.PropertySet;
import com.opensymphony.module.propertyset.PropertySetManager;
import com.atlassian.jira.util.BuildUtils
import com.atlassian.jira.util.BuildUtilsInfo
import com.atlassian.jira.util.BuildUtilsInfoImpl
import com.atlassian.plugin.PluginAccessor
import com.atlassian.plugin.PluginManager
import com.atlassian.jira.bc.license.JiraLicenseService
import com.atlassian.jira.bc.license.JiraLicenseServiceImpl
import org.apache.log4j.Level
import org.apache.log4j.Logger
import com.atlassian.jira.issue.IssueManager
import org.ofbiz.core.entity.GenericValue
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.event.type.EventDispatchOption
import groovy.json.JsonOutput
import groovy.transform.BaseScript
import groovy.json.JsonSlurper;
import groovy.json.StreamingJsonBuilder;
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response
import com.atlassian.jira.issue.index.IssueIndexingService
import com.atlassian.jira.util.ImportUtils
import com.atlassian.jira.bc.issue.IssueService
import com.atlassian.jira.bc.issue.IssueService.CreateValidationResult
import com.atlassian.jira.bc.issue.IssueService.IssueResult
import com.atlassian.jira.user.ApplicationUser



Logger.getLogger("com.onresolve").setLevel(Level.DEBUG)


projectManager = ComponentAccessor.getProjectManager()
componentManager = ComponentManager.getInstance()
issueManager = ComponentAccessor.getIssueManager()
def issueFactory = ComponentAccessor.getIssueFactory()
issueService = ComponentAccessor.issueService
searchService =  ComponentAccessor.getComponent(SearchService.class);
serviceAccount = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
customFieldManager = ComponentAccessor.getCustomFieldManager()
def subTaskManager = ComponentAccessor.getSubTaskManager()
issueService = ComponentAccessor.getIssueService()
def user = ComponentAccessor.jiraAuthenticationContext.getLoggedInUser()



Object getIssues(jqlQuery){
    // A list of GenericValues representing issues
    List<Issue> searchResults = null;

    SearchService.ParseResult parseResult =  searchService.parseQuery(serviceAccount, jqlQuery);

    if (parseResult.isValid()) {
        // throws SearchException
        SearchResults results = searchService.search(serviceAccount, parseResult.getQuery(), PagerFilter.getUnlimitedFilter());
        searchResults = results.getIssues();
        return searchResults;
    } 
            
     return [] 
}

Object getFieldValueByName(issue,customField) {
    def cField = customFieldManager.getCustomFieldObjectByName(customField)
    def cFieldValue = issue.getCustomFieldValue(cField)
    return cFieldValue
}


Object setFieldValueByName(issue,customField,value) {
    def cField = customFieldManager.getCustomFieldObjectByName(customField)
    issue.setCustomFieldValue(cField,*value)
}


Object setFieldValueByNameInParameters(inputParameters,customFieldName,value) {
    def customField = customFieldManager.getCustomFieldObjectByName(customFieldName)
    inputParameters.addCustomFieldValue(customField.id, value)
}

boolean associateTestsToTestExecution(testExecKey,listOfTestKeys){
    def jiraBaseUrl = com.atlassian.jira.component.ComponentAccessor.getApplicationProperties().getString("jira.baseurl")
    def endpointUrl = "${jiraBaseUrl}/rest/raven/1.0/api/testexec/${testExecKey}/test"
    url = new URL(endpointUrl);
    def body_req = [ "add": listOfTestKeys ]

    // you should use a specific user for this purpose
    username = "admin"
    password = "admin"
    def authString = "${username}:${password}".bytes.encodeBase64().toString()

    URLConnectionHttpURLConnection connection = (HttpURLConnection) url.openConnection();
    connection.requestMethod = setRequestMethod("POST")
    connection.doOutput = truesetDoOutput(true)
    connection.addRequestProperty("Authorization", "Basic ${authString}")
    connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8")
    connection.outputStream.withWriter("UTF-8") { new StreamingJsonBuilder(it, body_req) }
    connection.connect();
    log.debug(connection.getResponseCode())
    log.debug(connection.getResponseMessage())

    if (connection.getResponseCode() == 200) {
        // OK
        return true;
    } else {
        // error
        return false;
    }
}
def project = projectManager.getProjectObjByKey("CALC")
def newIssueType = ComponentAccessor.issueTypeSchemeManager.getIssueTypesForProject(project).find { it.name == "Test Execution" }

def newIssue


def issueInputParameters = issueService.newIssueInputParameters()
issueInputParameters.with {
    projectId = project.id
    summary = "Issue created from script"
    issueTypeId = newIssueType.id
    reporterId = user.name
}


def jql = "project = ${project.key} and issuetype  = Test and component = UI"
def issues = getIssues(jql)
def testKeys = issues.collect{ it.key }


appUser = user.getDirectoryUser()
CreateValidationResult createValidationResult = issueService.validateCreate(user, issueInputParameters)
if (!createValidationResult.isValid()) {
    log.error "Error validating new issue"+createValidationResult.getErrorCollection()
} else {
    IssueResult createResult = issueService.create(user, createValidationResult)
    newIssue = createResult.issue
    log.debug(newIssue.key)  
    associateTestsToTestExecution(newIssue.key, testKeys)
}

...

Code Block
languagegroovy
titletrigger_jenkins_build_restapi_endpoint.groovy
collapsetrue
import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.json.JsonOutput
import groovy.transform.BaseScript
import groovy.json.JsonSlurper;
import groovy.json.StreamingJsonBuilder;
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response
import java.net.HttpURLConnection
  
@BaseScript CustomEndpointDelegate delegate
  
triggerJenkinsBuild(httpMethod: "GET") { MultivaluedMap queryParams ->
  
	    def issueId = queryParams.getFirst("issueId") as String // use the issueId to retrieve this issue
	      
	    def flag = [
	    type : 'success',
	    title: "Build scheduled",
	    close: 'auto',
	    body : "A new build has been scheduled related with "+issueId
	    ]
    
 
	    URL url;
	    def jobName = "java-junit-calc"                         // could come from a CF in the Test Plan
	    def jenkinsHostPort = "192.168.56.102:8081"             // could be defined elsewhere
	    def token = "iFBDOBhNhaxL4T9ass93HRXun2JF161Z"          		// could also come from a CF in the Test Plan
	    def username = "admin"									                                  // probably, would need to be stored elsewhere
	    def password = "fa02840152aa2e4da3d8db933ec708d6"		       // probably, would need to be stored elsewhere
	    def baseURL = "http://${jenkinsHostPort}/job/${jobName}/buildWithParameters?token=${token}&TESTPLAN=$issueId"
 
	    url = new URL(baseURL);
	    def body_req = []
 
	    def authString = "${username}:${password}".bytes.encodeBase64().toString()

	URLConnection 
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
	    connection.requestMethod = setRequestMethod("POST")
	    connection.doOutput = true
	setDoOutput(true)
    connection.addRequestProperty("Authorization", "Basic ${authString}")
	    connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8")
	    connection.outputStream.withWriter("UTF-8") { new StreamingJsonBuilder(it, body_req) }
	    connection.connect();
	    log.debug(connection.getResponseCode())
	    log.debug(connection.getResponseMessage())
 
     
	    if (connection.getResponseCode() == 201) {
 		       Response.ok(JsonOutput.toJson(flag)).build()
 	   } else {
 		        //Response.status(Response.Status.NOT_FOUND).entity("Problem scheduling job!").build();
 	   }
     
}


Example

ScriptRunner configuration

...

Code Block
languagegroovy
titletrigger_jenkins_build_restapi_endpoint_with_testlist.groovy
collapsetrue
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.link.IssueLinkManager
import com.atlassian.jira.issue.link.IssueLinkType
import com.atlassian.jira.issue.link.IssueLinkTypeManager
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.jql.builder.JqlQueryBuilder
import com.atlassian.jira.user.util.UserUtil
import com.atlassian.jira.user.util.UserManager;
import com.atlassian.jira.bc.issue.IssueService
import com.atlassian.jira.bc.issue.search.SearchService;
import com.atlassian.jira.issue.search.SearchProvider
import com.atlassian.jira.issue.search.SearchResults
import com.atlassian.jira.web.bean.PagerFilter;
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.user.UserPropertyManager
import com.atlassian.jira.propertyset.JiraPropertySetFactory;
import com.google.common.collect.ImmutableMap;
import com.opensymphony.module.propertyset.PropertySet;
import com.opensymphony.module.propertyset.PropertySetManager;
import com.atlassian.jira.util.BuildUtils
import com.atlassian.jira.util.BuildUtilsInfo
import com.atlassian.jira.util.BuildUtilsInfoImpl
import com.atlassian.plugin.PluginAccessor
import com.atlassian.plugin.PluginManager
import com.atlassian.jira.bc.license.JiraLicenseService
import com.atlassian.jira.bc.license.JiraLicenseServiceImpl
import org.apache.log4j.Level
import org.apache.log4j.Logger
import com.atlassian.jira.issue.IssueManager
import com.opensymphony.workflow.InvalidInputException
import java.net.HttpURLConnection

import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.json.JsonOutput
import groovy.transform.BaseScript
import groovy.json.JsonSlurper;
import groovy.json.StreamingJsonBuilder;
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response
 
@BaseScript CustomEndpointDelegate delegate


issueManager = ComponentAccessor.getIssueManager()
searchService =  ComponentAccessor.getComponent(SearchService.class);
serviceAccount = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
customFieldManager = ComponentAccessor.getCustomFieldManager()

Object getIssues(jqlQuery){
    // A list of GenericValues representing issues
    List<Issue> searchResults = null;

    SearchService.ParseResult parseResult =  searchService.parseQuery(serviceAccount, jqlQuery);

    if (parseResult.isValid()) {
        // throws SearchException
        SearchResults results = searchService.search(serviceAccount, parseResult.getQuery(), PagerFilter.getUnlimitedFilter());
        searchResults = results.getIssues();
        return searchResults;
    } 
            
     return [] 
}


Object getFieldValue(issue,customField) {
    //def cField = customFieldManager.getCustomFieldObject(customField)
    def cField = customFieldManager.getCustomFieldObjectByName(customField)
    def cFieldValue = issue.getCustomFieldValue(cField)
    return cFieldValue
}

String replaceLast(String string, String substring, String replacement)
{
  int index = string.lastIndexOf(substring);
  if (index == -1)
    return string;
  return string.substring(0, index) + replacement + string.substring(index+substring.length());
}


triggerJenkinsBuildWithTestList(httpMethod: "GET") { MultivaluedMap queryParams ->
 
	// the details of getting and modifying the current issue are ommitted for brevity
	def issueId = queryParams.getFirst("issueId") as String // use the issueId to retrieve this issue
	

	def flag = [
	type : 'success',
	title: "Build scheduled",
	close: 'auto',
	body : "A new build has been scheduled related with "+issueId
	]
   

	URL url;
	def jobName = "java-junit-calc-triggered"               // could be defined in a CF in the Test Plan
	def jenkinsHostPort = "192.168.56.102:8081"             // could be defined elsewhere
	def token = "iFBDOBhNhaxL4T9ass93HRXun2JF161Z"  		// could also come from a CF in the Test Plan
	def username = "admin"									// probably, would need to be stored elsewhere
	def password = "fa02840152aa2e4da3d8db933ec708d6"		// probably, would need to be stored elsewhere
	//def baseURL = "http://${username}:${password}@${jenkinsHostPort}/job/${jobName}/build?token=${token}"
	//def baseURL = "http://${jenkinsHostPort}/job/${jobName}/build?token=${token}"

	jql = "issue in testPlanTests('${issueId}') and \"Test Type\" = Generic"
	issues = getIssues(jql)
    // we're assuming that we have Junit based Tests.. so we need to do some conversion beforehand, so maven can process the list of tests to be run
	def testlist = issues.collect { getFieldValue(it,"Generic Test Definition")}
	def testlist2 = testlist.collect { replaceLast(it,".","%23") }
    
	def baseURL = "http://${jenkinsHostPort}/job/${jobName}/buildWithParameters?token=${token}&TESTPLAN=${issueId}&TESTLIST=${testlist2.join(',')}"
	url = new URL(baseURL);
	def body_req = []

	def authString = "${username}:${password}".bytes.encodeBase64().toString()

	URLConnection    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
	    connection.requestMethod = setRequestMethod("POST")
	    connection.doOutput = truesetDoOutput(true)
	connection.addRequestProperty("Authorization", "Basic ${authString}")
	connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8")
	connection.outputStream.withWriter("UTF-8") { new StreamingJsonBuilder(it, body_req) }
	connection.connect();
	//connection.getContent();
	log.debug(connection.getResponseCode())
	log.debug(connection.getResponseMessage())

    
	if (connection.getResponseCode() == 201) {
 		Response.ok(JsonOutput.toJson(flag)).build()
 	} else {
 		//Response.status(Response.Status.NOT_FOUND).entity("Problem scheduling job!").build();
 	}
    
}

...

Code Block
languagegroovy
titletrigger_bamboo_build_restapi_endpoint.groovy
collapsetrue
import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.json.JsonOutput
import groovy.transform.BaseScript
import groovy.json.JsonSlurper;
import groovy.json.StreamingJsonBuilder;
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response
import java.nio.charset.StandardCharsets
import java.net.HttpURLConnection

@BaseScript CustomEndpointDelegate delegate
 
triggerBambooBuild(httpMethod: "GET") { MultivaluedMap queryParams ->
 
	def issueId = queryParams.getFirst("issueId") as String // use the issueId to retrieve this issue
	 
	def flag = [
	type : 'success',
	title: "Build scheduled",
	close: 'auto',
	body : "A new build has been scheduled related with "+issueId
	]
   

	URL url;
	// curl --user admin:admin -X POST -d "default&ExecuteAllStages=true" http://yourbambooserver/rest/api/latest/queue/XRAY-JUNITCALC
	def projectKey = "XRAY"									// could come from a CF in the Test Plan
    def planKey = "JUNITCALC"								// could come from a CF in the Test Plan
	def bambooHostPort = "192.168.56.102:8085"				// could be defined elsewhere
	def username = "admin"									// probably, would need to be stored elesewhere
	def password = "admin"									// probably, would need to be stored elesewhere
	def baseURL = "http://${bambooHostPort}/rest/api/latest/queue/${projectKey}-${planKey}"
    String urlParameters  = "default&ExecuteAllStages=true&bamboo.TESTPLAN=${issueId}";
    byte[] postData       = urlParameters.getBytes( StandardCharsets.UTF_8 );
    int    postDataLength = postData.length;
    
	url = new URL(baseURL);
	def body_req = []

	def authString = "${username}:${password}".bytes.encodeBase64().toString()

	URLConnection    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
	    connection.requestMethod = setRequestMethod("POST")
	    connection.doOutput = truesetDoOutput(true)
	connection.addRequestProperty("Authorization", "Basic ${authString}")
    connection.setRequestProperty( "Content-Type", "application/x-www-form-urlencoded"); 
    connection.setRequestProperty( "charset", "utf-8");
    connection.setRequestProperty( "Content-Length", Integer.toString( postDataLength ));
    connection.setUseCaches( false );

    DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
    wr.write( postData );

	connection.connect();
	//connection.getContent();
	log.debug(connection.getResponseCode())
	log.debug(connection.getResponseMessage())

    
	if (connection.getResponseCode() == 200) {
 		Response.ok(JsonOutput.toJson(flag)).build()
 	} else {
 		//Response.status(Response.Status.NOT_FOUND).entity("Problem scheduling job!").build();
 	}
    
}

...

Code Block
languagegroovy
titletrigger_bamboo_build_restapi_endpoint_with_testlist.groovy
collapsetrue
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.link.IssueLinkManager
import com.atlassian.jira.issue.link.IssueLinkType
import com.atlassian.jira.issue.link.IssueLinkTypeManager
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.jql.builder.JqlQueryBuilder
import com.atlassian.jira.user.util.UserUtil
import com.atlassian.jira.user.util.UserManager;
import com.atlassian.jira.bc.issue.IssueService
import com.atlassian.jira.bc.issue.search.SearchService;
import com.atlassian.jira.issue.search.SearchProvider
import com.atlassian.jira.issue.search.SearchResults
import com.atlassian.jira.web.bean.PagerFilter;
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.user.UserPropertyManager
import com.atlassian.jira.propertyset.JiraPropertySetFactory;
import com.google.common.collect.ImmutableMap;
import com.opensymphony.module.propertyset.PropertySet;
import com.opensymphony.module.propertyset.PropertySetManager;
import com.atlassian.jira.util.BuildUtils
import com.atlassian.jira.util.BuildUtilsInfo
import com.atlassian.jira.util.BuildUtilsInfoImpl
import com.atlassian.plugin.PluginAccessor
import com.atlassian.plugin.PluginManager
import com.atlassian.jira.bc.license.JiraLicenseService
import com.atlassian.jira.bc.license.JiraLicenseServiceImpl
import org.apache.log4j.Level
import org.apache.log4j.Logger
import com.atlassian.jira.issue.IssueManager
import com.opensymphony.workflow.InvalidInputException
import java.net.HttpURLConnection



import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.json.JsonOutput
import groovy.transform.BaseScript
import groovy.json.JsonSlurper;
import groovy.json.StreamingJsonBuilder;
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response
import java.nio.charset.StandardCharsets

@BaseScript CustomEndpointDelegate delegate

issueManager = ComponentAccessor.getIssueManager()
searchService =  ComponentAccessor.getComponent(SearchService.class);
serviceAccount = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
customFieldManager = ComponentAccessor.getCustomFieldManager()


Object getIssues(jqlQuery){
    // A list of GenericValues representing issues
    List<Issue> searchResults = null;

    SearchService.ParseResult parseResult =  searchService.parseQuery(serviceAccount, jqlQuery);

    if (parseResult.isValid()) {
        // throws SearchException
        SearchResults results = searchService.search(serviceAccount, parseResult.getQuery(), PagerFilter.getUnlimitedFilter());
        searchResults = results.getIssues();
        return searchResults;
    } 
            
     return [] 
}

Object getFieldValue(issue,customField) {
    def cField = customFieldManager.getCustomFieldObjectByName(customField)
    def cFieldValue = issue.getCustomFieldValue(cField)
    return cFieldValue
}

String replaceLast(String string, String substring, String replacement)
{
  int index = string.lastIndexOf(substring);
  if (index == -1)
    return string;
  return string.substring(0, index) + replacement + string.substring(index+substring.length());
}
 
triggerBambooBuildWithTestList(httpMethod: "GET") { MultivaluedMap queryParams ->

	def issueId = queryParams.getFirst("issueId") as String // use the issueId to retrieve this issue
	 
	def flag = [
	type : 'success',
	title: "Build scheduled",
	close: 'auto',
	body : "A new build has been scheduled related with "+issueId
	]
   

	jql = "issue in testPlanTests('${issueId}') and \"Test Type\" = Generic"
	issues = getIssues(jql)
    // // we're assuming that we have Junit based Tests.. so we need to do some conversion beforehand, so maven can process the list of tests to be run
	def testlist = issues.collect { getFieldValue(it,"Generic Test Definition")}
    def testlist2 = testlist.collect { replaceLast(it,".","%23") }

	URL url;
	// curl --user admin:admin -X POST -d "default&ExecuteAllStages=true&bamboo.TESTLIST=com.xpand.java.CalcTest#CanAddNumbers" http://yourbambooserver/rest/api/latest/queue/XRAY-JUNITCALCPARAMS

	def projectKey = "XRAY"									// could come from a CF in the Test Plan
    def planKey = "JUNITCALCPARAMS"							// could come from a CF in the Test Plan
    def stage = "default"                                   // could be hardcoded or come from a CF in the Test Plan
	def bambooHostPort = "192.168.56.102:8085"				// could be defined elsewhere
	def username = "admin"									// probably, would need to be stored elsewhere
	def password = "admin"									// probably, would need to be stored elsewhere
	def baseURL = "http://${bambooHostPort}/rest/api/latest/queue/${projectKey}-${planKey}"
    String urlParameters  = "${stage}&ExecuteAllStages=true&bamboo.TESTPLAN=${issueId}&bamboo.TESTLIST=${testlist2.join(',')}";
    byte[] postData       = urlParameters.getBytes( StandardCharsets.UTF_8 );
    int    postDataLength = postData.length;
    
	url = new URL(baseURL);
	def body_req = []

	def authString = "${username}:${password}".bytes.encodeBase64().toString()

	URLConnection    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
	    connection.requestMethod = setRequestMethod("POST")
	    connection.doOutput = truesetDoOutput(true)
	connection.addRequestProperty("Authorization", "Basic ${authString}")
    connection.setRequestProperty( "Content-Type", "application/x-www-form-urlencoded"); 
    connection.setRequestProperty( "charset", "utf-8");
    connection.setRequestProperty( "Content-Length", Integer.toString( postDataLength ));
    connection.setUseCaches( false );

    DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
    wr.write( postData );

	connection.connect();
	//connection.getContent();
	log.debug(connection.getResponseCode())
	log.debug(connection.getResponseMessage())

    
	if (connection.getResponseCode() == 200) {
 		Response.ok(JsonOutput.toJson(flag)).build()
 	} else {
 		//Response.status(Response.Status.NOT_FOUND).entity("Problem scheduling job!").build();
 	}
    
}

...

Code Block
languagegroovy
titlesynchTestsFromRelatedTestSets_restapi_endpoint.groovy
collapsetrue
import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.json.JsonOutput
import groovy.transform.BaseScript
import groovy.json.JsonSlurper;
import groovy.json.StreamingJsonBuilder;
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response
import java.nio.charset.StandardCharsets
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.link.IssueLinkManager
import com.atlassian.jira.issue.link.IssueLinkType
import com.atlassian.jira.issue.link.IssueLinkTypeManager
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.jql.builder.JqlQueryBuilder
import com.atlassian.jira.user.util.UserUtil
import com.atlassian.jira.user.util.UserManager;
import com.atlassian.jira.bc.issue.IssueService
import com.atlassian.jira.bc.issue.search.SearchService;
import com.atlassian.jira.issue.search.SearchProvider
import com.atlassian.jira.issue.search.SearchResults
import com.atlassian.jira.web.bean.PagerFilter;
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.user.UserPropertyManager
import com.atlassian.jira.propertyset.JiraPropertySetFactory;
import com.google.common.collect.ImmutableMap;
import com.opensymphony.module.propertyset.PropertySet;
import com.opensymphony.module.propertyset.PropertySetManager;
import com.atlassian.jira.util.BuildUtils
import com.atlassian.jira.util.BuildUtilsInfo
import com.atlassian.jira.util.BuildUtilsInfoImpl
import com.atlassian.plugin.PluginAccessor
import com.atlassian.plugin.PluginManager
import com.atlassian.jira.bc.license.JiraLicenseService
import com.atlassian.jira.bc.license.JiraLicenseServiceImpl
import org.apache.log4j.Level
import org.apache.log4j.Logger
import com.atlassian.jira.issue.IssueManager
import groovy.json.StreamingJsonBuilder
 



@BaseScript CustomEndpointDelegate delegate
 

boolean associateTestsToXrayIssue(endpoint, issueKey,listOfTestKeys){
    def jiraBaseUrl = com.atlassian.jira.component.ComponentAccessor.getApplicationProperties().getString("jira.baseurl")
    def endpointUrl = "${jiraBaseUrl}/rest/raven/1.0/api/${endpoint}/${issueKey}/test"
    
    log.debug("issueKey: "+issueKey)
    log.debug("listOfTestKeys: "+listOfTestKeys)
    log.debug("jirabaseurl: "+jiraBaseUrl)
    log.debug("endpoint: "+endpointUrl)
    url = new URL(endpointUrl);
    def body_req = [ "add": listOfTestKeys ]

    // you should use a specific user for this purpose
    username = "admin"
    password = "admin"
    def authString = "${username}:${password}".bytes.encodeBase64().toString()

    URLConnectionHttpURLConnection connection = (HttpURLConnection) url.openConnection();
    connection.requestMethod = setRequestMethod("POST")
    connection.doOutput = truesetDoOutput(true)
    connection.addRequestProperty("Authorization", "Basic ${authString}")
    connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8")
    connection.outputStream.withWriter("UTF-8") { new StreamingJsonBuilder(it, body_req) }
    connection.connect();
    log.debug(connection.getResponseCode())
    log.debug(connection.getResponseMessage())

    if (connection.getResponseCode() == 200) {
        // OK
        return true;
    } else {
        // error
        return false;
    }
}

boolean associateTestsToTestPlan(testPlanKey, listOfTestKeys){
 return associateTestsToXrayIssue("testplan", testPlanKey, listOfTestKeys)
}

boolean associateTestsToTestExecution(testExecutionKey, listOfTestKeys){
 return associateTestsToXrayIssue("testexec", testExecutionKey, listOfTestKeys)
}



Object getIssues(jqlQuery){
    // A list of GenericValues representing issues
    List<Issue> searchResults = null;
    SearchService.ParseResult parseResult =  searchService.parseQuery(serviceAccount, jqlQuery);
  
    if (parseResult.isValid()) {
        // throws SearchException
        SearchResults results = searchService.search(serviceAccount, parseResult.getQuery(), PagerFilter.getUnlimitedFilter());
        searchResults = results.getIssues();
        return searchResults;
    }
  
     return []
}


synchTestsFromRelatedTestSets(httpMethod: "GET") { MultivaluedMap queryParams ->
    // issue_key may refer to a Test Plan or to a Test Execution
    def issue_key = queryParams.getFirst("issueId") as String // use the issueId to retrieve this issue
    
 
    projectManager = ComponentAccessor.getProjectManager()
    componentManager = ComponentManager.getInstance();
    searchService =  ComponentAccessor.getComponent(SearchService.class);
    issueManager = ComponentAccessor.getIssueManager()
    customFieldManager = ComponentAccessor.getCustomFieldManager()
    userUtil = ComponentAccessor.getUserUtil();
    serviceAccount = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
    pluginAccessor = componentManager.getPluginAccessor();
    
    MutableIssue issue = issueManager.getIssueObject(issue_key)

    Logger.getLogger("com.onresolve").setLevel(Level.DEBUG)

    // assume that Test Plan/Execution is linked to Test Sets using the issue link "relates to"; customize if needed
    jql = "issue in linkedIssues('${issue_key}', 'relates to')"
    testset_issues = getIssues(jql)
    def had_errors = false
    def success = false
    
    testset_issues.each {
        // process only "Test Set" issues
        if (it.issueType.name == "Test Set") {
            jql = "issue in testSetTests('${it.key}')"
            issues = getIssues(jql)
            test_keys = issues.collect{ it.key }
            //log.debug(test_keys)
            if (issue.issueType.name == "Test Plan") {
                success = associateTestsToTestPlan(issue_key, test_keys)
            } else if ((issue.issueType.name == "Sub Test Execution") || (issue.issueType.name == "Test Execution")) {
            	success = associateTestsToTestExecution(issue_key, test_keys)
            }
            if (!success) {
                had_errors = true
            }
        }
    }    
    
    def flag = []
    if (success) {
    	flag = [
            type : 'success',
            title: "Test Sets Synchronization",
            close: 'auto',
            body : "Tests have been synchronized for " + issue_key
    	]
        Response.ok(JsonOutput.toJson(flag)).build() 
    } else {
    	flag = [
            type : 'success',
            title: "Test Sets Synchronization",
            close: 'auto',
            body : "Tests have been synchronized for " + issue_key
    	] 
        Response.serverError().entity([error: "some Tests were no synchronized"]).build()
    }
	
}

...