How to Clear a User Custom Field using Groovy

Ops Lead February 27, 2012

Hi,

when a feedback was given I want to clear the field with a post function:

CustomFieldManager customFieldManager = componentManager.getCustomFieldManager()
IssueChangeHolder changeHolder = new DefaultIssueChangeHolder();
Issue issue  = issue

def cfNFF = customFieldManager.getCustomFieldObjects(issue).find {it.name == 'Need Feedback From'}
def cfNFFval = issue.getCustomFieldValue(cfNFF)
log.warn "Need Feedback From: '"+cfNFFval+"'"
if ( cfNFFval ) {
   log.warn "Need Feedback From: '"+cfNFFval+"' cleared to"
   cfNFF.updateValue(null, issue, new ModifiedValue(cfNFFval, new UserCFType(null)), changeHolder); // ???
   log.warn "Need Feedback From: '"+issue.getCustomFieldValue(cfNFF)+"'"
} else {
   log.info "Need Feedback From: '"+cfNFFval+"' already cleared"
}

At the line marked I get an error because

new UserCFType(null)

is not allowed here. I tried 'null' but this also did not work

a) How do I have to insert an empty UserCFType value here?

b) Is there a better solution to clear the field?

Thank you

4 answers

1 accepted

0 votes
Answer accepted
Ops Lead March 4, 2012

Hi,

using setFieldValue() solves the issue. Here the complete Groovy code of the post function:

import org.apache.log4j.Category
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.issue.ModifiedValue
import com.googlecode.jsu.util.WorkflowUtils

log = Category.getInstance("post-clear-need_feedback_from.groovy")
log.warn "begin"

// issue is provided by environment
log.warn "issue "+issue.getKey()
cfm    = componentManager.getCustomFieldManager()
ch     = new DefaultIssueChangeHolder();
nff   = cfm.getCustomFieldObjects(issue).find {it.name == 'Need Feedback From'}
cfv   = issue.getCustomFieldValue(nff)
log.warn "Need Feedback From = '"+cfv+"' cleared"
// mv    = new ModifiedValue(nff, null)  // only for updateValue()
// nff.updateValue(null, issue, mv, ch)  // does not work when called as a post function
WorkflowUtils.setFieldValue(issue, nff, null, ch) // does work!
log.warn "end"

Does also work with Ruby.

You need the jira-plugin-pack which includes WorkflowUtils. I downloaded it from http://code.google.com/p/jira-plugin-pack/downloads/detail?name=jira-plugin-pack-1.0.0.jar .

JamieA
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
March 4, 2012

Did you try issue.setCustomFieldValue()? You should not need JSU.

Ops Lead March 4, 2012

No, look at http://docs.atlassian.com/software/jira/docs/api/4.4.4/ :

 void 	setCustomFieldValue(CustomField customField, Object value)
          Sets a custom field value on this Issue Object, but does not write it to the database.

JamieA
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
March 4, 2012

Yes, but then you call issue.store() to write to the database. This is all that JSU is doing.

Ops Lead March 6, 2012

Hi Jamie,

this does _not_ work:

...
mv  = new ModifiedValue(nff, null)
nff.updateValue(null, issue, mv, ch)
issue.store()
JamieA
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
March 6, 2012

I was suggesting to try setCustomFieldValue, store.

Ops Lead March 6, 2012

Sorry, my fault. Now it works:

...
log.warn "Need Feedback From = '"+cfv+"' cleared"
issue.setCustomFieldValue(nff, null)
issue.store()

For me that's the smallest and best code to solve the problem.

Thank you.

0 votes
Brian Bishop
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
November 10, 2016

found out issue.store() has been deprecated and no longer persists the data (at least in my particular setup) the key is:

updIssue = issueManager.updateIssue(currentUser, issue, UpdateIssueRequest.builder().build())


with some context:

import com.atlassian.jira.issue.UpdateIssueRequest;
// blank out the New Work Item Name field
CustomField fieldToNullify = customFieldManager.getCustomFieldObject(11013)
issue.setCustomFieldValue(fieldToNullify, "")
updIssue = issueManager.updateIssue(currentUser, issue, UpdateIssueRequest.builder().build())
def blankedOutNewWorkItemName = issue.getCustomFieldValue(fieldToNullify)
log.debug "DBG: ending value of new work item name field: " + blankedOutNewWorkItemName

