Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in

How to use Jira Software functionality in a Jira plugin

I often can see questions about developing a Jira plugin with Jira Software functionality. Like other people I can not find much information about it in the Internet. That is why I decided to make a short tutorial, where I would get all issues in an Epic and add issues to an Epic using Jira Software services.

1. Create a Jira plugin.

Open teminal and run the following command:

atlas-create-jira-plugin

 Terminal will ask you a couple of questions.  Answer the following way:

Define value for groupId: : ru.matveev.alexey.sw.tutorial
Define value for artifactId: : sw-tutorial
Define value for version:  1.0.0-SNAPSHOT: :
Define value for package:  ru.matveev.alexey.sw.tutorial: :
Confirm properties configuration:
groupId: ru.matveev.alexey.sw.tutorial
artifactId: sw-tutorial
version: 1.0.0-SNAPSHOT
package: ru.matveev.alexey.sw.tutorial
 Y: : Y

2. Change the pom.xml file.

Change jira.version property to 7.9.0

<jira.version>7.9.0</jira.version>

Add lines below to the maven-jira-plugin in the configuration tag:

<applications>
<application>
<applicationKey>jira-software</applicationKey>
<version>${jira.software.application.version}</version>
</application>
</applications>

Add jira.software.application.version property to the property tag:

<jira.software.application.version>7.9.0</jira.software.application.version>

These lines will let us launch Jira Software with the atlas-run command.

Increase JVM memory adding to the maven-jira-plugin in the configuration tag:

<jvmArgs>-Xms512M -Xmx1g</jvmArgs>

In my runtime environment Jira did not start without adding more memory to Jira.

3. Add Rest Module

Open terminal and run

atlas-create-jira-plugin-module

Answer the following way to the questions:

Choose a number (1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/34): 14

Enter New Classname MyRestResource: :
Enter Package Name ru.matveev.alexey.sw.tutorial.rest: :
Enter REST Path /myrestresource: :
Enter Version 1.0: :
Show Advanced Setup? (Y/y/N/n) N: : N

Add Another Plugin Module? (Y/y/N/n) N: : N

4. Find information about Jira Software

Open terminal and run:

atlas-run

After Jira started, you will be able to see the target folder in your plugin directory.  Go to the target/jira/home/plugins/installed-plugins and look for jira-greenhopper-plugin. In my case the name of the file looks like this:

jira-greenhopper-plugin-7.9.0-DAILY20180326142825.jar

It means, that the version of the jira-greenhopper-plugin is  7.9.0-DAILY20180326142825. Let's add this dependency to the pom.xml. Add to the dependencies tags the following lines:

<dependency>
<groupId>com.atlassian.jira.plugins</groupId>
<artifactId>jira-greenhopper-plugin</artifactId>
<version>7.9.0-DAILY20180326142825</version>
<scope>provided</scope>
</dependency>

Ok. we added the required dependency. Now we have to find out how we can work with Jira Software Services.

Jira uses OSGI, that is why each plugin exports services, which can be used by other plugins. Let's see what Jira Software exports. Open the following link in your browser:

http://localhost:2990/jira/plugins/servlet/upm#osgi 

My screen looks like this:

Selection_046.png

Then find the Atlassian Greenhopper plugin and open the Registered Services menu:

Selection_047.png

Look at the services and you will find the required by us services:

Service 1477 com.atlassian.greenhopper.service.issue.RapidViewIssueService

Service 1476 com.atlassian.greenhopper.service.issuelink.EpicService

5. Add Jira Software functionality to the plugin.

Delete the sw-tutorial/src/test/java/ut/ru/matveev/alexey/sw/tutorial/rest/MyRestResourceTest.java file.

Change sw-tutorial/src/main/java/ru/matveev/alexey/sw/tutorial/rest/MyRestResource.java file to:

package ru.matveev.alexey.sw.tutorial.rest;

