📜 ⬆️ ⬇️

JIRA and Confluence customization with plugins

Virtually all organizations where it is necessary to maintain documentation and manage business processes are faced with the need to select and configure software that facilitates these processes. JIRA and Confluence from Atlassian Software are quite popular in the Russian market. However, in their default configuration, they cannot solve all the tasks facing the organization - after all, each has its own vision of the work processes. In addition, requirements to customize JIRA grow as the product is used.

I work as a JIRA / Confluence developer at Mail.Ru Group, and I want to share the experience of writing plug-ins JIRA and Confluence: what can I do, how to do it and what I need not forget.

What I will tell you

There will be several posts on the development of various components. Plugins and source code can be found here .
')
Plugin description will include:

In this article I will comment on working plugins, the source code of which can be found here . To run the source is enough to read the article .

Custom fields

So let's start with custom fields. Fields are the basic unit of data in JIRA. They contain issues data. Fields in JIRA as a whole can be divided into two main categories: system fields and user fields. System fields include various forms, such as text fields, drop-down lists, and others. In practice, basic functionality is often not enough, and we need to program our custom fields (for example, a field that calculates the sum of other fields or the number of comments).

The first plugin (Query Issues Custom Fields) is a list whose values ​​are the requirement keys (issues) that are selected from the customized search query (JQL). The value of the list is the issue number.

Thus, the values ​​are updated automatically each time you edit and view the field. Ready plugin is here .

So, we want to develop a plugin that can be used for various projects, it is easy to use, and it works on all versions of JIRA.

To implement the first requirement, we need to organize a plugin data store where we can save the query (JQL) and other settings for the custom field being developed. To store a search query (JQL) it is advisable to use a data container for plug-ins (com.atlassian.sal.api.pluginsettings.PluginSettings). It should be noted that with this choice we will not have problems with the portability of the plug-in to other versions of JIRA. In addition, if you use the Java object serialization library (for example, XStream ) to represent an object as a string, we can store data of any structure. To use the repository, you need to add the following lines to the atlassian-plugin.xml plugin configuration file:

<!-- Plugin data manager --> <component key="queryfields-config" name="Query issues custom fields plugin configuration" class="ru.mail.jira.plugins.lf.QueryFieldsMgrImpl"/> <!-- Components which required for injection --> <component-import key="pluginSettingsFactory"> <interface>com.atlassian.sal.api.pluginsettings.PluginSettingsFactory</interface> </component-import> 

and determine the interface that performs the required manipulations,
Interface source code
 public interface QueryFieldsMgr { /** * Get "add null" option. */ boolean getAddNull(long cfId, long projId); /** * Get stored data for the custom field. */ String getQueryFieldData(long cfId, long projId); /** * Set "add null" option. */ void setAddNull(long cfId, long projId, boolean data); /** * Put data for the custom field. */ void setQueryFieldData(long cfId, long projId, String data); } 


and implement it:
Source code interface implementation
 import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory; public class QueryFieldsMgrImpl implements QueryFieldsMgr { /** * PlugIn key. */ private static final String PLUGIN_KEY = "QUERY_LINKING_ISSUE_CFS"; /** * Property separator. */ private static final String VAL_SEPARATOR = "||"; /** * Plug-In settings factory. */ private final PluginSettingsFactory pluginSettingsFactory; /** * Constructor. */ public QueryFieldsMgrImpl( PluginSettingsFactory pluginSettingsFactory) { this.pluginSettingsFactory = pluginSettingsFactory; } /** * Create property key. */ private String createPropKey(long cfId, long projId) { return (cfId + VAL_SEPARATOR + projId); } @Override public boolean getAddNull(long cfId, long projId) { String addNull = (String)pluginSettingsFactory.createSettingsForKey(PLUGIN_KEY).get(createPropKey(cfId, projId).concat(".addnull")); return Boolean.parseBoolean(addNull); } @Override public String getQueryFieldData( long cfId, long projId) { return (String)pluginSettingsFactory.createSettingsForKey(PLUGIN_KEY).get(createPropKey(cfId, projId)); } @Override public void setAddNull(long cfId, long projId, boolean data) { pluginSettingsFactory.createSettingsForKey(PLUGIN_KEY).put(createPropKey(cfId, projId).concat(".addnull"), Boolean.toString(data)); } @Override public void setQueryFieldData( long cfId, long projId, String data) { pluginSettingsFactory.createSettingsForKey(PLUGIN_KEY).put(createPropKey(cfId, projId), data); } } 



