I have an Insight object type called Asset.
I have an Insight object type called Bin, which has an attribute of Type object and Type Value Asset that is named "Assets added to bin."
I'm writing a new workflow in which the user selects a specific Bin from a Jira customfield and N number of Assets from another Jira customfield (both tie back to Insight). When the issue is submitted, my goal is for the Assets selected to be added into the selected Bin's "Assets added to bin" attribute.
It took me several days of banging my head against the wall, but I've come up with the following groovy post-function script to do what I've described above.
I'm posting here for two reasons: First, I wish I had this kind of sample code when I was putting my own script together (some of the sample code on Riada's page was nonfunctional and none of it really explained what was going on). So I hope someone out there is starting out with Insight post functions and finds this useful.
Second, I'd really appreciate a little code review. What I'm doing (I've summarized the main steps in the beginning) seems a little circuitous. Is there a way to just retrieve the Bin's "Assets added to bin"'s AttributeValueBeans list (steps 1-6 except use objAttrib instead of newObjectAttributeBean), skip step 7, add the assets discovered in the issue to the list (steps 8-10), and re-save the (newly updated) objAttrib? I tried a couple of variants but got exception errors that didn't provide much useful information for debugging.
Anyway, here's the code. Thanks!
int insightSchemaID = 5;
int jiraCustomFieldIDForAffectedObject = 11002;
int jiraCustomFieldIDForDisposalBin = 11407;
int insightAssetsAddedToBinID = 42702;
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.MutableIssue;
import com.atlassian.jira.event.type.EventDispatchOption;
import com.atlassian.jira.issue.context.IssueContextImpl;
import com.atlassian.jira.issue.fields.config.FieldConfig;
import java.util.ArrayList;
import java.util.stream.Collectors;
/*
Step 1: retrieve the Disposal Bin reference from the issue
Step 2: find the referenced Disposal Bin in Insight
Step 3: find the Insight attribute
Step 4: prep
Step 5: find the attribute for the bin we're about to update
Step 6: retrieve list of current assets in the Insight attribute
Step 7: populate list of values to be added with what's already in Insight
Step 8: retrieve the Affected Object references from the issue
Step 9: find the Assets in Insight that are referenced in Jira and add them to the list
Step 10: dedupe the list
Step 11: add list to the new ObjectAttribute
Step 12: assign the new ObjectAttribute the original ObjectAttribute's ID
Step 13: save changes
*/
/* Get Insight Object Facade from plugin accessor */
Class objectFacadeClass = ComponentAccessor.getPluginAccessor().getClassLoader().findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectFacade");
def objectFacade = ComponentAccessor.getOSGiComponentInstanceOfType(objectFacadeClass);
/* Get Insight Object Type Facade from plugin accessor */
Class objectTypeFacadeClass = ComponentAccessor.getPluginAccessor().getClassLoader().findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectTypeFacade");
def objectTypeFacade = ComponentAccessor.getOSGiComponentInstanceOfType(objectTypeFacadeClass);
/* Get Insight Object Attribute Facade from plugin accessor */
Class objectTypeAttributeFacadeClass = ComponentAccessor.getPluginAccessor().getClassLoader().findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectTypeAttributeFacade");
def objectTypeAttributeFacade = ComponentAccessor.getOSGiComponentInstanceOfType(objectTypeAttributeFacadeClass);
/* ------------------------------------------------------------- */
/* Step 1: retrieve the Disposal Bin reference from the issue */
/* ------------------------------------------------------------- */
CustomField disposalBinField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(jiraCustomFieldIDForDisposalBin);
if (disposalBinField == null) {
log.warn("Bin field not found in issue. Custom field identifier was " + jiraCustomFieldIDForDisposalBin + ". Exiting.");
return false;
}
else {
log.info("Bin field: " + disposalBinField);
}
def disposalBinID = disposalBinField.getValue(issue);
//Although this field is defined in Jira as Insight Object (single select), it returns an array so we need to pull the first item from the value returned
if (disposalBinID.isEmpty()) {
log.warn("Bin value not found. Exiting");
return false;
}
else {
log.info("Bin ID from Jira issue: " + disposalBinID[0]);
}
/* ------------------------------------------------------------- */
/* Step 2: find the referenced Disposal Bin in Insight */
/* ------------------------------------------------------------- */
/* Find disposal bin object in Insight */
def objBin = objectFacade.loadObjectBean(disposalBinID[0].id);
if (objBin == null) {
log.warn("Could not find Disposal Bin in Insight. Exiting.");
return false;
}
else {
log.info("Disposal Bin in Insight: " + objBin);
}
/* ------------------------------------------------------------- */
/* Step 3: find the Insight attribute */
/* ------------------------------------------------------------- */
def objectTypeAttributeBean = objectTypeAttributeFacade.loadObjectTypeAttributeBean(insightAssetsAddedToBinID); //the ID of the object type attribute "Assets added to bin"
if (objectTypeAttributeBean == null) {
log.warn("Could not find 'Assets added to bin' field in Insight. Exiting.");
return false;
}
else
{
log.info("Insight attribute: " + objectTypeAttributeBean);
}
/* ------------------------------------------------------------------- */
/* Step 4: prep */
/* ------------------------------------------------------------------- */
//create an empty attribute that will store all the values and will ultimately replace the attribute associated with the current bin
def newObjectAttributeBean = objBin.createObjectAttributeBean(objectTypeAttributeBean);
//create a list to populate with values old and new
def values = newObjectAttributeBean.getObjectAttributeValueBeans();
/* ------------------------------------------------------------------- */
/* Step 5: find the attribute for the bin we're about to update */
/* ------------------------------------------------------------------- */
def objAttrib = objectFacade.loadObjectAttributeBean(objBin.getId(), insightAssetsAddedToBinID);
if (objAttrib == null) {
log.warn("ObjAttrib is null; will create a new one.");
objAttrib = objBin.createObjectAttributeBean(objectTypeAttributeBean);
}
else {
log.info("Insight attribute definition: " + objAttrib);
}
/* ------------------------------------------------------------------- */
/* Step 6: retrieve list of current assets in the Insight attribute */
/* ------------------------------------------------------------------- */
def existingAssetsInBin = objAttrib.getObjectAttributeValueBeans();
if (existingAssetsInBin == null)
{
log.warn ("Unable to retrieve any assets from this bin.");
}
else {
log.info("existingAssetsInBin list: " + existingAssetsInBin);
}
/* ------------------------------------------------------------------- */
/* Step 7: populate list of values to be added with what's already in Insight */
/* ------------------------------------------------------------------- */
for (def existingAsset:existingAssetsInBin) {
log.info("Existing asset found: " + existingAsset.getValue());
def objAsset = objectFacade.loadObjectBean(existingAsset.getValue());
log.info("objAsset: " + objAsset);
def assetId = objAsset.getId();
log.info("Asset ID: " + assetId);
def newObjectAttributeValueBean = newObjectAttributeBean.createObjectAttributeValueBean();
newObjectAttributeValueBean.setReferencedObjectBeanId(assetId); //add an asset to the attribute
values.add(newObjectAttributeValueBean);
log.info("Array of values size is now: " + values.size());
}
//we'll use another for loop later to add more values to the current list
log.info("values list: " + values);
for (def value:values) {
log.info("Value: " + value);
}
/* --------------------------------------------------------------- */
/* Step 8: retrieve the Affected Object references from the issue */
/* --------------------------------------------------------------- */
CustomField affectedObjectField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(jiraCustomFieldIDForAffectedObject);
if (affectedObjectField == null) {
log.warn("Affected Object field not found in issue. Custom field identifier was " + jiraCustomFieldIDForAffectedObject + ". Exiting");
return false;
}
else {
log.info("Affected Object field: " + affectedObjectField);
}
//identify the values of the individual objects found
def affectedObjects = affectedObjectField.getValue(issue);
if (affectedObjects == null) {
log.warn("User failed to enter any objects in the Disposal Bin field. Exiting");
return true;
}
else {
log.info("Affected objects value from Jira issue: " + affectedObjects);
}
/* ----------------------------------------------------------------------------------------- */
/* Step 9: find the Assets in Insight that are referenced in Jira and add them to the list */
/* ----------------------------------------------------------------------------------------- */
for (def affectedObject:affectedObjects) {
log.info("loop");
if (affectedObject != null) {
log.info("Asset object: " + affectedObject);
def assetId = affectedObject.getId();
log.info("Asset object ID: " + affectedObject.getId());
def newObjectAttributeValueBean = newObjectAttributeBean.createObjectAttributeValueBean();
newObjectAttributeValueBean.setReferencedObjectBeanId(assetId); //add an asset to the attribute
values.add(newObjectAttributeValueBean); // Add the value to the object attribute
}
else {
log.warn("Asset object is null!");
}
}
for (def value:values) {
log.info("Value: " + value);
log.info("Class: " + value.getClass());
//class for each value should be MutableObjectAttributeValueBean
}
log.info("Values to be added to newObjectAttributeBean, before dedupe: " + values);
/* -------------------------------------------------------- */
/* Step 10: dedupe the list */
/* -------------------------------------------------------- */
def dedupedValues = values.stream().distinct().collect(Collectors.toList());
log.info("Values to be added to newObjectAttributeBean, after dedupe: " + dedupedValues);
for (def value:dedupedValues) {
log.info("Deduped value: " + value);
log.info("class: " + value.getClass());
}
/* ------------------------------------------------------------------------ */
/* Step 11: add list to the new ObjectAttribute */
/* ------------------------------------------------------------------------ */
newObjectAttributeBean.setObjectAttributeValueBeans(dedupedValues);
log.info("newObjectAttributeBean: " + newObjectAttributeBean);
log.info("newObjectAttributeBean ID: " + newObjectAttributeBean.getId());
log.info("Final list of values that are being added to newObjectAttributeBean: " + newObjectAttributeBean.getObjectAttributeValueBeans());
/* --------------------------------------------------------------------------- */
/* Step 12: assign the new ObjectAttribute the original ObjectAttribute's ID */
/* --------------------------------------------------------------------------- */
def objAttribute = objectFacade.loadObjectAttributeBean(objBin.getId(), insightAssetsAddedToBinID);
if ( objAttribute != null) {
/* If attribute exists reuse the old id for the new attribute */
newObjectAttributeBean.setId( objAttribute.getId());
log.info("List of values before: " + objAttribute.getObjectAttributeValueBeans());
log.info(" objAttribute:" + objAttribute);
log.info(" objAttribute ID: " + objAttribute.getId());
}
/* ------------------------------------------------------------------------ */
/* Step 13: save changes */
/* ------------------------------------------------------------------------ */
try {
objAttribute = objectFacade.storeObjectAttributeBean(newObjectAttributeBean);
log.info("Successfully stored attribute");
}
catch (Exception vie) {
log.warn("Exception storing objAttribute: " + vie.getMessage());
return false;
}
//to do: add a comment to the Issue describing what was done.
return true;