Elements Connect

Transferring 3rd party app field into Elements Connect field

Context

During the Cloud migration assessment phase, organizations may identify use cases that need to be addressed before the migration can take place. Common examples include:

  • Custom fields created by a third-party app that is not available on Cloud.

  • Custom fields created by a third-party app that is available on Cloud, but whose Cloud version has limitations that no longer meet the organization's requirements.

In these situations, it may be decided to replace the existing field with an Elements Connect field, regardless of whether Elements Connect was already being used on Data Center or is being introduced specifically for this migration.

The key point is that this field replacement should be completed on the Data Center instance before the migration to Cloud. Doing so ensures that the data is already stored in a format supported by the target Cloud environment, helping to reduce migration complexity and minimize the risk of data loss or unsupported configurations.

Process

Choosing the appropriate Elements Connect field type

Elements Connect Data Center provides two type of fields that support different use cases.

  • Live fields: they have two important values

    • Key: This is the only value stored in Jira and this is the value needed to populate (set) the field.

    • Template: This is the value displayed to users on the issue view. It is dynamically retrieved from the datasource based on the stored Key and is not stored in Jira.

  • Snapshot fields: they behave differently because the displayed value is stored directly in Jira, meaning the stored value and the displayed value are identical.

It’s important to mention that Elements Connect field type on Data Center will be maintained when migrating Elements Connect fields values to Cloud with JCMA, so it’s important to select the type carefully.

As Live fields are the most commonly used, the remainder of this guide focuses on the considerations when transferring an existing Jira custom field (or a custom field created by a third-party app) to an Elements Connect Live field.

Throughout this guide, we will refer to the existing field that needs to be replaced by Elements Connect as the source field.

Transferring the source field into Elements Connect Live text field

Extract the source field ID

Two possible ways to get the source field ID, use the one that suits you.

Jira REST API

Use this endpoint after replacing YOUR_JIRA_BASE_URL according to your own Jira instance

https://YOUR_JIRA_BASE_URL/rest/api/latest/field

Search for the field name and note its ID (customfield_xxxxx)

Jira Database

Execute this query

SQL
SELECT id
FROM customfield
WHERE cfname = 'MY_SOURCE_FIELD_NAME'

Returned value will be field ID “xxxxx”, the field is customfield_xxxxx.

Extract the value stored in Jira Database for the source field

The below process should be per field type.

To identify the storage format of the source field, you can follow one of the methods listed below

Jira REST API

Use this endpoint after replacing YOUR_JIRA_BASE_URL according to your own Jira instance,ISSUE_KEY with an issue where the source field is set, and customfield_xxxxxby the source field ID extracted in previous step:

https://YOUR_JIRA_BASE_URL/rest/api/2/issue/ISSUE_KEY?fields=customfield_xxxxx
Jira Database

Execute this query after replacing the customfield_xxxxxby the extracted source field ID

SQL
SELECT issue, stringvalue
FROM customfieldvalue
WHERE customfield = customfield_xxxxx

As explained earlier, a Live Text field stores only its Key (check this tutorial to know how to select a good Key in general). Therefore, when populating an Elements Connect Live field, the only value that needs to be written into the field is the Key.

Create Datasource in Elements Connect

Different Datasource are supported in Elements Connect Data Center (check here), create the Datasource that suits your use case.

When creating the datasource in Elements Connect, it’s crucial that it will hold and return the values saved in the source field; otherwise, those values can’t be copied and populated in Connect fields.

Create and configure Elements Connect field

As mentioned earlier, this process will handle transferring the source field into Elements Connect field of type Live text; however, it’s possible to configure different field types.

In Elements Connect administration page, Fields tab, create a new field:

  • Category Live and Type text

  • Click on the field to configure it

  • Select “Create a default configuration”

  • Select the datasource configured previously

  • Configure the field based on the datasource type, here are some examples.

  • Test the field configuration (in the configuration tester) to make sure the query is retrieving the desired data

  • Save field configuration

  • Create an issue and try to set the field (select a value) to confirm it’s well configured

Copy the data from source field into Connect field

