Add Custom Fields on Install

Heyo,

My plugin makes use of a number of custom fields, how do I go about creating those custom fields programatically when the plugin is installed?

JIRA version is 7.2.3.

Thanks,
Wyn

@Wyn, when you say plugin, did you mean a Java plugin, or Atlassian Connect?

Assuming it is a P2 plugin, take a look at Plugin Tutorials - J tricks - Little JIRA Tricks. You will have to adjust the APIs for the latest version but hopefully that is a good starting point.

Thanks for the replies.

@ibuchanan It’s a Java plugin.

@jobinkk That was my initial direction after a bit of googling (and actually found the page that you linked), but I ran into trouble where it said that “component” isn’t allowed when Atlassian-Plugin-Key is defined when I tried to run it. I tried looking for a more up-to-date example of a listener plugin, but had no luck.

you need to remove component and component-import declarations from atlassian-plugin.xml file since you are using new spring scanner method. It is default for all plugins created by atlas-sdk. Add @ComponentImport and @AutoWired annotations to your java classes.

@denizoguz Cheers for the reply, I’ve added a class in according to the link provided by jobinkk and modified it to include the annotations you mentioned, but now for some reason my plugin is disabled on startup and won’t enable, timing out and giving the following message in the logs:

Unresolved constraint in bundle com.reachal.jira.pow.JiraPow [166]: Unable to resolve 166.0: missing requirement [166.0] osgi.wiring.package; (osgi.wiring.package=groovy.lang)

Not sure if maybe I’ve missed out a dependency in the pom file or something? Can’t find anything for osgi.wiring.

The listener class I added is as follows:

package com.reachal.jira.pow;

import com.atlassian.jira.issue.CustomFieldManager;
import com.atlassian.jira.issue.context.GlobalIssueContext;
import com.atlassian.jira.issue.context.JiraContextNode;
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.issue.fields.screen.FieldScreen;
import com.atlassian.jira.issue.fields.screen.FieldScreenManager;
import com.atlassian.jira.issue.fields.screen.FieldScreenTab;
import com.atlassian.jira.issue.issuetype.IssueType;
import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.List;

public class LifecycleListener implements InitializingBean, DisposableBean {
    private static final String TEST_TEXT_CF = "Test Text CF";

    @Autowired
    private CustomFieldManager customFieldManager;

    @Autowired
    private FieldScreenManager fieldScreenManager;

    public LifecycleListener(@ComponentImport CustomFieldManager customFieldManager, @ComponentImport FieldScreenManager fieldScreenManager)
    {
        this.customFieldManager = customFieldManager;
        this.fieldScreenManager = fieldScreenManager;
    }

    @Override
    public void destroy() throws Exception {
        //Get the already installed custom field by name
        CustomField cField = customFieldManager.getCustomFieldObjectByName(TEST_TEXT_CF);
        //Remove if not null
        if (cField != null) {
            customFieldManager.removeCustomField(cField);
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        //Create a list of issue types for which the custom field needs to be available
        List<IssueType> issueTypes = new ArrayList<IssueType>();
        issueTypes.add(null);

        //Create a list of project contexts for which the custom field needs to be available
        List<JiraContextNode> contexts = new ArrayList<JiraContextNode>();
        contexts.add(GlobalIssueContext.getInstance());

        //Add custom field
        CustomField cField = customFieldManager.createCustomField(TEST_TEXT_CF, "A Sample Text Field",
                customFieldManager.getCustomFieldType("com.atlassian.jira.plugin.system.customfieldtypes:textfield"),
                customFieldManager.getCustomFieldSearcher("com.atlassian.jira.plugin.system.customfieldtypes:textsearcher"),
                contexts, issueTypes);

        // Add field to default Screen
        FieldScreen defaultScreen = fieldScreenManager.getFieldScreen(FieldScreen.DEFAULT_SCREEN_ID);
        if (!defaultScreen.containsField(cField.getId())) {
            FieldScreenTab firstTab = defaultScreen.getTab(0);
            firstTab.addFieldScreenLayoutItem(cField.getId());
        }
    }
}

I think you have dependency to groovy in Import-Package section of pom.xml. try removing it if it exist.

No dependency for anything called ‘groovy’, but I did put some additional dependencies in and it changed from groovy.lang to com.google.gson. The closest dependency I can find is com.google.code.gson, but commenting out the dependency makes no difference.

Dependencies are as follows, maybe I’m missing something?

<dependencies>
        <dependency>
            <groupId>com.atlassian.jira</groupId>
            <artifactId>jira-api</artifactId>
            <version>${jira.version}</version>
            <scope>provided</scope>
        </dependency>
        <!-- Add dependency on jira-core if you want access to JIRA implementation classes as well as the sanctioned API. -->
        <!-- This is not normally recommended, but may be required eg when migrating a plugin originally developed against JIRA 4.x -->
        <!--
        <dependency>
            <groupId>com.atlassian.jira</groupId>
            <artifactId>jira-core</artifactId>
            <version>${jira.version}</version>
            <scope>provided</scope>
        </dependency>
        -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.atlassian.plugin</groupId>
            <artifactId>atlassian-spring-scanner-annotation</artifactId>
            <version>${atlassian.spring.scanner.version}</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.atlassian.plugin</groupId>
            <artifactId>atlassian-spring-scanner-runtime</artifactId>
            <version>${atlassian.spring.scanner.version}</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.1</version>
            <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.atlassian.sal/sal-api -->
        <dependency>
            <groupId>com.atlassian.sal</groupId>
            <artifactId>sal-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <!-- Used for LifecycleListener -->
        <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
            <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${springframework.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${springframework.version}</version>
            <scope>compile</scope>
        </dependency>
        <!-- WIRED TEST RUNNER DEPENDENCIES -->
        <dependency>
            <groupId>com.atlassian.plugins</groupId>
            <artifactId>atlassian-plugins-osgi-testrunner</artifactId>
            <version>${plugin.testrunner.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>javax.ws.rs</groupId>
            <artifactId>jsr311-api</artifactId>
            <version>1.1.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.0</version>
            <scope>provided</scope>
        </dependency>
        <!-- Uncomment to use TestKit in your project. Details at https://bitbucket.org/atlassian/jira-testkit -->
        <!-- You can read more about TestKit at https://developer.atlassian.com/display/JIRADEV/Plugin+Tutorial+-+Smarter+integration+testing+with+TestKit -->
        <!--
		<dependency>
			<groupId>com.atlassian.jira.tests</groupId>
			<artifactId>jira-testkit-client</artifactId>
			<version>${testkit.version}</version>
			<scope>test</scope>
		</dependency>
		-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.4</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.atlassian.plugins.rest</groupId>
            <artifactId>atlassian-rest-common</artifactId>
            <version>1.0.2</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.wink</groupId>
            <artifactId>wink-client</artifactId>
            <version>1.1.3-incubating</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.1.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.6.6</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

hello ibuchanan

how can we do same for atlassian-connect

Assuming you are developing for Jira Cloud, there is the Issue Field module:
https://developer.atlassian.com/cloud/jira/platform/modules/issue-field/

thanks remie,

how can i add options to the field created using https://developer.atlassian.com/cloud/jira/platform/modules/issue-field/

regards,
pooja

That strongly depends on what kind of settings you are referring to, but perhaps a good place to start is the Issue Field example project from Atlassian (Bitbucket).

In the example they created a custom field that allow you to assign issues to a “Team”. As this notion does not exist in Jira, the values are actually populated from their own database. To enable users to manage their teams, additional integration have been made with their own UI to accommodate this.

This is a good example of how one would go about creating custom fields in Atlassian Connect.