ImportUtils.indexIssues = wasIndexing
0 votes
Brian Bishop
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
November 10, 2016

Any idea why the debug log would indicate the nullifying code was working, and yet the UI always shows the last value?

 

// com.FactSet.CloneAndLinkTemplateWorkItem.groovy
package com.FactSet
import com.atlassian.crowd.embedded.api.User
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.user.ApplicationUsers
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.IssueFactory
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.issue.attachment.Attachment
import com.atlassian.jira.issue.link.IssueLinkManager
import com.atlassian.jira.issue.link.IssueLinkTypeManager
import com.atlassian.jira.issue.security.IssueSecurityLevel
import com.atlassian.jira.issue.AttachmentManager
import com.atlassian.jira.issue.security.IssueSecuritySchemeManager
import com.atlassian.jira.issue.link.IssueLinkType
import com.atlassian.jira.issue.fields.config.manager.IssueTypeSchemeManager
import com.atlassian.jira.issue.Issue 
import com.atlassian.jira.event.issue.IssueEvent
import com.atlassian.jira.issue.link.IssueLink
import com.atlassian.jira.issue.security.IssueSecurityLevelManager
import com.atlassian.jira.workflow.WorkflowFunctionUtils
import com.atlassian.jira.project.ProjectManager
import com.atlassian.jira.user.UserUtils
import com.atlassian.jira.util.ImportUtils
import com.opensymphony.workflow.WorkflowContext
import com.atlassian.jira.project.Project
import com.atlassian.jira.issue.security.IssueSecurityLevelScheme
import org.ofbiz.core.entity.GenericValue
import org.apache.log4j.Category
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.security.JiraAuthenticationContext

def Category log = Category.getInstance("com.onresolve.jira.groovy.PostFunction")
log.setLevel(org.apache.log4j.Level.DEBUG)
log.debug "DBG: Begin postfunction"
def wasIndexing = ImportUtils.indexIssues
def issueManager = ComponentAccessor.getComponent(IssueManager.class)
def projectManager = ComponentAccessor.getComponent(ProjectManager.class)
def linkManager = ComponentAccessor.getComponent(IssueLinkManager.class)
def linkTypeManager = ComponentAccessor.getComponent(IssueLinkTypeManager.class)
def issueSecuritySchemeManager = ComponentAccessor.getComponent(IssueSecuritySchemeManager.class)
def issueSecurityLevelManager = ComponentAccessor.getComponent(IssueSecurityLevelManager.class)
def attachmentManager = ComponentAccessor.getComponent(AttachmentManager.class)
def customFieldManager = ComponentAccessor.getComponent(CustomFieldManager.class)
ComponentManager componentManager = ComponentManager.getInstance()
// testing
//def Issue thisIssue = issueManager.getIssueObject("PRTNRSDEV-3")    
def Issue issueToClone = issueManager.getIssueObject("RESOURCES-1")    
def issueToCloneKey =  issueToClone.getKey()
def thisIssueKey = issue.getKey()
def thisIssueProject = issue.getProjectObject()
log.debug "DBG: this issue key " + thisIssueKey
log.debug "DBG: issue to clone key " + issueToCloneKey
log.debug "DBG: this issue's project key " + thisIssueProject.getKey()

def newWorkItemNameField = customFieldManager.getCustomFieldObjectByName("New Work Item Name")
def newWorkItemName = issue.getCustomFieldValue(newWorkItemNameField)
log.debug "DBG: starting value of new work item name field: " + newWorkItemName
JiraAuthenticationContext authContext = ComponentAccessor.getJiraAuthenticationContext();
ApplicationUser currentUser = authContext.getLoggedInUser();
def issueFactory = ComponentAccessor.getComponent(IssueFactory.class)
def newissue = issueFactory.getIssue()
newissue.setSummary (newWorkItemName.toString())
newissue.setIssueTypeId("10204") //10204 == Work Item
newissue.setProjectObject (thisIssueProject)
newissue.description = issueToClone.description
newissue.reporter = currentUser 
//copy parent Work Item's basic data into new Work Item
List<String> syncWorkFieldsToNewWork = ["11100"];  // this string array of fields to copy will grow and grow.
for (String fieldId : syncWorkFieldsToNewWork) {
    CustomField customField_name = customFieldManager.getCustomFieldObject("customfield_" + fieldId)
    def sourceFieldValue = issueToClone.getCustomFieldValue(customField_name)
    newissue.setCustomFieldValue(customField_name, sourceFieldValue)
}
log.debug "DBG: create new issue"
params = ["issue":newissue]
newWorkItem = issueManager.createIssueObject(currentUser, params)

