Jelly Examples

All Versions

JIRA 4.0 Beta Documentation

Jelly is a scripting and templating language from Apache's Jakarta project. 

We use it within JIRA to import and manipulate data.

This page contains example scripts highlighting the more advanced capabilities of Jelly.

Retrieving a list of all users

Jelly can actually create and invoke methods on Java objects.  This script utilizes this to retrieve a list of all the users in JIRA:

<JiraJelly xmlns:jira="jelly:com.atlassian.jira.jelly.enterprise.JiraTagLib" xmlns:core="jelly:core">

<core:invokeStatic className="com.opensymphony.user.UserManager"method="getInstance" var="instance"/>
<core:invoke on="${instance}" method="getUsers" var="users"/>

<core:forEach var="user" items="${users}">
//do something with ${user}
</core:forEach>
</JiraJelly>

Retrieving all users from a group

Like the above script, this script creates an instance of the UserManager.  It then retrieves all the users from a group.

<JiraJelly xmlns:jira="jelly:com.atlassian.jira.jelly.enterprise.JiraTagLib" xmlns:j="jelly:core" xmlns:util="jelly:util">
<j:invokeStatic className="com.opensymphony.user.UserManager" method="getInstance" var="instance"/>
<j:invoke on="${instance}" method="getGroup" var="grp">
<j:arg type="java.lang.String" value="thegroupname"/>
</j:invoke>
<j:invoke on="${grp}" method="getUsers" var="users"/>
</JiraJelly>

Timeout an email to a new state with auto-response

