Hi,
as we have to move objects in various steps we want to automate this with groovy. I've seen similar requests in the forum but no valid answers.
The move with the following script works but the details / attributes are lost.
The objectTypes have the same parent and the source has one additional attribute that will be discarded.
Anybody with an idea?
import com.riadalabs.jira.plugins.insight.services.model.move.MoveObjectMapping
import com.riadalabs.jira.plugins.insight.services.model.move.MoveAttributeMapping
import com.riadalabs.jira.plugins.insight.services.model.move.MoveObjectBean
import helper.InsightManager
def im = new InsightManager()
def asset = im.getObjectBean("PROD-208936")
def moveMap = new MoveObjectMapping().create()
def fromAtts = im.objectTypeAttributeFacade.findObjectTypeAttributeBeans(asset.objectTypeId)
def toAtts = im.objectTypeAttributeFacade.findObjectTypeAttributeBeans(20)
moveMap.map(59,MoveAttributeMapping.create(fromAtts.find{id=59},toAtts.find{id=59})) // Key
moveMap.map(259,MoveAttributeMapping.create(fromAtts.find{id=259},toAtts.find{id=259})) // Artikelnummer
moveMap.map(60,MoveAttributeMapping.create(fromAtts.find{id=60},toAtts.find{id=60})) // Artikelname
moveMap.map(61,MoveAttributeMapping.create(fromAtts.find{id=61},toAtts.find{id=61})) // Created
moveMap.map(4522,MoveAttributeMapping.create(fromAtts.find{id=4522},toAtts.find{id=4522})) // Hersteller
moveMap.map(62,MoveAttributeMapping.create(fromAtts.find{id=62},toAtts.find{id=62})) // Updated
moveMap.map(4839,MoveAttributeMapping.create(fromAtts.find{id=4839},toAtts.find{id=4839})) // Gewicht
moveMap.map(403,MoveAttributeMapping.create(fromAtts.find{id=403})) // Kategorie
def mObject = new MoveObjectBean()
mObject.setFromObjectTypeId(asset.objectTypeId)
mObject.setObjectSchemaId(3)
mObject.setToObjectTypeId(20)
mObject.setMapping(moveMap)
mObject.setReferences(mObject.references.valueOf("KEEP_REFERENCES_TO_OBJECT"))
mObject.setIql("Key = " + asset.objectKey)
im.objectFacade.moveObjects(mObject)
im.objectFacade.storeObjectBean(asset.createMutable())
Sorry, the stupiest mistake. In the find closure there were assigments (id=59) instead of comparison (it.id==59).
@Christof Hurst , Hi! For God's sake, please tell me what library InsightManager you imported into your script. Is it the same InsightManagerForScriptrunner.groovy the wrapper from Riada?
Where can be found a release of IM that can be run by Insight own groovy capabilities?
Thank's for your help! I'm also struggling to move objects from one objectType to another objectType.
Best regards.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi,
I use an adapted script of the one you mentioned. I made it more fail safe.
If you use the wrapper of Riada, my above mentioned script will work if you use id.equals(<attr_id>)
BR Christof
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Christof,
Thanks for your reply. I appreciate your help with the InsightManager explanation. Would it be possible for you to share the adaptation with me or at least let me know how you adapted it and where you located it so that I can access it from the Groovy console?
Thanks in advance for your assistance.
Best regards,
Carlos Tichy
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Just add the class in the scriptrunner editor. In my case in path /helper/
I renamed the class and the file to "Insightmanager" (InsightManager.groovy)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
/helper ? ... like $JiraHomePath/helper ? (/var/atlassian/application-data/JIRA/helper/InsightManager.groovy)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Go to Scriptrunner Editor, make a folder "helper" on root level, create file InsightManager.groovy in that folder und put the code in it.
Then you can access via "import helper/InsightManager" and you can create an instance via "def im = new InsightManager()"
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Or C:\Program Files\Atlassian\Application Data\JIRA\helper\InsightManager.groovy ?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I don't know. Why not using Scriptrunner Editor? Best and easiest way.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I have added this script to filesystem and then go to JIRA_URL/secure/admin/InsightPluginWhiteList.jspa and add this as allowed script.
Then in automation I've added "action" to run this script.
As I have all Groovy scripts in git, Jenkins deployed etc.
But overall it's the same goal as using Script Editor like mentioned.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hello everyone on the forum, first of all, I want to thank you for the support and collaboration in this community; as a token of appreciation, I want to contribute my grain of sand by sharing with you this script (which was achieved thanks to the contributions from this and other threads). This script moves any object from one object type to another, mapping the attributes according to the structure of the destination object type.
import com.atlassian.jira.component.ComponentAccessor;
import com.riadalabs.jira.plugins.insight.services.model.move.MoveObjectMapping;
import com.riadalabs.jira.plugins.insight.services.model.move.MoveObjectBean;
import com.riadalabs.jira.plugins.insight.services.model.move.MoveAttributeMapping;
import com.riadalabs.jira.plugins.insight.services.progress.model.Progress
Class objectFacadeClass = ComponentAccessor.getPluginAccessor().getClassLoader().findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectFacade");
def objectFacade = ComponentAccessor.getOSGiComponentInstanceOfType(objectFacadeClass);
Class objectTypeFacadeClass = ComponentAccessor.getPluginAccessor().getClassLoader().findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectTypeFacade");
def objectTypeFacade = ComponentAccessor.getOSGiComponentInstanceOfType(objectTypeFacadeClass);
Class objectTypeAttributeFacadeClass = ComponentAccessor.getPluginAccessor().getClassLoader().findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectTypeAttributeFacade");
def objectTypeAttributeFacade = ComponentAccessor.getOSGiComponentInstanceOfType(objectTypeAttributeFacadeClass);
Class moveProgressClass = ComponentAccessor.getPluginAccessor().getClassLoader().findClass("com.riadalabs.jira.plugins.insight.services.progress.model.Progress");
def moveProgress = ComponentAccessor.getOSGiComponentInstanceOfType(moveProgressClass);
/*
* Define some variables
*/
// set schemaId and typeId of source and destination objectTypes (secure/InsightConfigure.jspa?objecttypeid="SOURCE_AND_DEST_OBJECT_TYPES")
int schemaId = 22; // <- Replace here with your own value
int sourceObjectTypeId = 12463; // <- Replace here with your own value
int destObjectTypeId = 12562; // <- Replace here with your own value
// set verificationAttributeId which is the ID of "Status" in source objectType (/secure/ObjectSchema.jspa?id="YOUR_SCHEMA_ID"&typeId="SOURCE_OBJECT_TYPE_ID"&view=list&mode=attribute)
int verificationAttributeId = 250332; // <- Replace here with your own value
// set verificationAttributeValue Id based on Jira Insight ID (/secure/InsightConfigure.jspa?id="YOUR_SCHEMA_ID"&tab=statuses)
int verificationAttributeValue = 234; // <- Replace here with your own value
// actual object ID and KEY from current request
int objectId = object.getId();
String objectKey = object.getObjectKey();
// action to take if the object to move has inboundReferences (options: "REMOVE_REFERENCES_TO_OBJECT" || "KEEP_REFERENCES_TO_OBJECT" || "DO_NOT_MOVE_OBJECT")
String ifInboundReferences = "REMOVE_REFERENCES_TO_OBJECT" // <- Replace here with your own value ("ADVICE: Do the exercise on the GUI beforehand to see the real behavior.")
/*
* Gets the actual values of current object
*/
// get the current objectType to verify
def currentObjectTypeId = object.getObjectTypeId();
if (currentObjectTypeId != sourceObjectTypeId) {
log.info("currentObjectTypeId is ${currentObjectTypeId} and it was expected ${sourceObjectTypeId}. Mistmatch of source objectTypes; no action taken on object ${objectKey}");
return false;
}
// get the current verification value of the "Status" objectAttribute to verify
def currentVerificationAttributeValue = objectFacade.loadObjectAttributeBean(objectId, verificationAttributeId).getObjectAttributeValueBeans()[0].getValue();
if (currentVerificationAttributeValue != verificationAttributeValue) {
log.info("currentVerificationAttributeValue is ${currentVerificationAttributeValue} and it was expected ${verificationAttributeValue}. Mistmatch of value in the Status objectAttribute; no action taken on object ${objectKey}");
return false;
}
/*
* Define move Map - for mapping attributes between two objectTypes (source objectType -> destination objectType)
*/
MoveObjectMapping moveMap = new MoveObjectMapping();
def sourceAttributes = objectTypeAttributeFacade.findObjectTypeAttributeBeans(sourceObjectTypeId);
def destAttributes = objectTypeAttributeFacade.findObjectTypeAttributeBeans(destObjectTypeId);
// Map attributes based on destination map structure to properly adjust source object attributes with their corresponding destination attributes.
sourceAttributes?.each {
sourceAttribute->
def destAttribute = destAttributes.find {
it.name == sourceAttribute.name && it.type == sourceAttribute.type
}
def attributesMap
if (!destAttribute) {
log.warn("Nothing to map to ${sourceAttribute.name}")
attributesMap = MoveAttributeMapping.create(sourceAttribute)
} else {
attributesMap = MoveAttributeMapping.create(sourceAttribute, destAttribute)
}
log.info("Adding mapping of ${sourceAttribute.name} from ${sourceAttribute.id} to ${destAttribute?.id}")
moveMap.map(sourceAttribute.id, attributesMap)
}
/**
* Defines the moveObject and moveObjectProgress to performs the move.
*/
def moveObject = new MoveObjectBean()
def Progress moveObjectProgress
moveObject.objectSchemaId = schemaId
moveObject.fromObjectTypeId = sourceObjectTypeId
moveObject.toObjectTypeId = destObjectTypeId
moveObject.mapping = moveMap
moveObject.references = moveObject.references.valueOf(ifInboundReferences)
// performing the actual move.
try {
moveObject.iql = "Key == ${objectKey}"
if (moveObject != null) {
moveObjectProgress = objectFacade.moveObjects(moveObject)
}
} catch (Exception vie) {
log.warn("Could not move object ${objectKey} due to Exception: ${vie.message}")
}
int curWait = 0
int maxWaitMillis = 60000
log.info("Waiting for move to finish: ${curWait} (${moveObjectProgress.status})}")
while (!moveObjectProgress.isFinished() && curWait < maxWaitMillis) {
Thread.sleep(100)
curWait = curWait + 100
log.warn("Waiting for move to finish: ${curWait} (${moveObjectProgress.status})")
}
if (curWait >= maxWaitMillis){
log.warn("Unknown final status moving object ${objectKey} from objectType ${sourceObjectTypeId} to objectType ${destObjectTypeId}; maxWaitMillis reached while waiting for move to finish.")
return false;
}
if (!moveObjectProgress.isError()) {
log.info("Object ${objectKey} moved from objectType ${sourceObjectTypeId} to objectType ${destObjectTypeId}")
return true;
} else {
log.error("Object ${objectKey} failed to move from objectType ${sourceObjectTypeId} to objectType ${destObjectTypeId}")
return false;
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Christof Hurstdid you find solution for this? In my case move is working, but also attributes are gone after moving an object form one typeId to another (in the same schema).
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Solution is in the accepted answer. If attributes are missing I would presume that they are not in the list to be copied or not with the correct data or data format.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I am using .each function and not mapping them manually with IDs, but I get the same result with your example and mapping them manually.
toAtts?.each { item ->
MoveAttributeMapping temp = MoveAttributeMapping.create(item, fromAtts[index]);
moveMap.map(fromAtts[index].id, temp);
index++;
}
After I've done the mapping my MoveAttributeMap object shows like this:
moveObject: MoveObjectBean{fromObjectTypeId=69,
toObjectTypeId=100,
mapping=MoveObjectMapping{attributeMappingMap={789=com.riadalabs.jira.plugins.insight.services.model.move.MoveAttributeMapping@2a38a0a1,
791=com.riadalabs.jira.plugins.insight.services.model.move.MoveAttributeMapping@39fd8d10,
792=com.riadalabs.jira.plugins.insight.services.model.move.MoveAttributeMapping@221dac8a,
841=com.riadalabs.jira.plugins.insight.services.model.move.MoveAttributeMapping@1061a041,
842=com.riadalabs.jira.plugins.insight.services.model.move.MoveAttributeMapping@7f333744,
843=com.riadalabs.jira.plugins.insight.services.model.move.MoveAttributeMapping@2a73a0bf,
844=com.riadalabs.jira.plugins.insight.services.model.move.MoveAttributeMapping@65c53087,
845=com.riadalabs.jira.plugins.insight.services.model.move.MoveAttributeMapping@78bbf7d6,
846=com.riadalabs.jira.plugins.insight.services.model.move.MoveAttributeMapping@1ed46692,
847=com.riadalabs.jira.plugins.insight.services.model.move.MoveAttributeMapping@29955baf}},
iql=Key = KAS-132313,
objectSchemaId=3,
references=KEEP_REFERENCES_TO_OBJECT}
Which looks like the mapping is done correctly, no?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Sorry I don't know. I know that my method is working. I would never trust this automatic way. I always define the set of attributes explicitely by myself.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I have implemented a similar move (between two child object types with the same parent) and didn't need to use the "storeObjectBean" method.
So I wonder if that's what tripping your script.
The moveObjects method kicks off an asynchronous process so in your case, perhaps the storeObjectBean method is attempting to save the old version of the object while the move is still being processed.
I had a similar problem when I was trying to populate a new attribute (date/time of the move on the target object after the move) before the move was complete.
I solved it by waiting for the move to complete before resuming any other part of my script.
Something like this:
def moveProgress = objectFacade.moveObjects(mObject)
Integer curWait = 0
Integer maxWaitMillis = 10000
log.debug "Waiting for move to finish: $curWait ($moveProgress.status)"
while (moveProgress.isFinished() == false && curWait < maxWaitMillis) {
Thread.sleep(100)
curWait = curWait + 100
log.debug "Waiting for move to finish: $curWait ($moveProgress.status)"
}
if (moveProgress.isFinished()) {
log.info "Move complete"
} else if (moveProgress.isError()) {
log.error "error during move"
return
} else {
log.warn "maxWaitMillis reach while waiting for move to finish."
return
}
//resume post move actions here, probably safects to re-laod your object bean after the move rather than keep the old asset object
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thanks for this answer but it didn't solve the problem.
The move now takes some millis to finish but the result is the same. All details are gone. Even the label. Line with storeObject was deleted. A clean reindex also didn't helped.
Actually the script is complete as shown above. There are no further actions. As the script is pretty simple and straight forward I have no glue.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Christof Hurstdid you find solution for this?
My attributes are gone too after a successful object movement from one typeId to another.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Then I think finding the correct value in the old object is not working. For me it was = instead of ==
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.