Creating a project and issues in a post function

Marko Slijepčević June 29, 2021

Greetings everyone,

I was wondering if someone could provide some assistance regarding some development I am doing on Jira using script runner.
My problem is the following: I am creating a new project by using a workflow transition with a script runner post function in the "main project". This works fine, I am able to create the new project. Next, I had to extend this by adding some issues inside this project which are all copied from a template project.

This part that returns an error is when I run it simultaneously with the project creation code (all in the same post-function script - first, create the project then add issues to the project) -> The project gets created but with no issues inside.

But, when I run the same code for issue creating in a console it works fine, all issues are copied from the source project to the desired target project. The same happens when I run the transition and comment out the "create a new project" part and leave only the copy issues (while doing this, I hard code the project key.

So to conclude, when both code snippets are run independently they work fine, but when running them together (all in one post function, or even in two separate post functions on the same transition), the issue copying fails.

The business need is to have all this in one transition.

What I get are a couple of errors 

 

Caused by: com.atlassian.jira.workflow.WorkflowException: java.util.concurrent.ExecutionException: java.lang.IllegalStateException: Expected one match for [Expr::id::=::16188] but found 0: []
at com.atlassian.jira.workflow.OSWorkflowManager.createIssue(OSWorkflowManager.java:780)
at com.atlassian.jira.issue.managers.DefaultIssueManager.createIssue(DefaultIssueManager.java:592) (...)

 

Caused by: java.lang.RuntimeException: java.util.concurrent.ExecutionException: java.lang.IllegalStateException: Expected one match for [Expr::id::=::16188] but found 0: []

 

Error Messages: [We can't create this issue for you right now, it could be due to unsupported content you've entered into one or more of the issue fields. If this situation persists, contact your administrator as they'll be able to access more specific information in the log file.]. Expression: result.valid (...)

 

as far as I can see, it always references an issue with the ID 16188 not found which is the PID of the new project that was just created. 
Well, then I tried to log out the project with this ID during the execution of the transition by using 

ComponentAccessor.projectManager.getProjectObjByKey(16188 )

and I can successfully reach the project, but later when I have to use the project ID the errors occur.

I am using the IssueService class to create issues and as I said, it works when I run it in the console, for the same projects.

 

def issueInputParameters = issueService.newIssueInputParameters().with {
setProjectId(project.id)
setIssueTypeId(issueType.id)
setReporterId(reporter.name)
setSummary(summary)
setPriorityId(priorityId)
setAssigneeId(assignee)
}

def validationResult = issueService.validateCreate(loggedInUser, issueInputParameters)
assert validationResult.valid : validationResult.errorCollection

def result = issueService.create(loggedInUser, validationResult)
assert result.valid : result.errorCollection

 

All other parameters return legit values with correct data types.


What am I missing here?

Kind regards,
Marko

1 answer

0 votes
Peter-Dave Sheehan
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
June 29, 2021

Can you share how you are creating the new project and how the project variable is assigned?

My guess, without actually seeing the flow, is that perhaps your project object is created before you store/save the project and doesn't include the id yet. And then you try to apply that ID to the new issue.

Another possibility is that 16188 refers to either your issueType.id or the prioirtyId and somehow, those are not correctly associated with you new project so they can't be assigned to an issue in that project.

Seeing more of the overall flow would be helpful.

Marko Slijepčević June 30, 2021

Hi @Peter-Dave Sheehan

the new project is created by using this simple code snippet: 

def newProject = new ProjectCreationData.Builder().with {
withName(projectName)
withDescription(projectDescription)
withKey(projectKey)
withLead(projectLead)
withUrl(null)
withAssigneeType(AssigneeTypes.PROJECT_LEAD)
withType(projectTypeKey)
}.build()


final ProjectService.CreateProjectValidationResult projectValidationResult = projectService.validateCreateProjectBasedOnExistingProject(loggedUser, PROJECT_TEMPLATE_PID, newProject) // loggedUser = JIRA_AUTHOMATION user
//assert projectValidationResult.isValid() : projectValidationResult.errorCollection

projectService.createProject(projectValidationResult)

Some of these field input parameters are inputs from the transition screen so I fetch that data. The only exception is the way how the project key is being created. This is a sequential number from the database, which I format into 'P001' and update for every new project that comes. 

One reason why it is practical is to extend the project creation script with the issue creation part is that I can use the new project's key right away in the code for the issue creation.

Later in the part where I try to copy the issues (code is above, in the initial question), I assign the project to the newIssueInputParameters() method by using setProjectId(project.id), I fetch the project by using:

def project = ComponentAccessor.projectManager.getProjectObjByKey(projectKey)
assert project : "Could not find project with key $projectKey"

and this works fine I'd say because no assertion error gets returned and I can log the project.id value.

Another possibility is that 16188 refers to either your issueType.id or the prioirtyId

16188 refers to the project PID, I can confirm that 100%. The new project gets created and I can read the same ID.

 

My guess, without actually seeing the flow, is that perhaps your project object is created before you store/save the project and doesn't include the id yet. And then you try to apply that ID to the new issue.

I'd also say that this might be a legit reason for the post-function not working. The project gets created but not stored/committed in the database. I also tried to split this script into two post-functions (in the same transition) and by extending the database with current_key and new_key values, but it still didn't work.

Any advice on this how to force the project created to be stored?

 

BR,
Marko

Peter-Dave Sheehan
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
June 30, 2021

I would dig deeper into that assertion. Maybe try to output some logs to show what the project object includes like:

log.info "Attempted to retrieve project just created with $projectKey: id=$project.id key=$project.key"

If you can get the project object with getProjectObjByKey, then the project was finished being stored in the DB I think. So the issue might be elsewhere.

When you get the error, which line of your script throws it? Is it the validationResult assertion? The create line? Or the create result assertion?

Marko Slijepčević July 1, 2021

Hi @Peter-Dave Sheehan

thanks for the effort!

That's the strange thing and what actually bothers me, because I can fetch the project ID when logging it but it seems that I can not use it later in newIssueInputParameters()

Here are some logs wher I log the values out:

22.JPG

 

The error is thrown by the validationResult

def validationResult = issueService.validateCreate(loggedInUser, issueInputParameters)
assert validationResult.valid : validationResult.errorCollection

and of course the issueService.create method then fails as well

def result = issueService.create(loggedInUser, validationResult)
assert result.valid : result.errorCollection

 And the only thing the validationResult checks are these parameters:

 def issueInputParameters = issueService.newIssueInputParameters().with {
setProjectId(project.id)
setReporterId(reporter.name)
setSummary(summary)
}

and I am able to log them out as well so they are not null. Even the permission is right, because the loggedInUser (Me) can create issues in the destination project.

BR,
Marko

Omar Blagui July 6, 2021

Hi @Marko Slijepčević

I had the same problem, the workaround that I did is to create the project-based of another project. Here is the code that I used. Hope it will help you 

import com.atlassian.jira.component.ComponentAccessor
import com.onresolve.scriptrunner.canned.jira.admin.CopyProject
import org.apache.log4j.Logger
import org.apache.commons.lang.RandomStringUtils
import com.onresolve.scriptrunner.runner.util.UserMessageUtil
import com.atlassian.jira.issue.Issue
import java.util.Locale
import com.atlassian.jira.project.Project
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.util.IssueChangeHolder
import com.atlassian.jira.issue.ModifiedValue
import org.apache.commons.lang3.StringUtils
import org.apache.commons.lang.StringUtils
import com.atlassian.jira.config.properties.APKeys
import com.atlassian.jira.security.JiraAuthenticationContext
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.crowd.embedded.api.User
import com.atlassian.jira.user.preferences.PreferenceKeys
import com.atlassian.jira.user.preferences.UserPreferencesManager
def projectNameValue = issue.summary
// get current user
JiraAuthenticationContext jiraAuthenticationContext = ComponentAccessor.getOSGiComponentInstanceOfType(JiraAuthenticationContext.class);
Object userObject = jiraAuthenticationContext.getLoggedInUser();
User user = userObject instanceof ApplicationUser ? ((ApplicationUser) userObject).getDirectoryUser() : (User) userObject

def loggedInUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() as ApplicationUser
log.warn("user :"+loggedInUser)
String userLocale = ComponentAccessor.getUserPreferencesManager().getExtendedPreferences(loggedInUser).getString(PreferenceKeys.USER_LOCALE)




int length = 9
boolean useLetters = true
boolean useNumbers = false
String generatedString = RandomStringUtils.random(length, useLetters, useNumbers)
String vargeneratedString = generatedString.toUpperCase()
def copyProject = new CopyProject()
Thread executorThread = new Thread(new Runnable() {

void run() {

def inputs = [
(CopyProject.FIELD_SOURCE_PROJECT) : 'TEST', // The project that you will copy
(CopyProject.FIELD_TARGET_PROJECT) : vargeneratedString,
(CopyProject.FIELD_TARGET_PROJECT_NAME) : projectNameValue,
(CopyProject.FIELD_COPY_VERSIONS) : true,
(CopyProject.FIELD_COPY_COMPONENTS) : true,
(CopyProject.FIELD_COPY_ISSUES) : false,
(CopyProject.FIELD_COPY_DASH_AND_FILTERS) : false,
]
def errorCollection = copyProject.doValidate(inputs, false)
if(errorCollection.hasAnyErrors()) {
log.warn("Couldn't create project: $errorCollection")
}
else {
def util = ComponentAccessor.getUserUtil()
def adminsGroup = util.getGroupObject("jira-administrators")
assert adminsGroup // must have jira-administrators group defined
def admins = util.getAllUsersInGroups([adminsGroup])
assert admins // must have at least one admin
ComponentAccessor.getJiraAuthenticationContext().setLoggedInUser(util.getUserByName(admins.first().name))
copyProject.doScript(inputs)


}


}

})
executorThread.start()

executorThread.join()

UserMessageUtil.success('A new project ' + projectNameValue + ' has been created');
log.error('A new project ' + projectNameValue + ' has been created');


log.error("generated value: "+vargeneratedString)

Best regards,
Omar

Suggest an answer

Log in or Sign up to answer
TAGS
AUG Leaders

Atlassian Community Events