This is a general process that aim to explain the logic to follow when transferring a field from 3rd party app field into Elements Connect field; however; it doesn't cover all possible storage formats of fields from different apps

You might need to adjust the below to match your use case, field type.

Below are some points to consider:

  • We suggest running the script first on limited number of issues.

  • In case of thousands of issues where the source field needs to be copied, adjust the JQL and run the script in batches per project, issue type, …

  • The below script will copy the data stored in Jira for the source field “customfield_xxxxx” (single value) into Elements Connect Live Text field.

  • The storage format of the source field value in Jira REST API is like below (where “zzzzz” should be returned by the Datasource and should match the Key value of the Elements Connect field).

    JSON
    {
      "customfield_xxxxx": "zzzzz"
    }
    

Here’s the script to run

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.bc.issue.search.SearchService
import com.atlassian.jira.web.bean.PagerFilter

// Source  field containing the value (key) to be copied.
// Replace with the source field ID (the field you want to migrate from)
final String SOURCE_FIELD_ID = "customfield_xxxxx"

// Target Elements Connect custom field.
// Replace with the Elements Connect field ID that should receive the value.
final String TARGET_FIELD_ID = "customfield_yyyyy"

// Edit the JQL below to retrieve only the issues that should be updated.
// It is recommended to narrow down the search as much as possible
// (for example by project, issue type, or another condition).
final String JQL = '''
    project = PM
'''

// Retrieve the currently logged-in user.
// The script runs with this user's permissions.
def currentUser = ComponentAccessor.jiraAuthenticationContext.loggedInUser

// Retrieve the source custom field object.
def sourceField = ComponentAccessor.customFieldManager
    .getCustomFieldObject(SOURCE_FIELD_ID)

// SearchService is used to validate and execute the JQL query.
def searchService = ComponentAccessor.getComponent(SearchService)

// Retrieve the Elements Connect plugin.
// This is required to access the internal API used to update Connect fields.
def plugin = ComponentAccessor.pluginAccessor
    .getPlugin("com.valiantys.jira.plugins.SQLFeed")

// Stop execution if the plugin or source field cannot be found.
assert plugin : "Elements Connect plugin was not found"
assert sourceField : "Source field was not found"

// Load the Elements Connect FieldValueService.
// This service is responsible for writing values into Connect fields.
def serviceClass = plugin.classLoader
    .loadClass("com.valiantys.nfeed.api.IFieldValueService")

def fieldValueService =
    ComponentAccessor.getOSGiComponentInstanceOfType(serviceClass)

assert fieldValueService : "Elements Connect FieldValueService was not found"

// Validate the JQL before executing it.
def parseResult = searchService.parseQuery(currentUser, JQL)
assert parseResult.valid : parseResult.errors

// Execute the search and retrieve all matching issues.
// For very large datasets, consider processing issues in batches instead
// of using PagerFilter.unlimitedFilter.
def issues = searchService.search(
    currentUser,
    parseResult.query,
    PagerFilter.unlimitedFilter
).results

// Counters used for the execution summary.
int updated = 0
int skipped = 0
int errors = 0

// Process each issue returned by the JQL.
issues.each { issue ->
    try {

        // Read the value from the source field.
        // The value will be used as the Elements Connect key.
        String connectKey = issue
            .getCustomFieldValue(sourceField)
            ?.toString()
            ?.trim()

        // Skip issues where the source field is empty.
        if (!connectKey) {
            skipped++
            return
        }

        // Update the Elements Connect field.
        // The provided value is stored as the Connect key.
        // Elements Connect will automatically resolve and display
        // the corresponding template value based on the datasource configuration.
        fieldValueService.setFieldValue(
            issue.key,
            TARGET_FIELD_ID,
            connectKey
        )

        updated++

    } catch (Exception e) {

        // Continue processing the remaining issues even if one fails.
        errors++

        // Log the issue key and error message for troubleshooting.
        log.error("${issue.key}: ${e.message}")
    }
}

// Display a summary after the script completes.
return """
Processed: ${issues.size()}
Updated: ${updated}
Skipped: ${skipped}
Errors: ${errors}
""".stripIndent()