import com.atlassian.greenhopper.model.Epic;
import com.atlassian.greenhopper.service.Page;
import com.atlassian.greenhopper.service.PageRequests;
import com.atlassian.greenhopper.service.ServiceOutcome;
import com.atlassian.greenhopper.service.issue.RapidViewIssue;
import com.atlassian.greenhopper.service.issue.RapidViewIssueService;
import com.atlassian.greenhopper.service.issuelink.EpicService;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.IssueManager;
import com.atlassian.jira.jql.builder.JqlQueryBuilder;
import com.atlassian.jira.security.JiraAuthenticationContext;
import com.atlassian.jira.user.ApplicationUser;
import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport;
import com.atlassian.plugins.rest.common.security.AnonymousAllowed;
import com.atlassian.query.Query;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
* A resource of message.
*/
@Path("/message")
public class MyRestResource {

private static final Logger LOG = LoggerFactory.getLogger(MyRestResource.class);
private final EpicService epicService;
private final IssueManager issueManager;
private final JiraAuthenticationContext jiraAuthenticationContext;
private final RapidViewIssueService rapidViewIssueService;

@Inject
public MyRestResource(@ComponentImport EpicService epicService,
@ComponentImport IssueManager issueManager,
@ComponentImport JiraAuthenticationContext jiraAuthenticationContext,
@ComponentImport RapidViewIssueService rapidViewIssueService) {
this.epicService = epicService;
this.issueManager = issueManager;
this.jiraAuthenticationContext = jiraAuthenticationContext;
this.rapidViewIssueService = rapidViewIssueService;
}

@Path("/hello")
@GET
@AnonymousAllowed
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response getMessage()
{
return Response.ok(new MyRestResourceModel("Hello World")).build();
}

@Path("/epictasks")
@GET
@AnonymousAllowed
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response getEpicTasks(@QueryParam("epic key") String epicKey)
{
ApplicationUser user = jiraAuthenticationContext.getLoggedInUser();
ServiceOutcome<Epic> epic = epicService.getEpic(user, epicKey);
Query query = JqlQueryBuilder.newBuilder().where().buildQuery();
ServiceOutcome<Page<RapidViewIssue>> issues = rapidViewIssueService.getIssuesForEpic(user, epic.getValue(), PageRequests.request(0L, 100), query);
List<String> issueList = issues.getValue().getValues().stream().map(el -> el.getIssue().getSummary()).collect(Collectors.toList());
return Response.ok(new MyRestResourceModel(issueList.toString())).build();
}

@Path("/epictasks")
@POST
@AnonymousAllowed
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response addTaskToEpic(@QueryParam("epic key") String epicKey,
@QueryParam("issue key") String issueKey)
{
ApplicationUser user = jiraAuthenticationContext.getLoggedInUser();
ServiceOutcome<Epic> epic = epicService.getEpic(user, epicKey);
Set<Issue> issueSet = new HashSet<>();
issueSet.add(issueManager.getIssueByCurrentKey(issueKey));
epicService.addIssuesToEpic(user, epic.getValue(), issueSet);
return Response.ok(new MyRestResourceModel(issueKey + " added to " + epicKey)).build();
}
}

 The idea of this code to show how you can use Jira Software services, that is why the code is very raw and prone to NPE. Kindly do not pay attention to it.

I added a rest call called epictasks. If you execute epictasks with the GET method and pass the issue key of an epic, then you will see all issues, which are linked to the epic. If you execute epictaks with the POST method and pass an epic key and an issue key, then the issue will be linked to the epic.

You can create a Jira Software project, create an epic and create a task and then link them, using the REST calls.

For example, let 's say I have an epic with SW-1 key and an issue with SW-5 key. First I execute the GET method in the REST Browser and I can see the following result:

Selection_048.png

You can see that there is no issues linked to the epic yet. Then I execute the POST method:

Selection_049.png

You can see that the issue with the SW-5 key was added to the epic. Now we can execute the GET method and see the result:

 Selection_050.png

We can see that the issue was added to the epic.

We accomplished our goals.

You can find the code of this tutorial here:

https://bitbucket.org/alex1mmm/sw-tutorial

TAGS
AUG Leaders

Atlassian Community Events