Confluence has been updated to version 6.15.9

Page tree
Skip to end of metadata
Go to start of metadata


It is possible to do with TGE Java API and the ScriptRunner add-on

Please ensure that you have ScriptRunner and TGE version 1.18.0 or later installed on your JIRA.

Suppose you want to copy the content of one TGE grid to another TGE grid on some transition. Create a scripted post-function in the desired transition and paste there the following script.

In this script we assume that both grids have the same configuration (i.e the same number, names and configuration of the columns). Copying of the grid data to the grid with different columns is also possible, but it requires additional script customization.



 * copyGridToAnotherGrid.groovy
 * Copies data from source grid to destination grid.
 * Grids should have the same set of columns. In other case addRows() API call will throw an appropriate error.
 * Configuration:
 * - tgeSourceCustomFieldName      - name of the source grid custom field
 * - tgeDestinationCustomFieldName - name of the destination grid custom field
import com.atlassian.crowd.embedded.api.User
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.user.ApplicationUsers
import com.atlassian.plugin.PluginAccessor
import org.apache.log4j.Logger

// configuration (update it to match your JIRA settings)
String tgeSourceCustomFieldName = "TGE_SRC";
String tgeDestinationCustomFieldName = "TGE_DST";

// set up logger
Logger log = Logger.getLogger("com.idalko.scripts");

// find source TGE custom field
PluginAccessor pluginAccessor = ComponentAccessor.getPluginAccessor();
CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager();
CustomField tgeSourceCustomField = customFieldManager.getCustomFieldObjectByName(tgeSourceCustomFieldName);
if (tgeSourceCustomField == null) {
    log.error("Source grid '" + tgeSourceCustomFieldName + "' is not found");
Long tgeSourceCustomFieldId = tgeSourceCustomField.getIdAsLong();

// find destination TGE custom field
CustomField tgeDestinationCustomField = customFieldManager.getCustomFieldObjectByName(tgeDestinationCustomFieldName);
if (tgeDestinationCustomField == null) {
    log.error("Destination grid '" + tgeDestinationCustomFieldName + "' is not found");
Long tgeDestinationCustomFieldId = tgeDestinationCustomField.getIdAsLong();

// get current user
JiraAuthenticationContext jiraAuthenticationContext = ComponentAccessor.getOSGiComponentInstanceOfType(JiraAuthenticationContext.class);
Object userObject = jiraAuthenticationContext.getLoggedInUser();
ApplicationUser applicationUser = userObject instanceof ApplicationUser ? (ApplicationUser) userObject : ApplicationUsers.from(userObject);
User user = userObject instanceof ApplicationUser ? ((ApplicationUser) userObject).getDirectoryUser() : (User) userObject;

// read grid data from the source grid
Class dataManagerClass = pluginAccessor.getClassLoader().findClass("");
def tgeGridDataManager = ComponentAccessor.getOSGiComponentInstanceOfType(dataManagerClass);
List<Map<String, Object>> sourceGridData = new ArrayList<Map<String, Object>>();
try {
    def callResult = tgeGridDataManager.readGridData(issue.getId(), tgeSourceCustomFieldId, null, null, 0, 1000, user);
    sourceGridData = callResult.getValues();
    log.debug("Grid ID=" + tgeSourceCustomFieldId + " content: " + sourceGridData);
} catch (Exception e) {
    log.debug("Grid ID=" + tgeSourceCustomFieldId + " data cannot be retrieved: " + e.getMessage());

// get the list of grid columns
Class tgeConfigManagerClass = pluginAccessor.getClassLoader().findClass("com.idalko.jira.plugins.igrid.api.config.grid.TGEGridConfigManager");
def tgeConfigManager = ComponentAccessor.getOSGiComponentInstanceOfType(tgeConfigManagerClass);
def tgeGrid = tgeConfigManager.getGridConfigOrNull(tgeSourceCustomFieldId);
def columnConfigs = tgeGrid.getColumnConfigs();
List<String> columnConfigNames = new LinkedList<String>();
for (def columnConfig : columnConfigs) {
    String columnConfigName = columnConfig.getConfigName();
log.debug("Grid ID=" + tgeSourceCustomFieldId + " has following columns: " + columnConfigNames);

// transform fetched data
List<Map<String, Object>> gridDataToAdd = new LinkedList<Map<String, Object>>();
for (Map<String, Object> gridRow : sourceGridData) {
    Map<String, Object> rowToAdd = new HashMap<String, Object>();
    for (String columnName : columnConfigNames) {
        def columnValue = gridRow.get(columnName);
        if (columnValue instanceof Map) {
            columnValue = columnValue.get("value");
        rowToAdd.put(columnName, columnValue);
log.debug("Transformed data to add: " + gridDataToAdd);

// copy grid data to destination grid
try {
    tgeGridDataManager.addRows(issue.getId(), tgeDestinationCustomFieldId, gridDataToAdd, user);
    log.debug(gridDataToAdd.size() + " grid rows are added to Grid ID=" + tgeDestinationCustomFieldId);
} catch (Exception e) {
    log.debug("Grids rows cannot be added due to error: " + e.getMessage());

At the beginning of the script you can see configuration section. The names of the source grid and destination grid are specified there. Change them to match your grid configuration.

// configuration (update it to match your JIRA settings)
String tgeSourceCustomFieldName = "TGE_SRC";
String tgeDestinationCustomFieldName = "TGE_DST";