If you work in an IT company, then most likely your processes are built around the well-known Atlassian product - Jira. There are many task trackers on the market for solving the same problems, including open-source solutions (Trac, Redmine, Bugzilla), but perhaps it is Jira that is most widely used today.
My name is Dmitry Semenikhin, I am a Timlid in the company of Badoo. In a small series of articles, I will tell you exactly how we use Jira, how we set it up for our processes, what was “screwed” on top and how we turned the issue-tracker into a single communication center for the task and simplified our lives. In this article, you will see our flow from the inside, learn how you can “twist” your Jira, and read about the additional features of the tool that you might not have known.
The article focuses primarily on those who are already using Jira, but may be experiencing difficulties with the integration of its standard capabilities into existing processes in the company. Also, the article may be useful for companies that use other task trackers, but are faced with some limitations and are thinking about changing the solution. The article is not built on the principle of "problem - solution", in it I describe the existing tools and features built by us around Jira, as well as the technologies that we used to implement them.
Additional features Jira
To make the subsequent text more understandable, let's look at what tools Jira provides to us for implementing non-standard requests - those that go beyond the standard Jira functionality.
')
REST API
In general, an API command call is an HTTP request to an API URL specifying the method (GET, PUT, POST and DELETE), the command and the request body. The request body as well as the API response are in JSON format. An example request that returns a JSON representation of the ticket:
GET /rest/api/latest/issue/{ticket_number}
Using the API, you can, using scripts in any programming language:
- create tickets;
- modify any ticket properties (built-in and custom);
- write comments;
- using JQL (built-in query language) to receive any ticket lists;
- and much more.
Detailed API documentation is provided
here .
We wrote our own high-level Jira API client in PHP that implements all the commands we need. Here is an example of commands for working with comments:
public function addComment($issue_key, $comment) { return $this->_post("issue/{$issue_key}/comment", ['body' => $comment]); } public function updateComment($issue_key, $comment_id, $new_text) { return $this->_put("issue/{$issue_key}/comment/{$comment_id}", ['body' => $new_text]); } public function deleteComment($issue_key, $comment_id) { return $this->_delete("issue/{$issue_key}/comment/{$comment_id}"); }
Webhooks
Using the webhook, you can customize the call to an external callback function on your host for various events in Jira. At the same time, you can configure as many such rules as you like so that different URLs will be “twitched” for different events and for tickets that correspond to the filter specified in the webhook. The webhooks configuration interface is available to the Jira administrator.
As a result, you can create rules like this:
Name : “SRV - New Feature created / updated”
URL :
www.myremoteapp.com/webhookreceiverScope : Project = SRV AND type in ('New Feature')
Events : Issue Updated, Issue Created
In this example, the specified URL will be called for the events of creating and changing tickets corresponding to the
Scope filter. In this case, the body of the request will contain all the necessary information about what exactly has changed and what event has occurred.
It is important to understand that Jira does not guarantee that your event will be delivered. If the external URL did not answer or answered with an error, it will not be seen anywhere (except for logs, perhaps). Therefore, the webhook event handler should be as reliable as possible. For example, events can be put in a queue and try to process until it is successful. This will help solve problems with temporarily unavailable services, for example, any external database necessary for proper event handling.
Detailed webhooks documentation is provided
here .
ScriptRunner
This is a plugin for Jira, a very powerful tool that allows you to customize a lot in Jira (including it can replace webhooks). To use this plugin requires knowledge of Groovy. The main advantage of the tool for us is that you can embed custom logic online in the flow. The code of your script will be executed immediately in the Jira environment in response to a specific action. For example, you can make your button in the ticket interface, clicking on which will create tickets associated with the current task or run unit tests for this task. And if something goes wrong, you, as a user, will immediately find out about it.
Those interested can read the
documentation .
Flow: what is hidden under the hood
And now how we apply additional features of Jira in our projects. Consider this in the context of passing our typical flow ticket from creation to closing. At the same time about the flow itself will tell.
Open / backlog
So, first the ticket gets into the backlog of new tickets with the
Open status. Then the component lead, after seeing the new ticket on its dashboard, decides whether to assign a ticket to the developer right now or send it to the backlog of known tickets (
Backlog status) to assign it later when a free developer appears and higher priority tickets are closed. This may seem strange, since it seems logical to do the opposite: create tickets in the
Backlog status, and then transfer them to the Open status. But this scheme has taken root in our country. It allows you to easily configure filters to reduce the time taken to decide on new tickets. An example of a JQL filter that shows new tasks for a lead:
Project = SRV AND assignee is EMPTY AND status in (Open)
In progress
Technical nuances of working with GitIt should be noted that our work on each task is carried out in a separate Git-branch. As for this, we have an agreement that the name of the branch at the beginning must contain the ticket number. For example,
SRV-123_new_super_feature . Also, comments to each commit in a branch must contain a ticket number in the format [SRV-123]: {comment}. We need such a format, for example, to correctly remove a “bad” task from a build. How this is done is described in detail in the
article .
These requirements are controlled by git-hooks. For example, here is the contents of prepare-commit-msg, which prepares a comment for the commit by getting the ticket number from the name of the current branch:
If a commit with a “wrong” comment is attempted to be launched, such a push will be rejected. Also, an attempt to push a branch without a ticket number at the beginning will be rejected.
When the ticket gets on the developer, first of all it is decomposed. The result of the decomposition is the developer's idea of ​​how to solve the problem and how long the solution will take. After all the main details have been clarified, the ticket is transferred to the
In Progress status, and the developer starts writing code.
We have decided to set the due date task at the moment when it is transferred to the In Progress status. If the developer did not do this, he will receive a reminder in the corporate HipChat messenger. Special script every two hours:
- selects tickets in the status of progress with the empty field due date ( project = SRV AND status = 'In Progress' AND duedate is EMPTY ) using the REST API Jira;
- selects incomplete tickets with due date older than the current date ( project = SRV AND status = 'In Progress' AND duedate not EMPTY AND duedate <now () );
- for each ticket, learns the developer by reading the corresponding field in the ticket, as well as the lead of the developer;
- groups tickets by developers and leads and sends reminders to HipChat using its API.
Having made all the necessary commits, the developer pushes the thread into a common turnip. In this case, Git-hook post-receive is triggered, which makes a lot of interesting things:
- the name of the git branch, as well as comments to commits are checked for compliance with our rules;
- it is checked that the ticket with which the branch is associated is not closed (it is impossible to push a new code into closed tickets);
- checked syntax of modified PHP files (PHP -l file_name.php );
- formatting is checked;
- if the ticket into which the branch is pushing is in the Open status, then it is automatically transferred to the In Progress status;
- the ticket is attached to the branch, the corresponding entry is made in the custom field of the Commits ticket using the Jira API. It looks like this:
(
branchdiff is a link to a branch with a head from which the current branch originated, in our tool review of the
Codeisok code);
- A comment is created in the ticket with all commits in this push.
(Aida is the conditional name of our automation complex for working with Jira, Git and not only. It is from this name that automatic comments appear on the ticket. We wrote more about Aida in the article ).
Clicking on the commit hash opens the diff from the previous revision of the branch (how it looks about, show below);
- It checks whether there are any files in the branch for which translation into supported languages ​​(for example, web page templates) may be required, and if there are any, then the custom field Lexems is set to New \ Changed. This ensures that the ticket does not leave for production without complete translation;
- The name of the employee who is pushing the branch is added to the list of developers (custom field of the Developers ticket).
On review
Having written the code and independently making sure that all the requirements for the task are met, and the tests are not broken, the developer assigns a ticket to the reviewer (
On Review status). Usually the developer himself decides who will review his ticket. Most likely, it will be another developer who perfectly understands the necessary part of the code. The review is performed using the
Codeisok tool, which opens immediately with the necessary diff by clicking on the link
branchdiff in the field of the
Commits ticket or on the link in the form of a hash of the commit in the comments.
The reviewer sees something like this:
Having completed the review, the reviewer clicks the
Finish button, and, among other things, at this moment the following occurs:
- using the JIra API, a comment is created in the ticket with the comments of the reviewer in the context of the code. It looks like this:

