Come for the products,
stay for the community

The Atlassian Community can help you and your team get more value out of Atlassian products and practices.

Atlassian Community about banner
4,254,263
Community Members
 
Community Events
164
Community Groups

ScriptRunner Component sync

I want to be able to Sync Components from my Main "DevOps" project to all other projects in JIRA,

Because we want a unified place for components.

I started with this:



import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.project.Project
import com.atlassian.jira.project.version.Version

def projectManager = ComponentAccessor.getProjectManager()
def projectSource = projectManager.getProjectObjByKey("DEVOPS") // change project name here
def projectDestinationList = projectManager.getProjectObjects()
//def projectDestination = projectManager.getProjectObjByKey("DESTINATION_PROJECT_KEY")

def ProjectComponentManager = ComponentAccessor.getProjectComponentManager()
Collection<ProjectComponent> componentList = ProjectComponentManager.findAll(projectSource.getid())
def componentTemp
if (componentList != null)
{
    for (project in projectDestinationList) {
    if (project.getKey() != "DEVOPS") {
    for (component in componentList) {
        componentTemp = ProjectComponentManager.findComponent(project.getid(), component)
        if  (componentTemp == null) {
            log.debug("Now adding component " + component + " to " + project.getName())
            def component = ProjectComponentManager.create(component, "description", "admin", 1,  "admin user ID")
            //ProjectComponentManager.createComponent()
        }
    }
    }
    }
}

Now I need assistance on completing this because I dont know how to get it to work

 

4 answers

OK,

 

I finally have the solution:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.project.Project
import com.atlassian.jira.project.version.Version
import com.atlassian.jira.bc.project.component.ProjectComponent

def projectManager = ComponentAccessor.getProjectManager()
def projectSource = projectManager.getProjectObjByKeyIgnoreCase("DEVOPS").getId() // change project name here
def projectDestinationList = projectManager.getProjectObjects()
def projectComponentManager = ComponentAccessor.getProjectComponentManager()

Collection<ProjectComponent> componentList = projectComponentManager.findAllForProject(projectSource) as Collection<ProjectComponent>

if (componentList != null) {
   for (project in projectDestinationList) {
      if (project.getKey() != "SOFTENG") {
         for (component in componentList) {
            def componentTemp = projectComponentManager.findByComponentName(project.getId(), component.getName())
            if  (componentTemp == null) {
                log.debug("Now adding component " + component.getName() + " to " + project.getName())
                def componentTempResult = projectComponentManager.create(component.getName(), component.getDescription(), component.getLead(), 1,project.getId())
                // 1= COMPONENT_LEAD, 2= PROJECT_DEFAULT, 3 =PROJECT_LEAD , 4= UNASSIGNED
            }
         }        
      }
   }
}


So, with a little help from my friend and some additional research,

1. I added "as Collecion" after defining my componentlistcollection

2. I used component.getName() instead of component

3. I added a remark of the ENUM values of the AssigneeType for a component.

Thank you Atlassian Community and Adaptavist documentation.

Great script ! You used it as a script listener on all Component events, right ?

Anyhow, you should probably suggest adaptavist to add it to their library.adaptavist.com ;-)

Like ofirgu@bezeqint.co.il likes this

ofirgu@bezeqint.co.il just to tidy it up, you can remove this line:

import com.atlassian.jira.project.version.Version
Like ofirgu@bezeqint.co.il likes this

 

I'd like to adapt this to sync Components from a source project to a list of specific projects only instead of to ALL projects.

Would it just be a matter of changing this line

def projectDestinationList = projectManager.getProjectObjects() 

to this??  (please help me with the syntax)

def projectManager.getProjectObjByKeyIgnoreCase("PROJECT1", "PROJECT2", "PROJECT3").getId()

