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)
}



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)

}

Validate requirement

...

upon making a transition

Sometimes you may need to assure that the requirement is actually OK covered before transitioning it to some status, or before resolving it.

The following script validates the requirement based on the directly linked tests executed for the version assigned to the requirement issue.

You can either make the validation based on the existence of failed tests  (i.e. requirement status is "NOK") or, in a more complete way by making sure all of them are passing (i.e. requirement status is "OK").

.



Info
titlePlease note

This solution is not perfect for several reasons, so please take the following notes into consideration:

  1. this should be implemented as a workflow condition (currently it's not possible with ScriptRunner on Jira Cloud)
  2. the tests association should be validated properly, based on all the direct linked tests and on the ones linked to "sub-requirements"


You need to:

  1. edit the workflow transition of the "coverable issue" (e.g. story, requirement), by editing the related workflow
  2. add a ScriptRunner Post Function, in the Post Functions tab  


Image Added


Image Added


Code Block
languagegroovy
titleScript content
collapsetrue
Map<String, Object> searchResult = get('/rest/api/2/search')
Code Block
languagegroovy
titlerequirement_validation.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.component.ComponentAccessor
import com.atlassian.jira.jql.builder.JqlQueryBuilder
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.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


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;
    } 
        .queryString('jql', "key   
     return [] 
}


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

Issue issue = issue;

log.debug(issue.project.name)
projectName = issue.project.name
version = issue.fixVersions.join('')
log.debug(version)
    
//jql = "key = ${issue.key} and issue in requirements('NOK','${projectName}','${version}')"
jql = "key = ${issue.key} and issue in requirements('OK','${projectName}','${version}')"
issues = getIssues(jql)
count = issues.size 
//log.debug(count)

/*
if (count>0) {
    invalidInputException = new InvalidInputException("Some tests are failing. You must assure that they pass before making the transition.")
}
*/

if (count == 0) {
    invalidInputException = new InvalidInputException("Some tests need to be executed. You must assure that they pass before making the transition.")= ${issue.key} and hasLinks = 'is tested by'")
        .asObject(Map)
        .body 

// if no Tests linked, then force a certain transition (i.e. rollback it)
if (searchResult.issues.size == 0) {
    def res = post("/rest/api/2/issue/" + issue.key + "/transitions")
    .header("Content-Type", "application/json")
    .body([
        "transition": [
            "id": "301"
        ]
    ])
    .asString()
    //assert res.status == 204    
}


Reopen/transition linked Tests to a requirement

...