How to create *Date* type ScriptRunner Script Field in Jira

This post describes how one can create a calculated Script Field of type Date based on existing Jira custom field of type Date / Date Time.

Tested on Jira Server, Data Center. You will need awesome ScriptRunner App to start with.

Why one need Calculated Field?

I’m glad you asked! Here is use case that I was tasked to solve. Our users fill Proposed Purchase Date as part of new Jira ticket creation process. Over the lifetime of this Jira ticket, this field is updated as we get more up-to-date information. But recently our Business Team came back saying they would like to know very first value that was set for this field for a given Jira Ticket. Since this value is already recorded into Change History for field Proposed Purchase Date, I wanted to find out how can I retrieve this value and present it every time Ticket is viewed. And this is where ScriptRunner comes into picture. ScriptRunner provides ability to create *calculated fields* based on available data within in Jira.

But very soon I found out that creation of this field is not easy as it sounds also there was not much documentation available either. So by joining forces with Atlassian Community finally I was able to successfully create calculated field which we can call as First Proposed Purchase Date to display initial value of Proposed Purchase Date.

Steps for creation of Script Field of type Date

  • Create a regular customer field of type Script Field
    • Navigate to Administration >> Issues >> Custom Fields >> Add Custom Fields
    • On Select a Field Type screen, select Scripted Field
    • After completion of the new custom field, go to Edit Custom Field Details screen for this new field.
      • Make sure you set Search Template as a Date Time Range Picker
      • Also as a good practice, limit the application context of this field to specific project that you are interested in.
    • Edit this Custom field to set Date Time Range picker as a Search Template
  • ScriptRunner logic setup for this Script Field
    • Go to Manage Apps >> Script Fields >> Script Fields section
    • You should see field First Proposed Purchase Date which we created as part of our first step. Click on Gear Icon >> Edit
    • Select Date Time as a template
    • And in script section enter following code
import com.atlassian.jira.component.ComponentAccessor
import java.text.SimpleDateFormat
import org.apache.log4j.Logger
import org.apache.log4j.Level
import java.util.Date

def log = Logger.getLogger("jira.script_field.first_proposed_purchase_date")
log.setLevel(Level.DEBUG);
log.debug("Inside 'First Proposed Purchase Date' Script Field Calculation, Issue Key - "+ issue.key);

def proposed_purchase_date_changes = ComponentAccessor.getChangeHistoryManager().getChangeItemsForField(issue, "Proposed Purchase Date")

//Make sure last_deployed_date has been set at least once. Else this Scripted field should return nothing!
if (proposed_purchase_date_changes && proposed_purchase_date_changes.size() > 0){
    def formatter = new SimpleDateFormat("yyyy-MM-dd")
	formatter.setTimeZone(TimeZone.getTimeZone("PST"));

    def first_change_in_proposed_purchase_date = proposed_purchase_date_changes.first()
    def from_date = first_change_in_proposed_purchase_date?.from;
    def to_date = first_change_in_proposed_purchase_date?.to;
    
    Date first_proposed_purchase_date = null;
    //If "Proposed Purchase Date" has been set during issue creation then we should use "From Date" from change History
    //Else "To Date" should be used from Change History.
    if (from_date){
    	first_proposed_purchase_date = formatter.parse(from_date)
    }
    else{
        first_proposed_purchase_date = formatter.parse(to_date)
    }

    return first_proposed_purchase_date;
}

More about Groovy Code

Code listed above is one that working successfully and helped me to resolved following bugs during testing.

  1. Calculated Field was not displayed if source field was set during Ticket Creation process itself!
    • If Proposed Purchase Date was set as part of Ticket creation process, then Jira doesn’t produce ChangeHistory for it. And hence in such cases First Proposed Purchase Date was not displayed though it should be.
    • Fix was make sure we retrieve 1st change from ChangeHistory and check if From is available or not. If yes, use this value!
  2. Calculated field was not displaying correct value for some Tickets.
    • This was due to first fix! In situations where field has been updated as part of Ticket Editing, first change is captured in *To* value.
    • So correct logic should be – In 1st change, we should always verify if *From* is available or not. If available, use that value else use *To* value
  3. Calculated field was showing incorrect value (one day offset) for some Tickets.
    • This was a tricky one. And after few tries I realized problem arising because our Jira Server time is based on UTC and hence Date Object is created it was in UTC object. Later Jira converts it into user selected time zone and that was reason it was getting it wrong sometimes!
    • To get around this problem, I’ve to set the timezone on DateFormatter to PST/PDT (our user base is primarily here in West Coast – I still think there should be better way to get this done.) And then we have a date as user set it for first time!
  4. There was also one weird problem that I faced was if we haven’t set Search Template to *Date Time Range picker*, Jira couldn’t able to re-index this field and it was not allowing creation of any new tickets across Jira. So please be careful and do this!

Want to say big thank you to Dev & Prasad for helping me to create this field successfully.

OAuth with Jira

Jira provides rich set of REST APIs for user interaction through automation. One can authenticate with these REST APIs in three different ways: 1) Using Basic Auth 2) Cookie based Auth and 3) Using OAuth Token

It’s recommended one should use last two options specially with OAuth Token. In this tutorial we will learn how to generate OAuth token that you can use within your code.

Pr-requisite:
* Availability of OpenSSL command line
* Python 3
* Get Jira OAuth Generator library from Github

Steps

  • Clone Jira OAuth Generator library from GitHub
  • Python 3 Setup
    • Create Python Virtual Environment
      • mkvirtualenv -p python3 jira_oauth1_py3_env
    • Activate this environment to work on
      • workon jira_oauth1_py3_en
    • Install all required libraries
      • pip install -r requirements.txt
  • Generate RSA public and private keys
    openssl genrsa -out oauth.pem 1024
    openssl rsa -in oauth.pem -pubout -out oauth.pub
  • Performing OAuth Dance
    • Through Web browser login to Jira as a user for which you want to generate OAuth token.
    • From command line, run python script
      python jira_oauth_token_generator.py config/starter_oauth.config
    • Copy and paste link in browser as suggested. You will be asked to *Authorize / Decline* Upon authorization, you will get final access token information.
      • This oauth_token and oauth_token_secret data points you will need later to authenticate yourself while using OAuth with Jira.

How to use OAuth to access Jira

Couple of ways you can Access using Python.

1. Using Python Jira library (recommended):
Take a look at access_using_jira_library.py to find out how you can use OAuth with this library.
(jira_oauth1_py3_env) ➜ jira-oauth-generator git:(master) ✗ python access_using_jira_library.py config/final_oauth_token.config

Retrieving Issue: EXJIRA-123
Issue: EXJIRA-123,  Summary: Deploy new JIRA Version

Retrieving 1st 3 Jira Projects available to you
First 3 Projects are [‘ABC’, ‘EDF’, ‘EXJIRA’]

2. Using bare bones Jira REST API along with Requests Library:
Take a look at access_using_requests_package.py to find out how you can use OAuth to access Jira with out box REST APIs.
(jira_oauth1_py3_env) ➜ jira-oauth-generator git:(master) ✗ python access_using_requests_package.py config/final_oauth_token.config

Retrieving 1st Jira Project available to you
(ABC) American Born Car

Adding comment to issue ABC-123
Comment successfully added. Please verify through browser!