and then comment out this line and remove its closing "}"??

 if (project.getKey() != "SOFTENG") { 

 

Leaving us with something like this?

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.project.Project
import com.atlassian.jira.bc.project.component.ProjectComponent

def projectManager = ComponentAccessor.getProjectManager()
def projectSource = projectManager.getProjectObjByKeyIgnoreCase("SOURCEPROJECTKEYHERE").getId() // change project key here
def projectDestinationList = projectManager.getProjectObjByKeyIgnoreCase("KEY1", "KEY2", "KEY3").getId()
def projectComponentManager = ComponentAccessor.getProjectComponentManager()

Collection<ProjectComponent> componentList = projectComponentManager.findAllForProject(projectSource) as Collection<ProjectComponent>

if (componentList != null) {
   for (project in projectDestinationList) {
   //   if (project.getKey() != "EXCLUDEDPROJECTKEYHERE") {
         for (component in componentList) {
            def componentTemp = projectComponentManager.findByComponentName(project.getId(), component.getName())
            if  (componentTemp == null) {
                log.debug("Now adding component " + component.getName() + " to " + project.getName())
                def componentTempResult = projectComponentManager.create(component.getName(), component.getDescription(), component.getLead(), 1,project.getId())
                // 1= COMPONENT_LEAD, 2= PROJECT_DEFAULT, 3 =PROJECT_LEAD , 4= UNASSIGNED
            
         }        
      }
   }
}

 

Or perhaps leave everything as is and just change this line:

if (project.getKey() != "EXCLUDEDPROJECTKEYHERE") {

to this instead? (again, please forgive/correct my syntax)

if (project.getKey() == "KEY1" || "KEY2" || "KEY3") {

I'm really out of my depth here... any help/ideas would be greatly appreciated.  I think that a 1:some use case would be more common for most people so I'm sure others would also benefit.

Hi @Andy Ukasick,

 

I would use this:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.project.Project
import com.atlassian.jira.bc.project.component.ProjectComponent

def projectManager = ComponentAccessor.getProjectManager()
def projectSource = projectManager.getProjectObjByKeyIgnoreCase("SOURCEPROJECTKEYHERE").getId() // change project key here
def projectDestinationList = projectManager.getProjectObjByKeyIgnoreCase("KEY1", "KEY2", "KEY3").getId()
def projectComponentManager = ComponentAccessor.getProjectComponentManager()

Collection<ProjectComponent> componentList = projectComponentManager.findAllForProject(projectSource) as Collection<ProjectComponent>

if (componentList != null) {
   for (project in projectDestinationList) {
         for (component in componentList) {
            def componentTemp = projectComponentManager.findByComponentName(project.getId(), component.getName())
            if  (componentTemp == null) {
                log.debug("Now adding component " + component.getName() + " to " + project.getName())
// HERE I would add a function to verify that a user called getLead() actually exists in the setination project. we added all Enterprise users as viewers to all projects.
                def componentTempResult = projectComponentManager.create(component.getName(), component.getDescription(), component.getLead(), 1,project.getId())
                // 1= COMPONENT_LEAD, 2= PROJECT_DEFAULT, 3 =PROJECT_LEAD , 4= UNASSIGNED
            
         }        
   }
}
Like Andy Ukasick likes this

Our proposal Script:

 

def dest_prj = ["PRJ1","PRJ2"]

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.project.Project
import com.atlassian.jira.bc.project.component.ProjectComponent

def projectManager = ComponentAccessor.getProjectManager()
def projectSource = projectManager.getProjectObjByKey("COMPMASTER").getId()
def projectComponentManager = ComponentAccessor.getProjectComponentManager()
Collection<ProjectComponent> componentList = projectComponentManager.findAllForProject(projectSource) as Collection<ProjectComponent>

def i = 0
while ( i < dest_prj.size() ) {
def projectDestinationList = projectManager.getProjectObjByKey(dest_prj[i])
def project = projectDestinationList

if (componentList != null) {
for (component in componentList) {
//log.debug("Component " + component.getName() )
def componentTemp = projectComponentManager.findByComponentName(project.getId(), component.getName())
if (componentTemp == null) {
//log.debug("Now adding component " + component.getName() + " to " + project.getName())
def componentTempResult = projectComponentManager.create(component.getName(), component.getDescription(), component.getLead(), 1,project.getId())
// 1= COMPONENT_LEAD, 2= PROJECT_DEFAULT, 3 =PROJECT_LEAD , 4= UNASSIGNED
}
}
}
i++
}

here is the log error:
2019-01-16 18:38:31,873 ERROR [runner.AbstractScriptListener]: *************************************************************************************
2019-01-16 18:38:31,873 ERROR [runner.AbstractScriptListener]: Script function failed on event: com.atlassian.jira.event.bc.project.component.ProjectComponentCreatedEvent, file: <inline script>
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
Script173.groovy: 14: unable to resolve class ProjectComponent
@ line 14, column 12.
Collection<ProjectComponent> componentList = ProjectComponentManager.findAll(projectList.getid())
^
1 error

Hi ofirgu@bezeqint.co.il, can you elaborate on what your problem is? Do you get an error when running the script?

Also, please keep in mind that synchronising components involves a bit more magic, as Jira will throw an error if the component already exists. Do you want your script to update existing components upon changes? Have you also thought about when this script should run? Contrary to version changes Jira does not offer events for component changes so you will need some sort of schedule task.

If you need help with any of these questions, feel free to DM me! I have some experience with this problem as I've created a specific app for it (Version & Component Sync) :D

Cheers,

Remie

1. My Script fails

2. I did check for the component existence in the target project, and leave it as is if it already exists.

3. your plugin is nice, But I have to manage links or create links in order for it to work, while on my script, I go to the script runner panel, trigger it, and it does a sync on all projects. no link creation required.

 

I am really close on getting it to work

I think the problem lies with the following line:

componentTemp = ProjectComponentManager.findComponent(project.getid(), component)

If you look at the ProjectComponentManager documentation, it does not include a findComponent() method which allows you to specify the projectId and ProjectComponent object.

In this case it is probably best to use findByComponentName:

componentTemp = ProjectComponentManager.findByComponentName(project.getid(), component.getName())

Hi @Raul Pelaez  and @Remie Bolte 

I have a error when i create the component 

 

Error : 

 

2022-02-09 16:25:44,064 ERROR [runner.AbstractScriptListener]: *************************************************************************************
2022-02-09 16:25:44,064 ERROR [runner.AbstractScriptListener]: Script function failed on event: com.atlassian.jira.event.bc.project.component.ProjectComponentCreatedEvent, file: null
java.lang.NullPointerException: Cannot invoke method getId() on null object
at Script29.run(Script29.groovy:24)

 

You can help me ?

Hello @Salim Hammar ,

Probably the error is the initial parameters because the destination project is an array of keys of projects.

The source project initial param is a String with the key of the project (is different than the other)

Best regards!

Hi @Raul Pelaez 

look the script : 

script_sync.png

 

and tell where is the error please ?

Like Raul Pelaez likes this

change the first line by this:

def dest_prj = ["TS"]

That's all!

Yes good

Thank you very match 

Like Raul Pelaez likes this

Hi @Raul Pelaez 

But i see than i create a issue in the project "dest_prj" the "source_prj" in the column issues is not updated ,because i'm create a issue in the project "dest_prj" for the components who are in the project "source_prj" it's possible the synchronise the numer issue created in the differents project bound in the script 

It's possible ?

Hello Salim, I cannot understand the question sorry, but seems another topic different of the main of this ticket. Please raise another Community question and I will try to answer it if you mention me :)

Best regards

Hi @Raul Pelaez 

Actually the scirpt he syncronise the components ok

And i would like when i create issue in the project "dest_prj" in the project with component "compo1" and in  "source_prj" in the components "compo1" the number issues does not update.

 

compo.png

it's possible to syncronise the number the issue created in the project "dest_prj" and he updated in the project "source_prj" ?

Hi @Raul Pelaez 

And i note when i modify a name for component , he create a component and a component are modify he stays 

you have solution for this issue ?

Hello @Salim Hammar 

The script you see is only a little part of a sync of Components, as you see it needs more code if you do modifications in names of components or if you delete a component, etc...

Regards

Hi @Raul Pelaez 

Okay im understand and you know the code added in this script because im find but i don't find a fuction or script for add in the script ?? you have idea ??

Regards

Thanks in advance

Hi @Raul Pelaez 

 

I try do modfify the script for add a function for update the name components

Look this script , have you idea for error ??

 

SCRIPT8COMPO.png

Thanks in advance 

Hello Salim,
Here you can see an example to obtain the type of event:
https://community.atlassian.com/t5/Marketplace-Apps-Integrations/Jira-Custom-Listener-with-event-ProjectComponent/qaq-p/1047574

Because you must listen events of different types: ProjectComponentUpdatedEvent and ProjectComponentCreatedEvent in your case
Hope this info helps
Best regards :)

Hi @Raul Pelaez , thank you for your answer

I try but , my script he don't work 

Capture d’écran 2022-02-11 224716.png

 

You can help me ?

 

Thanks in advance

Hi @Raul Pelaez  

I have a problem , because 

for the variable  "def dest_prj = ["TS","TK"] " i would like insert many project key but for this way is not working ?

You have idea ??

Thanks in advance

Suggest an answer

Log in or Sign up to answer
TAGS

Community Events

Connect with like-minded Atlassian users at free events near you!

Find an event

Connect with like-minded Atlassian users at free events near you!

Unfortunately there are no Community Events near you at the moment.

Host an event

You're one step closer to meeting fellow Atlassian users at your local event. Learn more about Community Events

Events near you