See Jelly Escalation For Support.

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Jul 24, 2007

    Mark Michaelis says:

    Wouldn't it be nice to have a place here where to place User Contributed Jelly S...

    Wouldn't it be nice to have a place here where to place User Contributed Jelly Scripts? I found some in the forum but there is still a lot of white space to be filled. Well, perhaps the easiest solution is what I am doing now: Here is one my examples as comment:

    Bulk Change Comment Visibility

    <JiraJelly xmlns:jira="jelly:com.atlassian.jira.jelly.JiraTagLib" xmlns:util="jelly:util" xmlns:core="jelly:core" xmlns:log="jelly:log">
    	<!--
    	    This script will set the visiblity for comments to a certain
    	    group. The issues affected are those returned by the
    	    filter configured below.
    
    	    Mark Michaelis, CoreMedia AG, Hamburg, Germany
    	-->
    	
    	<core:set var="myName" value="Comment Visibility Setter"/>
    	
    	<log:warn>&gt;&gt;&gt; Starting ${myName} &lt;&lt;&lt;</log:warn>
    	
    	<!-- ************* -->
    	<!-- Configuration -->
    	<!-- ************* -->
    	
    	<!-- The id of the filter where the issues should get a new security level set. -->
    	<core:set var="issuesFilter" value="10892"/>
    	<!-- The Security Level to use. -->
    	<core:set var="targetVisibilityGroupName" value="someGroup"/>
    	
    	<log:debug trim="true">
    		Configuration:
    		- Issue Filter: ID = ${issuesFilter}
    		- Comment Visibility: Group = ${targetVisibilityGroupName}
    	</log:debug>
    	
    	<!-- ******** -->
    	<!-- Managers -->
    	<!-- ******** -->
    	
    	<!-- The ComponentManager will be used to access all other managers. com.atlassian.jira.ComponentManager -->
    	<core:invokeStatic className="com.atlassian.jira.ComponentManager" method="getInstance" var="componentManager"/>
    	<!-- The IssueManager is required to resolve issues returned by search-requests to "normal" JIRA issue objects -->
    	<core:invoke on="${componentManager}" method="getIssueManager" var="issueManager"/>
    	<!-- The CommentManager will return comments of an issue; com.atlassian.jira.issue.comments.CommentManager -->
    	<core:invoke on="${componentManager}" method="getCommentManager" var="commentManager"/>
    	
    	<!-- ************* -->
    	<!-- Search Issues -->
    	<!-- ************* -->
    	
    	<jira:RunSearchRequest filterid="${issuesFilter}" var="issues" size-var="issueCount" />
    	
    	<log:warn trim="true">
    		${myName}: Found ${issueCount} issues to change.
    	</log:warn>
    	
    	<!-- *********************************** -->
    	<!-- Match Issues and possibly link them -->
    	<!-- *********************************** -->
    	
    	<core:forEach var="issue" items="${issues}">
    		<log:warn>${myName}: Working on issue ${issue.key}</log:warn>
    		<!-- First resolve the sourceIssue to a _real_ JIRA Issue object -->
    		<core:invoke on="${issueManager}" method="getIssueObject" var="jiraIssue">
    			<core:arg type="java.lang.String" value="${issue.key}"/>
    		</core:invoke>
    		
    		<core:invoke on="${commentManager}" method="getComments" var="comments">
    			<core:arg type="com.atlassian.jira.issue.Issue" value="${jiraIssue}"/>
    		</core:invoke>
    		
    		<core:forEach var="comment" items="${comments}">
    			<core:invoke on="${comment}" method="setGroupLevel">
    				<core:arg type="java.lang.String" value="${targetVisibilityGroupName}"/>
    			</core:invoke>
    			<core:invoke on="${commentManager}" method="update">
    				<core:arg type="com.atlassian.jira.issue.comments.Comment" value="${comment}"/>
    				<core:arg type="boolean" value="false"/> <!-- Don't send update notifications -->
    			</core:invoke>
    		</core:forEach>
    		
    	</core:forEach>
    	
    	<log:warn>&gt;&gt;&gt; ${myName} Done &lt;&lt;&lt;</log:warn>
    </JiraJelly>
    

    Mind that I set some loggings to level warn just to make them appear in the log without further configuration. Actually I don't know how to configure logging to make it more verbose for jelly scripts.

  2. Jul 24, 2007

    Mark Michaelis says:

    Bulk Update Issue Security Levels The following script will update the security...

    Bulk Update Issue Security Levels

    The following script will update the security levels of the issues returned by a filter. The script requires two arguments:

    • issueFilter – the id of the filter which returns the issues to process
      The ID can be found out e. g. on the Manage Filters screen. Just extract the requestId from the filter link.
    • targetSecurityLevelId – the id of the security level to set
      To get the id go to Administration / Issue Security Schemes / Operations: Security Levels. Then analyze the URL for the operations. The parameter security is what you are searching for.

    The script does not check for any errors, e. g. if the security level is valid in the given context of the issue. To go into detail here, have a look at the Forum.

    One last thing: On overviews (such as filter results) the issues will still appear with the old security level. Re-Indexing is your friend here.

    <JiraJelly xmlns:jira="jelly:com.atlassian.jira.jelly.JiraTagLib" xmlns:util="jelly:util" xmlns:core="jelly:core" xmlns:log="jelly:log">
    	<!--
    	    This script will set the security level of the issues returned
    	    by the search request. See settings below for configuration.
    	    
    	    Mark Michaelis, CoreMedia AG, Hamburg, Germany
    	    -->
    	
    	<core:set var="myName" value="Security Level Setter"/>
    	
    	<log:warn>&gt;&gt;&gt; Starting ${myName} &lt;&lt;&lt;</log:warn>
    	
    	<!-- ************* -->
    	<!-- Configuration -->
    	<!-- ************* -->
    	
    	<!-- The id of the filter where the issues should get a new security level set. -->
    	<core:set var="issuesFilter" value="10901"/>
    	<!-- The Security Level to use. -->
    	<core:set var="targetSecurityLevelId" value="10001"/>
    	
    	<!-- ******** -->
    	<!-- Managers -->
    	<!-- ******** -->
    	
    	<!-- The ComponentManager will be used to access all other managers. com.atlassian.jira.ComponentManager -->
    	<core:invokeStatic className="com.atlassian.jira.ComponentManager" method="getInstance" var="componentManager"/>
    	<!-- The IssueManager is required to resolve issues returned by search-requests to "normal" JIRA issue objects -->
    	<core:invoke on="${componentManager}" method="getIssueManager" var="issueManager"/>
    	
    	<core:invokeStatic className="java.lang.Class" method="forName" var="IssueSecurityLevelManager.class">
    		<core:arg type="java.lang.String" value="com.atlassian.jira.issue.security.IssueSecurityLevelManager"/>
    	</core:invokeStatic>
    	<core:invokeStatic className="com.atlassian.jira.ComponentManager" method="getComponentInstanceOfType" var="issueSecurityLevelManager">
    		<core:arg type="java.lang.Class" value="${IssueSecurityLevelManager.class}"/>
    	</core:invokeStatic>
    	
    	<core:invoke on="${issueSecurityLevelManager}" method="getIssueSecurityName" var="securityLevelName">
    		<core:arg type="java.lang.Long" value="${targetSecurityLevelId}"/>
    	</core:invoke>
    	
    	<core:invoke on="${issueSecurityLevelManager}" method="getIssueSecurityLevel" var="securityLevel">
    		<core:arg type="java.lang.Long" value="${targetSecurityLevelId}"/>
    	</core:invoke>
    	
    	<log:warn trim="true">
    		Configuration:
    		- Issue Filter: ID = ${issuesFilter}
    		- Security Level: ${targetSecurityLevelId} (${securityLevelName})
    	</log:warn>
    	
    	<!-- ************* -->
    	<!-- Search Issues -->
    	<!-- ************* -->
    	
    	<jira:RunSearchRequest filterid="${issuesFilter}" var="issues" size-var="issueCount" />
    	
    	<log:warn trim="true">
    		${myName}: Found ${issueCount} issues to change.
    	</log:warn>
    	
    	<!-- *********************************** -->
    	<!-- Match Issues and possibly link them -->
    	<!-- *********************************** -->
    	
    	<core:forEach var="issue" items="${issues}">
    		<log:warn>${myName}: Working on issue ${issue.key}</log:warn>
    		<!-- First resolve the sourceIssue to a _real_ JIRA Issue object -->
    		<core:invoke on="${issueManager}" method="getIssueObject" var="jiraIssue">
    			<core:arg type="java.lang.String" value="${issue.key}"/>
    		</core:invoke>
    		
    		<core:invoke on="${jiraIssue}" method="setSecurityLevel">
    			<core:arg type="org.ofbiz.core.entity.GenericValue" value="${securityLevel}"/>
    		</core:invoke>
    		
    		<core:invoke on="${jiraIssue}" method="store"/>
    	
    	</core:forEach>
    	
    	<log:warn>&gt;&gt;&gt; ${myName} Done &lt;&lt;&lt;</log:warn>
    </JiraJelly>
    
  3. Apr 23, 2008

    Gbegley says:

    Creating A Subtask Here is a jelly script that will create a subtask without th...

    Creating A Subtask

    Here is a jelly script that will create a subtask without the addition or modification to the Jira code base.
    Special thanks to Mark for his example subtask jelly tag that provided the necessary insight into the Manager API.

    <JiraJelly  xmlns:jira="jelly:com.atlassian.jira.jelly.enterprise.JiraTagLib" xmlns:j="jelly:core">
     <j:new var="date" className="java.util.Date"/>
     <j:invokeStatic var="componentManager" className="com.atlassian.jira.ComponentManager" method="getInstance"/>
     <j:invokeStatic var="issueManager" className="com.atlassian.jira.ManagerFactory" method="getIssueManager"/>
     <j:invoke var="subTaskManager" on="${componentManager}" method="getSubTaskManager"/>
     <jira:CreateIssue
          project-key="JELLY"
          summary="Jelly created parent issue: ${date.time}"
          issueKeyVar="parentIssuekey"
          issueIdVar="parentIssueId"
          reporter="support"
          assignee="jelly"/>
    parent issue key: ${parentIssueKey}
    parent issue id: ${parentIssueId}
     <jira:CreateIssue
          project-key="JELLY"
          summary="Jelly created child issue: ${date.time}"
          issueKeyVar="issuekey"
          issueIdVar="childIssueId"
          reporter="support"
          assignee="jelly"/>
    child issue key: ${childIssueKey}
    child issue id: ${childIssueId}
     <j:invoke  var="parentIssue" on="${issueManager}" method="getIssue">
      <j:arg value="${parentIssueId}" type="java.lang.Long"/>
     </j:invoke>
     <j:invoke  var="childIssue" on="${issueManager}" method="getIssue">
      <j:arg value="${childIssueId}" type="java.lang.Long"/>
     </j:invoke>
    parentIssue: ${parentIssue}
    child issue: ${childIssue}
     <j:invoke on="${subTaskManager}" method="createSubTaskIssueLink">
      <j:arg value="${parentIssue}" type="org.ofbiz.core.entity.GenericValue"/>
      <j:arg value="${childIssue}" type="org.ofbiz.core.entity.GenericValue"/>
      <j:arg value="${parentIssue.getAssignee()}" type="com.opensymphony.user.User"/>
     </j:invoke>
    </JiraJelly>
    
  4. Aug 14, 2008

    amina says:

    I use this jelly script in order to close all the issues resolved and not apdate...

    I use this jelly script in order to close all the issues resolved and not apdated by the customer

    <JiraJelly xmlns:jira="jelly:com.atlassian.jira.jelly.enterprise.JiraTagLib" xmlns:core="jelly:core" xmlns:log="jelly:log" >
    <jira:Login username="admin" password="admin">
        <log:info>Running Close issues service</log:info>
        <!- Properties for the script ->
        <core:set var="comment">This issue has not been updated for 8 business days and will be Closed.
       
    If this issue has not been completed please reopen this issue and we will do our best to help you as soon as we can.
       
    Thank you,
       
      The Atlassian Support Team</core:set>
        <core:set var="workflowStep" value="3" />
        <core:set var="workflowUser" value="admin" />
        <core:set var="filter7Days" value="10000" />

        <!- Run the SearchRequestFilter ->
        <jira:RunSearchRequest filterid="${filter7Days}" var="issues" />
       
        <!- Iterate over the issues ->
        <core:forEach var="issue" items="${issues}">
            <log:warn>Closing inactive issue ${issue.key}</log:warn>
            <jira:TransitionWorkflow key="${issue.key}" user="${workflowUser}" workflowAction="${workflowStep}" comment="${comment}" resolution="$(fixed)"/>
        </core:forEach>
    </jira:Login>
    </JiraJelly>

     How can I set the delay to 7, 8 or 10 days? is it in the filter I'll configure? (in the filter there's no way to choose a delay)

    1. Aug 14, 2008

      Mark Michaelis says:

      Hi Amina, I must admit I was surprised myself that this is not mentioned on the...

      Hi Amina,

      I must admit I was surprised myself that this is not mentioned on the Jelly Escalation page. It's in the administration section of JIRA where you can adjust this:

      1. Administration
      2. System >> Services
      3. Add a service:
        1. Name My Escalation Task
        2. Built-in Services: Run Jelly script
        3. Delay: in minutes
        4. Press Add Service button
        5. Input File: The Jelly script to run. Must be located on the server.
        6. Output File: Can be empty.
        7. Delay: Hm, can be entered/altered here again.
        8. Press Update
  5. Aug 18, 2008

    amina says:

    Thank you Mark, for your answer but I'll give an example to explain my problem: ...

    Thank you Mark, for your answer but I'll give an example to explain my problem:

    I have some issues waiting for the customer validation, if these issues are inactive for 8 days I want to change there statut into closed

    All the issues are not created or modified at the same date so a service wich will turn every 8 days would change all the "waiting validation" statuts even the issues resolved since the day before...

    So what I need is to have a filter that takes all the issues with "waiting validation" statut 8 days before

    The service can turn every day

    Perhaps what you explained to me Mark is what I should do but ???

  6. Aug 21, 2008

    amina says:

    I have a problem with my script below. I have this error in the outputFile: nul...

    I have a problem with my script below. I have this error in the outputFile:

    null:-1:-1: <null> Could not parse Jelly script

    1. Oct 16, 2008

      Quimicefa says:

      I've found the same error as amina, when in the Jelly Script there are tilde, an...

      I've found the same error as amina, when in the Jelly Script there are tilde, and other extrange characters.

  7. Jan 11

    Anonymous says:

    can you post an example of how to use core:if tag. i can't find any useful examp...

    can you post an example of how to use core:if tag. i can't find any useful examples. how to compare two variables, for example.t

  8. Apr 22

    Alexander E. Shevchenko says:

    A simple jelly script for updating custom field on issues. I create custom filed...

    A simple jelly script for updating custom field on issues. I create custom filed Rating of type Number Field. This script increment Rating(id=10133) on all issues from filterid=11711

    <JiraJelly xmlns:jira="jelly:com.atlassian.jira.jelly.JiraTagLib" xmlns:core="jelly:core" xmlns:log="jelly:log" >
    
        <!-- Run the SearchRequestFilter -->
        <jira:RunSearchRequest filterid="11711" var="issues" />
    
        <!-- Iterate over the issues -->
        <core:forEach var="issue" items="${issues}">
                    <!-- Grab an instance of ComponentManager -->
                    <core:invokeStatic className="com.atlassian.jira.ComponentManager" method="getInstance" var="componentManager"/>
    
    		<!-- Get the IssueManager from ComponentManager -->
                    <core:invoke on="${componentManager}" method="getIssueManager" var="issueManager" />
    
    		<!-- Get the MutableIssue from IssueManager -->
                    <core:invoke on="${issueManager}" method="getIssueObject" var="issue">
                        <core:arg type="java.lang.String" value="${issue.key}"/>
                    </core:invoke>
    
    		<!-- Get Custom FieldManager from ComponentManager -->
                    <core:invoke on="${componentManager}" method="getCustomFieldManager" var="customFieldManager" />
    
    		<!-- Get Custom FieldObject: customFieldObj -->
    		<core:invoke on="${customFieldManager}" method="getCustomFieldObjectByName" var="customFieldObj">
                        <core:arg type="java.lang.String" value="Rating"/>
            	</core:invoke>
            	<!-- Get Custom Field Value: rating -->
    		<core:invoke on="${customFieldObj}" method="getValue" var="rating">
                        <core:arg type="com.atlassian.jira.issue.IssueImpl" value="${issue}"/>
             	</core:invoke>
    
    		<!-- Get auxiliary variable -->
    
    		<core:new var="Hidden" className="java.lang.Boolean">
    			<core:arg type="java.lang.String" value="false"/>
    		</core:new>
    
    		<core:new var="Required" className="java.lang.Boolean">
    			<core:arg type="java.lang.String" value="false"/>
    		</core:new>
    
    		<core:new var="changeHolder" className="com.atlassian.jira.issue.util.DefaultIssueChangeHolder"/>
    
    		<core:new var="fieldManager" className="com.atlassian.jira.issue.fields.DefaultFieldManager"/>
    
    		<core:invoke on="${fieldManager}" method="getOrderableField" var="orderableField">
    			<core:arg type="java.lang.String" value="10133"/>
    		</core:invoke>
    
    		<core:new var="fieldLayoutItem" className="com.atlassian.jira.issue.fields.layout.field.FieldLayoutItemImpl">
    				<core:arg type="com.atlassian.jira.issue.fields.CustomFieldImpl" value="${orderableField}"/>
    				<core:arg type="java.lang.String" value="Description" />
    				<core:arg type="java.lang.Boolean" value="${Hidden}" />
    				<core:arg type="java.lang.Boolean" value="${Required}" />
    		</core:new>
    
    		<core:invoke on="${customFieldObj}" method="getValue" var="rating">
                        <core:arg type="com.atlassian.jira.issue.IssueImpl" value="${issue}"/>
             	</core:invoke>
    
    		<core:new var="modifiedValue" className="com.atlassian.jira.issue.ModifiedValue">
    				<core:arg type="java.lang.Double" value="${rating}"/>
    				<core:arg type="java.lang.Double" value="${rating + 1}" />
    		</core:new>
    
    		<!-- Updating Custom Field -->
    		<core:invoke on="${customFieldObj}" method="updateValue" var="rating">
                        <core:arg type="com.atlassian.jira.issue.fields.layout.field.FieldLayoutItemImpl" value="${fieldLayoutItem}"/>
    		    <core:arg type="com.atlassian.jira.issue.IssueImpl" value="${issue}"/>
                        <core:arg type="com.atlassian.jira.issue.ModifiedValue" value="${modifiedValue}"/>
    		    <core:arg type="com.atlassian.jira.issue.util.DefaultIssueChangeHolder" value="${changeHolder}"/>
             	</core:invoke>
        </core:forEach>
    </JiraJelly>
    
    

Add Comment


Except where otherwise noted, content in this space is licensed under a Creative Commons Attribution 2.5 Australia License.