Page History
...
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
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() URLConnection connection = url.openConnection(); connection.requestMethod = "POST" connection.doOutput = 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() } } |
Example
Add a custom link to the Tests top menu
Sometimes it may be useful to add a custom link to the Tests top menu.
As an example, you may have an internal documentation/Confluence space with some valuable information concerning Xray usage in your organization.
ScripRunner configuration
Adding an entry to the top menu is easy.
Just go the Add-ons section in your Jira administration and then "Script Fragments".
Add a new "Raw xml module".
And add the configuration for the link; this configuration is exactly the same as if you were going to develop your own app, so it follows Atlassian developer documentation guidelines for the "web-item" element.
Make sure the "web-item" as a "weight" value higher than 120, to append your link to the end of the options available from the dropdown menu.
Example
Let's say that we want to add a link to "https://getxray.app" in the top Test menu, having the name "My Custom Link".
The "raw xml module" configuration would be something similar to the following snippet.
Code Block |
---|
<web-item key="xray-topnav-tests-meta-customlink" name="Custom link" section="raven-menu/xray.topnav.meta.section" weight="130">
<label>My Custom Link</label>
<link linkId="raven-topnav-test-item-meta.customlink">https://getxray.app</link>
</web-item> |