After that, a specific data manager can be used in any servlets and extensions of standard Jira components, for example:
 public class LinkerField extends TextCFType implements SortableCustomField<String> { /** * PlugIn data manager. */ private final QueryFieldsMgr qfMgr; /** * Constructor. */ public LinkerField( CustomFieldValuePersister customFieldValuePersister, GenericConfigManager genericConfigManager, QueryFieldsMgr qfMgr) { super(customFieldValuePersister, genericConfigManager); this.qfMgr = qfMgr; } ... 


It is also a good practice to implement the administrative settings page of the plugin. On the page it makes sense to print a list of all project management fields and provide the page with controls to customize the field. The class that implements the administrative page is best made a heir from com. atlassian.jira.web.action.JiraWebActionSupport . An example of a class is email.jira.plugins.lf.QueryFieldsConfig . To connect to the plugin, it is enough to add the following lines to atlassian-plugin.xml :
 <web-item key="queryfields-configuration" name="Query issues custom fields configuration link" section="admin_plugins_menu/mailru-admin-section" weight="95"> <label key="queryfields.admin.title"/> <condition class="com.atlassian.jira.plugin.webfragment.conditions.JiraGlobalPermissionCondition"> <param name="permission">admin</param> </condition> <link linkId="queryfields-configuration">/secure/QueryConfigCfsConfig.jspa</link> </web-item> <webwork1 key="queryfields_conf" name="Query issues custom fields configuration" class="java.lang.Object"> <actions> <action name="ru.mail.jira.plugins.lf.QueryFieldsConfig" alias="QueryConfigCfsConfig"> <view name="input">/templates/queryfieldsconf.vm</view> <view name="success">/templates/queryfieldsconf.vm</view> </action> </actions> </webwork1> 


For more details on how to implement JIRA URL actions, see here .
In addition, it should be remembered that the administrative page should be protected from XSRF attacks. Read more about it here .

If we cannot decide how we will display our field, then we can take a simple text field ( ru.mail.jira.plugins.lf.LinkerField ) as a basis and expand it. It is impossible to build charts and collect statistics on text fields, but this functionality can be implemented by: ru.mail.jira.plugins.lf.LirkerFieldSearcher , ru.mail.jira.plugins.lf.LirkerFieldCustomFieldValueProvider , ru.mail.jira.plugins.lf .LirkerFieldSearchInputTransformer and en.mail.jira.plugins.lf.LirkerFieldCustomFieldRenderer .

After that, we just have to program the appearance for editing and the view: edit-linkerfield.vm and view-linkerfield.vm .

I want to note that if you do not know how to program a presentation, I advise you to see how the standard fields are implemented: webapp / WEB-INF / classes / templates / plugins / fields.

This approach can be used to implement custom fields of any complexity. For example, in this way you can implement a colorpicker, a list of calculated fields, formulas, and so on.

Event handlers


The second plugin I want to comment on is the JIRA MRIM Listener. This plugin sends event notifications to JIRA to Mail.Ru Agent. To create such a plugin, it is enough to implement only one event handler. Here is the class template:
Source
 public class MyListener implements InitializingBean, DisposableBean { /* * Logger. */ private static Log log = LogFactory.getLog(MyListener.class); /** * Event publisher. */ private EventPublisher eventPublisher; /** * Constructor. */ public MyListener ( EventPublisher eventPublisher) { this.eventPublisher = eventPublisher; } @Override public void afterPropertiesSet() throws Exception { //--> register ourselves with the EventPublisher eventPublisher.register(this); } @Override public void destroy() throws Exception { //--> unregister ourselves with the EventPublisher eventPublisher.unregister(this); } @EventListener public void onIssueEvent(IssueEvent issueEvent) { // your code here } } 


The source code is here . It is worth noting that for filtering events here you can use the plugin's data warehouse, similar to that described in the previous example. Using an event handler, you can create related requests, sign file attachments, send HTTP requests, and more.

Instead of conclusion


For those who are interested in development, but have never done it yet, I want to recommend the book - the JIRA Development Cookbook and keep track of free plugins at https://market.atlassian.com/vendors/37127 .

That's all I wanted to tell you. If you have any questions or want to share your thoughts about JIRA and Confluence, I will be glad to talk with you in the comments. In addition, if you have ideas for a free plug-in, write, do, or help with the implementation.

Source: https://habr.com/ru/post/149329/


All Articles