Kristian Walker
22 May 2023
How to notify users of inactive issues in Jira using ScriptRunner
How often do you find a Jira issue that's slipped through the cracks? In this blog post, we will demonstrate how to automate a report to flag issues that have been inactive for a specified timeframe.
How often do you find a Jira issue that's slipped through the cracks?
Whether the assignee has been pulled onto an urgent task and simply forgotten about the ticket, or another ticket has taken much longer than anticipated: they can't find the time. Or maybe the issue is a particularly tricky one, and the assignee has sent it on to another department for advice, and that department have asked another department, and that department have asked another department…
To prevent these quasi-abandoned tickets from causing problems, you might run a manual check every so often.
But what happens when you don’t have the time for that? How can you keep an eye on things automatically?
You can save yourself and your team the manual task of searching for stuck or forgotten issues by automating a report to flag any issues that have been inactive for a specified timeframe. In this blog post, we will demonstrate how to:
- Find issues inactive by a specified number of days
- Set up an automated recurring report
How to find inactive issues in Jira Cloud
We recommend using an Escalation Service in ScriptRunner to find inactive issues in Jira Cloud. For those who aren’t familiar with Escalation Services, they automatically perform an action on an issue after a specified timeframe. So for example, if an issue hasn’t been assigned to anyone within 7 days, an Escalation Service can automatically assign a priority status.
Using an Escalation Service, you can use a JQL search to define on which issues you'd like the action to be performed. This action will run automatically, on any schedule you set.
You can configure the Escalation Service to run as often as you like, at a time most convenient for your team's specific requirements. For example, it can run:
- Weekly, at 9am every Tuesday
- Twice a week, at 4pm every Monday and Friday
- Monthly, at 10am on the 4th Wednesday of the month
Escalation Services automatically run the logic specified in your script for every issue returned by the JQL search. To do this manually would require the user to write code first to run the JQL search, and then write more code to manually run the logic for each returned issue. This keeps your business logic simple to understand and easier to maintain.
What JQL Query should I use to find Jira issues that haven’t been updated recently?
To identify any issues that have not been updated in the past five days, and then send a notification to users, we first need to define our JQL query.
JQL Query
1Project in (DEMO) AND issuetype in (Story) AND status in ("In Progress") AND assignee is not empty And updated >-5d
This JQL query specifies which issues to search for. In this example, we want to search in the project "DEMO" for "Story" issue types with a status of "In Progress". From these specified issues, the search will return issues that have not been updated in the past five days due to the clause "updated >-5d".
How do I automate reporting with the Escalation Service?
With our query defined, navigate to the Escalation Services page in ScriptRunner for Jira Cloud to configure the Escalation Service with the following settings:
- In the field "On this schedule" we can set when the Escalation Service will run.
- In the field "For the first 50 results returned by this query" we can enter the JQL query we have already created.
- In the "As this user" box, you can choose to run the script as a specified user or, alternatively, as the ScriptRunner for Jira Cloud add-on user.
Now we can add the script to create our alert message.
NotifyInactiveIssues.groovy
1/*
2* This example escalation service script should be conifgured to run on a schedule such as at 9am every day and should use the JQL query below for the JQL query
3* Project = KWTEST AND issuetype = Story AND status in ("In Progress") AND assignee is not empty And updated >-5d
4* "All right, title and interest in this code snippet shall remain the exclusive intellectual property of Adaptavist Group Ltd and its affiliates. Customers with a valid ScriptRunner
5* license shall be granted a non-exclusive, non-transferable, freely revocable right to use this code snippet only within their own instance of Atlassian products. This licensing notice cannot be removed or
6* amended and must be included in any circumstances where the code snippet is shared by You or a third party."
7*/
8
9// Construct a comment to the inactive issue
10def inActiveIssueComment = """ *****************************
11This issue which is assigned to ${issue.fields.assignee.displayName} has not been updated for the past 5 days. \n
12Can you please add an update on this issue. \n
13***************************** """;
14
15// Construct a slack message saying which issue is inactive
16def inActiveIssueMessage = """ *****************************
17The issue with the key of ${issue.key} which is assigned to ${issue.fields.assignee.displayName} has not been updated for the past 5 days.
18***************************** """;
19
20// Add a comment to each issue mentioning that it needs updating
21post("/rest/api/2/issue/${issue.key}/comment")
22 .header('Content-Type', 'application/json')
23 .body([
24 body: inActiveIssueComment
25 ])
26 .asObject(Map)
27
28// Post a message to slack for each issue mentioning it needs updating
29
30// Construct the meta data needed for the update message
31 Map msg_meta = [channel: 'scriptrunner-jira-cloud-post-to-slack-demo', username: 'Inactive Issue Notifier', icon_emoji: ':clipboard:']
32
33 // Construct the message string to post to slack
34 def slackMessage = inActiveIssueMessage
35
36// Construct the message body
37 Map msg_dets = [text: slackMessage]
38
39// Post the message to slack
40 def supportRotaUpdateMessage = post('https://slack.com/api/chat.postMessage')
41 .header('Content-Type', 'application/json')
42 .header('Authorization', "Bearer ${SLACK_SRCLOUD_TOKEN}")
43 .body(msg_meta + msg_dets)
44 .asObject(Map)
What’s this script doing?
First, the script constructs a message stating that the identified issues need to be updated. By setting the issue key and issue assignee using template variables, these values are dynamically populated in the message string from the issue in lines 9 - 18.
Next, the script calls the add comment REST API as a post request, which posts the created message as a comment on the issue on lines 21 - 26.
The script then makes a call to the external Slack post message API on lines 40 to 44 to post a message to report the inactive issues.
The Slack API call uses the msg_meta Map variable define on line 31. This link specifies the Slack channel you want to post to, the name of the user the message should post from, and the user's associated icon.
On line 42 of the script, we can authenticate the Slack post by defining an authentication header where we pass in our Slack API token. This token is referred to as ${SLACK_SRCLOUD_TOKEN} as we advise storing this on the Script Variables page in ScriptRunner for Jira Cloud: this allows API tokens to be stored as encrypted values that are visible only to Jira Admins, a good best practice to follow for security purposes!
The results
When this script is run, several things happen.
Firstly, a comment is added to any inactive issues. In the example below, the assignee is asked to add an update on the issue.
Then, a message is posted to the specified Slack channel, providing a report of any inactive issues ready for your team to action.
Using this approach, you can quickly identify any issues that may have slipped through the cracks. With prompts both inside and outside of Jira, your team can stay informed and re-assign work where necessary to stay on top of your workload.
Bonus tip
Want to post your list of issues to a Confluence page rather than a Slack channel?