def sequence = 0
for (IssueLink link in linkManager.getInwardLinks(issue.id)) {
	if ("Include" == link.issueLinkType.name) {
		sequence++;
	}
}

Collection<IssueLinkType> issueLinkTypes = linkTypeManager.getIssueLinkTypes()
String linkID=null;
for (IssueLinkType issueLinkType : issueLinkTypes) {
	String name=issueLinkType.getName();
	if(name.equals("Include")){
		linkID=issueLinkType.getId();
		break;
	}
}
linkManager.createIssueLink (issue.id, newissue.id, Long.parseLong(linkID), sequence, currentUser)

ImportUtils.indexIssues = wasIndexing

// blank out the New Work Item Name field
CustomField fieldToNullify = customFieldManager.getCustomFieldObjectByName("New Work Item Name")
issue.setCustomFieldValue(fieldToNullify, null)
issue.store()
def blankedOutNewWorkItemName = issue.getCustomFieldValue(fieldToNullify)
log.debug "DBG: ending value of new work item name field: " + blankedOutNewWorkItemName

ImportUtils.indexIssues = wasIndexing
/* clone attachments */
// attachmentManager.copyAttachments(issue, currentAppUser, newissue.getKey())
0 votes
JamieA
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
February 27, 2012

Just use null, not "new UserCFType(null)".

Ops Lead February 27, 2012

I already used null. Then the code does not throw an error but the field content will not deleted. The old content remains.

JamieA
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
February 27, 2012

It should work, try reindexing to see if it;s an indexing problem. It is definitely *not* "new UserCFType(null)".

Ops Lead February 27, 2012

Reindex is done by the standard process of post-functions:

Set issue status to the linked status of the destination workflow step.
— THEN
Script /home/jira/SR/post-clear-need_feedback_from.groovy will be run.
— THEN
Add a comment to an issue if one is entered during a transition.
— THEN
Update change history for an issue and store the issue in the database.
— THEN
Re-index an issue to keep indexes in sync with the database.
— THEN
Fire a Allgemeines Ereignis event that can be processed by the listeners.

I cannot reindex the whole jira database at the moment.

Is there another way to clear the field?

Another quastion: Is there a docu where I will find the right import names for groovy programming? Some tries result in groovy.lang.MissingMethodException errors.

Here we have late evening. It would be great if there is an alternative solution. Thank you for help until now.

JamieA
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
February 27, 2012
Ops Lead February 28, 2012

Hi,

a half day work with the result, that this function works well when written in Ruby!?? Example tested with ScriptRunner:

require 'java'
java_import org.apache.log4j.Category
java_import com.atlassian.jira.issue.ModifiedValue

log = Category.getInstance("script logger")
log.warn "start ruby script"

issue = componentManager.getIssueManager().get_issue_object(97328)
cfm   = componentManager.getCustomFieldManager()
ch    = DefaultIssueChangeHolder.new
nff   = cfm.getCustomFieldObjects(issue).find {|it| it.name == 'Need Feedback From'}
cfv   = issue.get_custom_field_value(nff)
mv    = ModifiedValue.new(cfv, nil)
nff.updateValue(nil, issue, mv, ch)

log.warn "stop  ruby script"

It for test only working with a specific issue id?97328 - but there is a strange message in log:

