Hello,
We have the following use-case:
- text field called "DoD"
- text field called "Acceptance Criteria"
- checklist field called "Story DoD" (from here: https://marketplace.atlassian.com/apps/1211562/checklist-for-jira?hosting=server&tab=overview)
When "acceptance criteria" is filled in, then the text field "DoD" should get the text:
"Acceptance Criteria defined" to it.
When all the checkboxes in "Story DoD" are filled in, the text field "DoD" (same one as above), should get the text "All checkboxes checked" appended to it.
First I tried with two listeners, but then I realized that the update of one of them can trigger the other and vice-versa.
I am having problems putting them together in just on script.
What I managed so far is below:
import com.atlassian.jira.component.ComponentAccessor
import com.opensymphony.workflow.InvalidInputException
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.security.JiraAuthenticationContext
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def optionsManager = ComponentAccessor.getOptionsManager()
def fieldConfigSchemeManager = ComponentAccessor.getFieldConfigSchemeManager()
def issue = event.issue as MutableIssue
def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
def DoD= ComponentAccessor.customFieldManager.getCustomFieldObjectByName("DoD")
def DoDValue = issue.getCustomFieldValue(DoD)
String appendedmessage1 = 'All the checkboxes in the Story DoD field are checked'
def StoryCheckbox = customFieldManager.getCustomFieldObjectByName("Story DoD")
def config = fieldConfigSchemeManager.getRelevantConfig(issue, StoryCheckbox)
def allOptions = optionsManager.getOptions(config)
def criteria = ComponentAccessor.customFieldManager.getCustomFieldObjectByName("Acceptance Criteria")
def criteriavalue = issue.getCustomFieldValue(criteria)
String appendedmessage2 = 'Acceptance Criteria defined'
Boolean alreadyAddedMessage1 = criteriavalue.indexOf(appendedmessage1) != -1
Boolean alreadyAddedMessage2 = criteriavalue.indexOf(appendedmessage2) != -1
I am having problems putting the condition in place.
Any help is appreciated.
Thank you!
Hi,
What happens if "Acceptance criteria" is filled and all the checkboxes in "Story DoD" are checked ?
I'm pretty sure you should handle this in one listener.
Hello,
Yes, it should be one listener, because in two different ones the message posted by one could trigger the other. However, I'm having troubles putting it together in just one script.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Have you identified which part is giving you troubles ?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Sorry for the late reply, I was off some days.
I am having problems updating the issue when is has all the checkboxes checked. When "Acceptance Criteria" is filled in, it works. The bad part is that it replaces instead of appending, but I can figure that out later.
Please check what I have below and let me know if you have any suggestions.
Thank you!
switch (!alreadyAddedMessage1) {
case true:
if (!alreadyAddedMessage2)
{
if (criteriavalue) {
issue.setCustomFieldValue(
customFieldManager.getCustomFieldObjectByName("DoD")
, appendedmessage2,
)
}
else if (issue.getCustomFieldValue(StoryCheckbox) == allOptions) {
issue.setCustomFieldValue(
customFieldManager.getCustomFieldObjectByName("DoD")
, appendedmessage1
)
}
};
break
case false:
if (!alreadyAddedMessage2)
{
if (criteriavalue) {
issue.setCustomFieldValue(
customFieldManager.getCustomFieldObjectByName("DoD")
, appendedmessage2,
)
}
};
break
}
ComponentAccessor.getIssueManager().updateIssue(user,issue, EventDispatchOption.DO_NOT_DISPATCH, false)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi @Mihai Mihai ,
re-reading this, I have a few questions. Why do you need to fill this acceptance criteria field ? Why use a text-field over standard checkbox field ?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
We could not get everybody to use the same values for the checkboxes.
Some product owners also wanted a free text field where they could add items specific to them.
We have a very large instance with over 140 projects, and we tried to satisfy many different projects with the same schema, so stuff like this appeared.
Changing the way things are right now would not be a possibility for us.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I see, it might be tough to change something used among that many users. I checked the code and this is how I would do it :
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.ModifiedValue
int cfDoDId = 11001
int cfAcceptanceCriteriaId = 11002
int cfStoryDoDId = 11003
def cfDoD = customFieldManager.getCustomFieldObject(cfDoDId)
def cfAcceptanceCriteria = customFieldManager.getCustomFieldObject(cfAcceptanceCriteria)
def cfStoryDoD = customFieldManager.getCustomFieldObject(cfStoryDoDId)
def cfAcceptanceCriteriaChanged = event?.getChangeLog()?.getRelated("ChildChangeItem")?.find {it.field == "Acceptance Criteria"}
if (cfAcceptanceCriteriaChanged){
def cfAcceptanceCriteriaValue = issue.getCustomFieldValue(cfAcceptanceCriteria)
def cfDoDValue = issue.getCustomFieldValue(cfDoD)
if (cfAcceptanceCriteriaValue != null && cfAcceptanceCriteriaValue != "" && cfDoDValue.indexOf("Acceptance Criteria defined") == -1){
def cfDoDNewValue = (cfDoDValue == "") ? "Acceptance Criteria defined" : cfDoDValue + " & Acceptance Criteria defined"
cfDoD.updateValue(null, issue, new ModifiedValue(cfDoDValue, cfDoDNewValue), new DefaultIssueChangeHolder())
}
}
def cfStoryDoDChanged = event?.getChangeLog()?.getRelated("ChildChangeItem")?.find {it.field == "Story DoD"}
if (cfStoryDoDChanged){
def cfStoryDoDValue = issue.getCustomFieldValue(cfStoryDoD)
log.error("cfStoryDoDValue : " + cfStoryDoDValue)
log.error("cfStoryDoDValue class : " + cfStoryDoDValue.getClass())
def config = ComponentAccessor.getFieldConfigSchemeManager().getRelevantConfig(issue, cfStoryDoD)
def allOptions = optionsManager.getOptions(config)
def cfDoDValue = issue.getCustomFieldValue(cfDoD)
if (cfStoryDoDValue != null && cfStoryDoDValue == allOptions && cfDoDValue.indexOf("All checkboxes checked") == -1){
def cfDoDNewValue = (cfDoDValue == "") ? "All checkboxes checked" : cfDoDValue + " & All checkboxes checked"
cfDoD.updateValue(null, issue, new ModifiedValue(cfDoDValue, cfDoDNewValue), new DefaultIssueChangeHolder())
}
}
assuming your "allOptions" variable indeed is equal to the custom field value when all the checkboxes are checked. I do not have the plug-in so you have to make sure this is the case (that is why I put some logs there).
Also, ensure that this listener is triggered by each event where the user can change these values (I guess Issue Updated, but you should care also for transitions).
Antoine
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thank you very much for your reply.
I tried it, but get one error, and the updates are not done, probably because of it:
java.lang.NullPointerException: Cannot invoke method indexOf() on null object
"Acceptance Criteria" has some values in it, the checkboxes are also all checked.
Do you have any suggestion for this?
Thank you!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi,
That is my bad, I had in mind that empty text field would return "", but it returns null.
Try :
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.ModifiedValue
int cfDoDId = 11001
int cfAcceptanceCriteriaId = 11002
int cfStoryDoDId = 11003
def cfDoD = customFieldManager.getCustomFieldObject(cfDoDId)
def cfAcceptanceCriteria = customFieldManager.getCustomFieldObject(cfAcceptanceCriteria)
def cfStoryDoD = customFieldManager.getCustomFieldObject(cfStoryDoDId)
def cfAcceptanceCriteriaChanged = event?.getChangeLog()?.getRelated("ChildChangeItem")?.find {it.field == "Acceptance Criteria"}
if (cfAcceptanceCriteriaChanged){
def cfAcceptanceCriteriaValue = issue.getCustomFieldValue(cfAcceptanceCriteria)
def cfDoDValue = issue.getCustomFieldValue(cfDoD)
if (cfAcceptanceCriteriaValue != null && cfAcceptanceCriteriaValue != "" && (cfDoDValue == null || cfDoDValue.indexOf("Acceptance Criteria defined") == -1)){
def cfDoDNewValue = (cfDoDValue == null) ? "Acceptance Criteria defined" : cfDoDValue + " & Acceptance Criteria defined"
cfDoD.updateValue(null, issue, new ModifiedValue(cfDoDValue, cfDoDNewValue), new DefaultIssueChangeHolder())
}
}
def cfStoryDoDChanged = event?.getChangeLog()?.getRelated("ChildChangeItem")?.find {it.field == "Story DoD"}
if (cfStoryDoDChanged){
def cfStoryDoDValue = issue.getCustomFieldValue(cfStoryDoD)
log.error("cfStoryDoDValue : " + cfStoryDoDValue)
log.error("cfStoryDoDValue class : " + cfStoryDoDValue.getClass())
def config = ComponentAccessor.getFieldConfigSchemeManager().getRelevantConfig(issue, cfStoryDoD)
def allOptions = optionsManager.getOptions(config)
def cfDoDValue = issue.getCustomFieldValue(cfDoD)
if (cfStoryDoDValue != null && cfStoryDoDValue == allOptions && (cfDoDValue == null || cfDoDValue.indexOf("All checkboxes checked") == -1)){
def cfDoDNewValue = (cfDoDValue == null) ? "All checkboxes checked" : cfDoDValue + " & All checkboxes checked"
cfDoD.updateValue(null, issue, new ModifiedValue(cfDoDValue, cfDoDNewValue), new DefaultIssueChangeHolder())
}
}
Antoine
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thank you very much. That solves that error, and now the listeners themselves have a check-mark, but the change is only actually being made for the acceptance criteria field, not also when the checkboxes field has the checkboxes checked, like you thought might happen.
Looking in the logs, I see this:
2019-04-11 12:25:36,840 ERROR [runner.ScriptRunnerImpl]: cfStoryDoDValue : [Story description understood and complete, Impact and risk are analyzed and understood, Feasible in time and cost, No impediment identified, Can be verified] 2019-04-11 12:25:36,841 ERROR [runner.ScriptRunnerImpl]: cfStoryDoDValue class : class java.util.ArrayList
Do you have any suggestions for this?
Thank you!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi,
Indeed we need to figure what value your checkbox field is expecting. Please add :
log.error("cfStoryDoDValue[0] class : " + cfStoryDoDValue[0].getClass())
log.error("allOptions : " + allOptions)
log.error("allOptions class : " + allOptions.getClass())
log.error("allOptions[0] class : " + allOptions.getClass())
Towards the end where these variables are valued. Also try to update the Story DoD custom field only to test it, and not the acceptance criteria, because I am not sure how the listener would react in that case.
Antoine
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I added those and these are the errors:
2019-04-11 14:08:52,006 ERROR [runner.ScriptRunnerImpl]: cfStoryDoDValue : [Story description understood and complete, Impact and risk are analyzed and understood, Feasible in time and cost, No impediment identified, Can be verified] 2019-04-11 14:08:52,006 ERROR [runner.ScriptRunnerImpl]: cfStoryDoDValue class : class java.util.ArrayList 2019-04-11 14:08:52,008 ERROR [runner.ScriptRunnerImpl]: allOptions : [Story description understood and complete, Impact and risk are analyzed and understood, Feasible in time and cost, No impediment identified, Can be verified] 2019-04-11 14:08:52,008 ERROR [runner.ScriptRunnerImpl]: allOptions class : class com.atlassian.jira.issue.customfields.option.OptionsImpl 2019-04-11 14:08:52,011 ERROR [runner.AbstractScriptListener]: ************************************************************************************* 2019-04-11 14:08:52,011 ERROR [runner.AbstractScriptListener]: Script function failed on event: com.atlassian.jira.event.issue.IssueEvent, file: com/listeners/IIPDoRUpdate_V3.groovy groovy.lang.MissingMethodException: No signature of method: org.apache.log4j.Logger.error() is applicable for argument types: (java.lang.String, IIPDoRUpdate_V3$_run_closure3) values: [allOptions[0] class : class com.atlassian.jira.issue.customfields.option.OptionsImpl, ...] Possible solutions: error(java.lang.Object), error(java.lang.Object, java.lang.Throwable), grep(), iterator(), every(), getRoot() at IIPDoRUpdate_V3.run(IIPDoRUpdate_V3.groovy:48)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Please add this one :
log.error("cfStoryDoDValue[0] class : " + cfStoryDoDValue[0].getClass())
and replace this
log.error("allOptions[0] class : " + allOptions.getClass())
by this :
log.error("allOptions[0] class : " + allOptions.get(0).getClass())
Thanks
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I did the changes. These are the results:
2019-04-11 14:23:55,627 ERROR [runner.AbstractScriptListener]: ************************************************************************************* 2019-04-11 14:23:55,628 ERROR [runner.AbstractScriptListener]: Script function failed on event: com.atlassian.jira.event.issue.IssueEvent, file: com/listeners/IIPDoRUpdate_V3.groovy groovy.lang.MissingMethodException: No signature of method: org.apache.log4j.Logger.error() is applicable for argument types: (java.lang.String, IIPDoRUpdate_V3$_run_closure3) values: [allOptions[0] class : class com.atlassian.jira.issue.customfields.option.LazyLoadedOption, ...] Possible solutions: error(java.lang.Object), error(java.lang.Object, java.lang.Throwable), grep(), iterator(), every(), getRoot() at IIPDoRUpdate_V3.run(IIPDoRUpdate_V3.groovy:45)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Update: changed their place and I think this is what you were looking for:
2019-04-11 14:26:37,925 ERROR [runner.ScriptRunnerImpl]: cfStoryDoDValue[0] class : class com.okapya.jira.customfields.ChecklistItem 2019-04-11 14:26:37,925 ERROR [runner.ScriptRunnerImpl]: allOptions[0] class : class com.atlassian.jira.issue.customfields.option.LazyLoadedOption
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I think the best and only way to check then is to compare the size then, try to use :
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.ModifiedValue
int cfDoDId = 11001
int cfAcceptanceCriteriaId = 11002
int cfStoryDoDId = 11003
def cfDoD = customFieldManager.getCustomFieldObject(cfDoDId)
def cfAcceptanceCriteria = customFieldManager.getCustomFieldObject(cfAcceptanceCriteria)
def cfStoryDoD = customFieldManager.getCustomFieldObject(cfStoryDoDId)
def cfAcceptanceCriteriaChanged = event?.getChangeLog()?.getRelated("ChildChangeItem")?.find {it.field == "Acceptance Criteria"}
if (cfAcceptanceCriteriaChanged){
def cfAcceptanceCriteriaValue = issue.getCustomFieldValue(cfAcceptanceCriteria)
def cfDoDValue = issue.getCustomFieldValue(cfDoD)
if (cfAcceptanceCriteriaValue != null && cfAcceptanceCriteriaValue != "" && (cfDoDValue == null || cfDoDValue.indexOf("Acceptance Criteria defined") == -1)){
def cfDoDNewValue = (cfDoDValue == null) ? "Acceptance Criteria defined" : cfDoDValue + " & Acceptance Criteria defined"
cfDoD.updateValue(null, issue, new ModifiedValue(cfDoDValue, cfDoDNewValue), new DefaultIssueChangeHolder())
}
}
def cfStoryDoDChanged = event?.getChangeLog()?.getRelated("ChildChangeItem")?.find {it.field == "Story DoD"}
if (cfStoryDoDChanged){
def cfStoryDoDValue = issue.getCustomFieldValue(cfStoryDoD)
log.error("cfStoryDoDValue : " + cfStoryDoDValue)
log.error("cfStoryDoDValue class : " + cfStoryDoDValue.getClass())
def config = ComponentAccessor.getFieldConfigSchemeManager().getRelevantConfig(issue, cfStoryDoD)
def allOptions = optionsManager.getOptions(config)
def cfDoDValue = issue.getCustomFieldValue(cfDoD)
if (cfStoryDoDValue != null && cfStoryDoDValue.size() == allOptions.size() && (cfDoDValue == null || cfDoDValue.indexOf("All checkboxes checked") == -1)){
def cfDoDNewValue = (cfDoDValue == null) ? "All checkboxes checked" : cfDoDValue + " & All checkboxes checked"
cfDoD.updateValue(null, issue, new ModifiedValue(cfDoDValue, cfDoDNewValue), new DefaultIssueChangeHolder())
}
}
Antoine
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
This unfortunately adds the "All checkboxes checked" message with every update of the checkbox field, no matter if it has 1 checkbox checked out of 5, 2 out of 5, 3 out of 5 , 4 out of 5 or actually all 5.
Thank you.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
We have a requirement, as one of our internal team has moved from a "different system" to Jira ServiceDesk. In their different system, they have the following fields
1. Impact- a dropdown custom field with options I1 I2 I3 I4
2. Urgency - a dropdown custom field with options U1 U2 U3 U4
3. Priority - a dropdown system field with options P1 P2 P3 P4
4. Weight - Single-line textbox which holds a number(n1 n2 n3 n4 n5...n10)
I could do the following:
While creating issue users will choose impact and urgency. If Impact is I1 and urgency U2 I can update Priority(P3) and Weight(n3).
I couldn't achieve:
I would like to develop the same functionality when Impact & Urgency is edited. If edited, priority & weight should get updated as well.
Any help is very much appreciated. I tried something similar with a text box but now with options.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi @Sysad ,
May you please open a new Question ? That way other members of the community will be able to answer. I will gladly look into it. Also please specify how you were able to achieve the update.
Antoine
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Also you can link the new thread here so I can check it. :)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thank you for the response. Here is the link
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I used inbuilt automation in JSD to get this auto field update when an issue is created and need help on issue edit.
When issue's Impact or Urgency changes/edited then priority and weight should change
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I think I got lucky and found something useful:
cfStoryDoDValue.every({ it.checked })
seems to do the trick.
My last condition is now:
if (cfStoryDoDValue != null && cfStoryDoDValue.every({ it.checked }) && (cfDoDValue == null || cfDoDValue.indexOf("All checkboxes checked") == -1)){
def cfDoDNewValue = (cfDoDValue == null) ? "All checkboxes checked" : cfDoDValue + " & All checkboxes checked"
cfDoD.updateValue(null, issue, new ModifiedValue(cfDoDValue, cfDoDNewValue), new DefaultIssueChangeHolder())
and it only adds the text if actually all the items are checked.
However, I did see that if I update "Acceptance Criteria" and not also the checkbox field, the proper message for acceptance criteria is added.
If I do not update acceptance criteria and I do check the boxes (all of them), the proper message is added.
If I update both acceptance criteria and the checkbox field, only the message for the checkbox field is added.
Thank you!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Good job ! I was doing some testing on my part but it is harder without having the plugin.
For the last issue, try adding
def issueIndexingService = ComponentAccessor.getComponent(IssueIndexingService)
issue.store()
issueIndexingService.reIndex(issue)
just before
def cfStoryDoDChanged = event?.getChangeLog()?.getRelated("ChildChangeItem")?.find {it.field == "Story DoD"}
and
import com.atlassian.jira.issue.index.IssueIndexingService
to the imports.
If that does not work, you will need to check if both fields have been updated, i.e.
if (cfAcceptanceCriteriaChanged && cfStoryDoDChanged){ ...
Antoine
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thanks for the tip again @Antoine Berry
I needed the
if (cfAcceptanceCriteriaChanged && cfStoryDoDChanged){
part that you suggested. Now it works.
Again, thanks for all your help!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Online forums and learning are now in one easy-to-use experience.
By continuing, you accept the updated Community Terms of Use and acknowledge the Privacy Policy. Your public name, photo, and achievements may be publicly visible and available in search engines.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.