- if there were remarks to the code and the reviewer decided to re-open the ticket, then the developer will receive a notification about this in HipChat (this is done using the webhook rule that triggers the re-discovery);
- The Reviewers ticket field is filled.
Resolved
Further, if the review was successful, the ticket is sent to the backlog of QA-engineers in the
Resolved status. But along with this, using the webhook on the resolved event in the background, automatic tests are run on the code of the branch. After a few minutes, a new comment will appear in the ticket, which will report on the test results.

Also, at any time, you can manually initiate a rerun of tests by clicking the special button Run unit tests in the ticket menu. After a successful run, a new comment will appear in the ticket, similar to the previous one.
In fact, this button is one of the additional task statuses in the Jira workflow, translation into which triggers the triggering of the Groovy script for the ScriptRunner plugin. The script calls the external URL that initiates the test run, and if the URL responds successfully, the ticket returns to its previous status (in our case,
Resolved ).
In Shot / In Shot - OK
The task is first tested in a devel environment. If everything is good, a shot is created (for example, by clicking on the
Create shot link in the
Commits field) - a directory on a dedicated server into which changes from the ticket copied with the current master are copied. The server works with production data: the bases and services are the same as those that serve real users. Thus, the tester can open a web site or connect to a shot using a mobile client and “isolate” check the feature in the production environment. “Isolated” means that no other code / functionality other than the new one from the branch and the current master is executed. Therefore, this stage of testing is perhaps the main one, since it allows the QA-engineer to most reliably find the problem directly in the test task.
Access to the resources of the shot is carried out by special URLs that are generated in the script for creating a shot and are placed in the ticket header using the Jira API. As a result, we see links to the site, admin panel, logs, and other tools that are executed in a shot environment:

