Feb 26 2015

JIRA is a pain when you need to create lots of projects with custom Schemes. On the XWiki open source project we allow the community to contribute extensions and we offer a place to host the sources in the xwiki-contrib GitHub organization. We also offer for each project a JIRA project where users can report issues and where developers can track what they're working on. 

Thus we have the need to create lots of JIRA projects. Today, I got bored of repeating over and over the same setup for creating such projects. It involves 9 steps:

  1. Setting the category
  2. Setting the custom XWiki Workflow Scheme
  3. Setting the custom XWiki Screen Scheme
  4. Setting the custom XWiki Field Configuration Scheme
  5. Setting the custom XWiki Notifications Scheme
  6. Setting the custom XWiki Permission Scheme
  7. Setting the Project Lead
  8. Setting the project URL
  9. Setting some groups in one of the project's Roles

Following this tutorial (and a lots of googling emoticon_wink) I was able to automate steps 1-6 in the above list (Source code).

Now when we create a new JIRA project we get this nice template:


The main code doing the work is in XWikiAddProjectHook.java:

 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.

package org.xwiki.devtools.jira.template;

import java.util.Arrays;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

import com.atlassian.jira.bc.projectroles.ProjectRoleService;
import com.atlassian.jira.blueprint.api.AddProjectHook;
import com.atlassian.jira.blueprint.api.ConfigureData;
import com.atlassian.jira.blueprint.api.ConfigureResponse;
import com.atlassian.jira.blueprint.api.ValidateData;
import com.atlassian.jira.blueprint.api.ValidateResponse;
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.fields.layout.field.FieldLayoutManager;
import com.atlassian.jira.issue.fields.layout.field.FieldLayoutScheme;
import com.atlassian.jira.issue.fields.screen.issuetype.IssueTypeScreenScheme;
import com.atlassian.jira.issue.fields.screen.issuetype.IssueTypeScreenSchemeManager;
import com.atlassian.jira.notification.NotificationSchemeManager;
import com.atlassian.jira.permission.PermissionSchemeManager;
import com.atlassian.jira.project.Project;
import com.atlassian.jira.project.ProjectCategory;
import com.atlassian.jira.project.ProjectManager;
import com.atlassian.jira.scheme.Scheme;
import com.atlassian.jira.security.roles.ProjectRole;
import com.atlassian.jira.util.SimpleErrorCollection;
import com.atlassian.jira.workflow.WorkflowSchemeManager;

public class XWikiAddProjectHook implements AddProjectHook
   private static final Logger LOGGER = LogManager.getLogger(XWikiAddProjectHook.class);

   public ValidateResponse validate(final ValidateData validateData)
       return ValidateResponse.create();

   public ConfigureResponse configure(final ConfigureData configureData)
        Project project = configureData.project();

       // Set Workflow Scheme
       WorkflowSchemeManager workflowSchemeManager = ComponentAccessor.getWorkflowSchemeManager();
        Scheme xwikiScheme = workflowSchemeManager.getSchemeObject("XWiki Workflow Scheme");
       if (xwikiScheme != null) {
            workflowSchemeManager.addSchemeToProject(project, xwikiScheme);
       } else {
            LOGGER.warn(String.format("[XWiki] Failed to find the \"XWiki Workflow Scheme\" scheme. "
               + "It is not set for the new project [%s]", project.getName()));

       // Set Notification Scheme
       NotificationSchemeManager notificationSchemeManager = ComponentAccessor.getNotificationSchemeManager();
        Scheme notificationScheme = notificationSchemeManager.getSchemeObject("XWiki Notification Scheme");
       if (notificationScheme != null) {
            notificationSchemeManager.addSchemeToProject(project, notificationScheme);
       } else {
            LOGGER.warn(String.format("[XWiki] Failed to find the \"XWiki Notification Scheme\" scheme. "
               + "It is not set for the new project [%s]", project.getName()));

       // Set Permission Scheme
       PermissionSchemeManager permissionSchemeManager = ComponentAccessor.getPermissionSchemeManager();
        Scheme permissionScheme = permissionSchemeManager.getSchemeObject("XWiki Open");
       if (permissionScheme != null) {
           // Remove all defined permissions screen since there can be only ony apparently
            permissionSchemeManager.addSchemeToProject(project, permissionScheme);
       } else {
            LOGGER.warn(String.format("[XWiki] Failed to find the \"XWiki Open\" scheme. "
               + "It is not set for the new project [%s]", project.getName()));

       // Set Project Category
       ProjectManager projectManager = ComponentAccessor.getProjectManager();
        ProjectCategory contribCategory = projectManager.getProjectCategoryObjectByName("XWiki Contributed Projects");
       if (contribCategory != null) {
            projectManager.setProjectCategory(project, contribCategory);
       } else {
            LOGGER.warn(String.format("[XWiki] Failed to find the \"XWiki Contributed Projects\" category. "
               + "It is not set for the new project [%s]", project.getName()));

       // Set Field Configuration Scheme
       FieldLayoutManager fieldLayoutManager = ComponentAccessor.getFieldLayoutManager();
       // Note: I couldn't find a way to get the Field Configuration Scheme by String so I'm iterating over all of them
       FieldLayoutScheme fieldLayoutScheme = null;
       for (FieldLayoutScheme scheme : fieldLayoutManager.getFieldLayoutSchemes()) {
           if (scheme.getName().equals("XWiki Open Field Configuration Scheme")) {
                fieldLayoutScheme = scheme;
       if (fieldLayoutScheme != null) {
            fieldLayoutManager.addSchemeAssociation(project, fieldLayoutScheme.getId());

       // Set Screen Scheme
       IssueTypeScreenSchemeManager issueTypeScreenSchemeManager = ComponentAccessor.getIssueTypeScreenSchemeManager();
       // Note: I couldn't find a way to get the Screen Scheme by String so I'm iterating over all of them
       IssueTypeScreenScheme screenScheme = null;
       for (IssueTypeScreenScheme scheme : issueTypeScreenSchemeManager.getIssueTypeScreenSchemes()) {
           if (scheme.getName().equals("Basic Issue Creation Scheme")) {
                screenScheme = scheme;
       if (screenScheme != null) {
            issueTypeScreenSchemeManager.addSchemeAssociation(project, screenScheme);
       } else {
            LOGGER.warn(String.format("[XWiki] Failed to find the \"Basic Issue Creation Scheme\" scheme. "
               + "It is not set for the new project [%s]", project.getName()));

       // Set project committers role to xwiki-committers and contrib-committers
       ProjectRoleService roleService = ComponentAccessor.getComponentOfType(ProjectRoleService.class);
        SimpleErrorCollection errorCollection = new SimpleErrorCollection();
        ProjectRole commmitterRole = roleService.getProjectRoleByName("Committers", errorCollection);
       // Make sure to remove any of the groups we wish to add to the Committers role as otherwise the addition fails
       roleService.removeActorsFromProjectRole(Arrays.asList("xwiki-committers", "contrib-committers"), commmitterRole,
            project, "atlassian-group-role-actor", errorCollection);
        roleService.addActorsToProjectRole(Arrays.asList("xwiki-committers", "contrib-committers"), commmitterRole,
            project, "atlassian-group-role-actor", errorCollection);

       return ConfigureResponse.create().setRedirect("/plugins/servlet/project-config/" + project.getKey()
           + "/summary");


Created by Vincent Massol on 2015/02/26 23:55
Created by Vincent Massol on 2015/02/26 23:55
This wiki is licensed under a Creative Commons 2.0 license