2012-02-29 18:08:24,167 http-8443-5 ERROR akt 1088x224525x1 oopz0j 192.168.210.28 /secure/admin/groovy/GroovyRunner.jspa [onresolve.jira.groovy.GroovyRunner] The script failed : org.jruby.exceptions.RaiseException: (TypeError) cannot convert instance of class org.jruby.java.proxies.ConcreteJavaProxy to class org.ofbiz.core.entity.GenericValue
2012-02-29 18:08:24,168 http-8443-5 ERROR akt 1088x224525x1 oopz0j 192.168.210.28 /secure/admin/groovy/GroovyRunner.jspa [onresolve.jira.groovy.GroovyRunner] The script failed : org.jruby.exceptions.RaiseException: (TypeError) cannot convert instance of class org.jruby.java.proxies.ConcreteJavaProxy to class org.ofbiz.core.entity.GenericValue
org.jruby.exceptions.RaiseException: (TypeError) cannot convert instance of class org.jruby.java.proxies.ConcreteJavaProxy to class org.ofbiz.core.entity.GenericValue

When I use a slightly adapted version as a post function, similar messages arise (too long for comment, but's nearly the same).

-- but the script does not work, there is no "script logger" message and no function - strange.

Do you have an idea? Do I have to change something to use Ruby for post functions?

Thank you in advance

JamieA
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
February 28, 2012

I don't know, I'm not very familiar with ruby. However what you've put is the moral equivalent of the groovy so it's impossible that that could work and groovy does not. Why don't you post the groovy you think should work, you posted stuff above but saying you knew it was incorrect.

Ops Lead February 29, 2012

Hi Jamie,

well, I'm more familiar with ruby so I preferred this language in script runner. Groovy does work well as a post function so I transferred and shorened the ruby to groovy in script runner - it worked:

import org.apache.log4j.Category
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.issue.ModifiedValue
   
log   = Category.getInstance("script runner")
log.warn "begin"
cfm   = componentManager.getCustomFieldManager()
ch    = new DefaultIssueChangeHolder()
issue = componentManager.getIssueManager().getIssueObject(97328)
nff   = cfm.getCustomFieldObjects(issue).find {it.name == 'Need Feedback From'}
cfv   = issue.getCustomFieldValue(nff)
log.warn "Need Feedback From = '"+cfv+"' cleared"
mv    = new ModifiedValue(nff, null)
nff.updateValue(null, issue, mv, ch)
log.warn "end"

With only one line difference + one more import, this _should_ work as a post function - but it does _NOT_!??? The custom field is _not_ cleared.

import org.apache.log4j.Category
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.issue.ModifiedValue

log = Category.getInstance("post-clear-need_feedback_from.groovy")
log.warn "begin"
cfm    = componentManager.getCustomFieldManager()
ch     = new DefaultIssueChangeHolder();
Issue issue  = issue    // changed //
nff   = cfm.getCustomFieldObjects(issue).find {it.name == 'Need Feedback From'}
cfv   = issue.getCustomFieldValue(nff)
log.warn "Need Feedback From = '"+cfv+"' cleared"
mv    = new ModifiedValue(nff, null)
nff.updateValue(null, issue, mv, ch)
log.warn "end"

Any idea?

PS: The strange error message I reported yesterday is related to any ruby script running, maybe a jira restart will help. Still I would prefer ruby - are there any hints regarding ruby integration into jira?

JamieA
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
February 29, 2012

Not really, sorry. Seems to be a few hits. The code that I put in my answer appears to work for you, can you mark the answer as correct to help other people? ta.

Ops Lead February 29, 2012

You asked me "The code that I put ... can you mark the answer as correct" - sorry, the question was 'using groovy' and this does not work, not as a post function.

Ops Lead March 1, 2012

Hi,

after a jira restart ruby scripting does work as expected.

Neither ruby nor groovy scripts are able to clear the custom field content within a post function using updateValue(). Neither without FieldLayoutItem or with in updateValue.

- Is this a general limitation?

- If not, is it necessary to follow another way to catch the object for updateValue()?

The Java code you linked above does handle system fields only but no custom field. I found a sample code using WorkflowUtils.setFieldValue() for a custom field: https://studio.plugins.atlassian.com/wiki/display/GRV/Miscellaneous+Groovy+Scripts?focusedCommentId=9961492#comment-9961492

- Where/how do I have to install jira-plugin-pack-1.0.0.jar (com.googlecode.jsu.util.WorkflowUtils) to be used for script programming?

Thank you

Suggest an answer

Log in or Sign up to answer
TAGS
AUG Leaders

Atlassian Community Events