Also at the moment of generating the shots, a script is launched that analyzes the contents of the modified files and creates requests for the translation of the found new lexemes. After the translation is completed, the value of the
Lexems field changes to Done and the ticket can be added to the build.
If the test was successful, then the ticket is transferred to the status
In Shot - OK.In Build / In Build - OK
We post the code twice a day - in the morning and in the evening. To do this, create a special build-branch, which will eventually be merged with the master and laid out "into battle".
At the time of building a build branch, a special script receives a list of tickets in the status
In Shot - OK using a JQL request and tries to lock them into the build branch when all of the following conditions are met:
- the transfer for the ticket has been completed or nothing needs to be translated ( Lexems in ('No', 'Done') );
- the developer is present at the workplace (the automatic merge system checks on the internal database if the developer is not on vacation or on sick leave, and if so, the ticket can be frozen only manually by release engineers or another responsible developer, which is specified in the special field of Developer ; the lead of the absent developer in this case receives a notification that the ticket cannot be automatically added to the build);
- the ticket does not have the Up in Build checkbox set to the value of by Developer (this is a special custom field of the ticket, which allows the developer to determine for himself when the ticket gets into the build);
- A ticket branch does not depend on another branch that has not yet entered master or the current build. We do our best to avoid this situation, but sometimes this happens when the developer creates his branch not from the master, but from the branch of another ticket, or when he sticks to someone else's branch. This can be done by accident, so we decided that additional protection would not hurt.
It should be noted that automatic merging may not occur due to a merge conflict. In this case, the ticket is automatically transferred to the
Reopen status and assigned to the developer, about which he immediately receives a notification in HipChat, and a corresponding message is added to the comment of the ticket. After resolving the conflict, the ticket is returned to the build.
If everything is fine and the ticket branch is frozen in the build, the ticket is automatically transferred to the
In Build status, and the name of the build is written in the custom field of the
Build_Name ticket.
Further, using this value, it is easy to get a list of tickets that have been posted with each build. For example, to look for someone to blame if something went wrong.
At the next stage, QA-engineers additionally check whether the task code works correctly in conjunction with other tasks in the build. If all is well, the ticket is manually set to
In Build - OK.On Production / On Production - OK / Closed
Next, the whole test suite (Unit, integration, Selenium-, etc.) is run through the build. If everything is good, the build is installed in the master, and the code is laid out on the production. The ticket is transferred to the
On Production status
.Next, the developer (or customer) makes sure that the feature on the production works correctly, and sets the
On Production - OK status to the ticket
.Two weeks later, tickets in the
On Production - OK status are automatically transferred to the
Closed status, if someone has not done it manually before.
Also worth mentioning are additional statuses in which the ticket can be located:
- Requirements - when it is not possible to promptly receive from the customer the necessary clarifications on the task, and without them further work on the ticket is impossible, the ticket is transferred to this status and is assigned to the person who must give explanations;
- Suspended - if the work on the ticket is suspended, for example, if the developer is blocked by the tasks of an adjacent team or was forced to switch to a more urgent task;
- Reopened - the task can be rediscovered by the developer after the review, after testing, after an unsuccessful attempt to merge the branch with master.
As a result, the simplified scheme of our workflow looks like this:
Ticket - task communication center
As a result of passing through the flow, its cap takes on the form:

What is more interesting here that we have customized for myself and what I have not yet mentioned?
We try to keep the discussion of controversial issues with the task designer in the comments of the ticket, and not to “smear” important clarifications by mail and instant messengers. If the discussion did take place “on the side,” it is highly desirable to copy what was agreed to in the ticket.
In addition to the "human" texts, as I mentioned above, in the commentary a lot of things are written automatically using the API:
- commits;
- review results;
- test run results.
Sometimes automatic comments can interfere, for example, with product managers. Therefore, we made a simple JS script that adds a button to the Jira interface and allows you to minimize all automatic comments, leaving only “human” ones. As a result, folded automatic comments look compact.

JS-code of the script that we have embedded in the ticket template window.addEventListener('load', () => { const $ = window.jQuery; const botsAttrMatch = [ 'aida', 'itops.api' ].map(bot => `[rel="${bot}"]`).join(','); if (!$) { return; } const AIDA_COLLAPSE_KEY = 'aida-collapsed'; const COMMENT_SELECTOR = '.issue-data-block.activity-comment.twixi-block'; const JiraImprovements = { init() { this.addButtons(); this.handleAidaCollapsing(); this.handleCommentExpansion();
What else?
API webhooks Jira :
- HipChat, - ( );
- HipChat ( , );
- ( ) ( ; );
- ; , ;
- In progress ;
- , «» (, On Review), ;
- , Jira (, «d.semenihin (Day off)»). .
Jira — , , . , , . Jira , .
— . Jira , Jira. , - .
Thanks for attention!