Managing JIRA Scrum Sprints using API. Atlassian Jira is a great tool for organizing Agile processes, especially Scrum. But managing Scrum Sprints manually using Jira web GUI maybe time consuming and annoying. So, I decided to automate some routine operations using JIRA API and Python.
The API calls are described on the official page at JIRA Agile REST API Reference.
I will use my domain account for authentication. First of all let’s see how to get Jira Scrum Board ID by it’s name and get all the Sprints related to the Board.
name = "CyberSecurity"
response = requests.get('https://jira.corporation.com/rest/agile/1.0/board?name=' + name, auth=(user, password))
print(response.text)
board_id = json.loads(response.text)['id']
Output:
{"maxResults":50,"startAt":0,"isLast":true,"values":[{"id":2334,"self":"https://jira.corporation.com/rest/agile/1.0/board/2334","name":"CyberSecurity","type":"scrum"}]}
Getting all the Sprints
Not bad, now we can list all sprints for this Scrum Board:
response = requests.get('https://jira.corporation.com/rest/agile/1.0/board/' + str(board_id)
+ '/sprint', auth=(user, password))
print json.dumps(json.loads(response.text), indent=2, sort_keys=True)
Output:
{
"isLast": true,
"maxResults": 50,
"startAt": 0,
"values": [
...
{
"endDate": "2018-12-29T12:41:00.000+03:00",
"goal": "",
"id": 9879,
"name": "24.12.2018-31.12.2018",
"originBoardId": 1886,
"self": "https://jira.corporation.com/rest/agile/1.0/sprint/9879",
"startDate": "2018-12-24T12:41:44.662+03:00",
"state": "active"
}
]
}
If you have more than 50 Sprints, it will be necessary to make several request and increase startAt until isLast is true.
Creating a new sprint
Now we can create a new Sprint. We have to set name of the Sprint, time when it starts and ends, and the board_id we received earlier.
headers = {
'Content-Type': 'application/json',
}
data = {
'name': '14.01.2019-21.01.2019',
'startDate': '2019-01-14T10:00:00.000+10:00',
'endDate': '2019-01-21T10:00:00.000+10:00',
'originBoardId': board_id
}
response = requests.post('https://jira.corporation.com/rest/agile/1.0/sprint', headers=headers,
data=json.dumps(data), auth=(user, password))
print(response.text)
Output:
{"id":10233,"self":"https://jira.corporation.com/rest/agile/1.0/sprint/10233","state":"future","name":"14.01.2019-21.01.2019","startDate":"2019-01-14T03:00:00.000+03:00","endDate":"2019-01-21T03:00:00.000+03:00","originBoardId":1886}
Starting and closing the sprint
Now let’s start this sprint. In fact it is no more than changing the state parameter:
headers = {
'Content-Type': 'application/json',
}
data = {
'state': 'active'
}
sprint_id = "10233"
response = requests.post('https://jira.corporation.com/rest/agile/1.0/sprint/' + str(sprint_id), headers=headers,
data=json.dumps(data), auth=(user, password))
print(response.text)
Output:
{"id":10233,"self":"https://jira.corporation.com/rest/agile/1.0/sprint/10233","state":"active","name":"14.01.2019-21.01.2019","startDate":"2019-01-14T03:00:00.000+03:00","endDate":"2019-01-21T03:00:00.000+03:00","originBoardId":1886}
Closing the sprint is the same, but the state should be set to ‘closed’.
Moving Issues between the Sprints
Ok, now let’s figure out what Issues we have in the Sprint:
response = requests.get('https://jira.corporation.com/rest/agile/1.0/sprint/' + str(sprint_id)+ '/issue', auth=(user, password))
print(response.text)
It will return a pretty complex structure. However, it is easily parsable and you can iterate and choose IDs you need like this:
issues = set()
for issue in json.loads(response.text):
assignee = ""
if 'assignee' in issue['fields']:
if issue['fields']['assignee']:
assignee = issue['fields']['assignee']['name']
if assignee == "j.smith" and "CyberSecurity" in issue['fields']['labels']:
issues.add(issue['key'])
And then move them to another sprint:
new_sprint_id = "9879"
data = {
'issues': list(issues)
}
response = requests.post('https://jira.corporation.com//rest/agile/1.0/sprint/' + str(new_sprint_id)+ '/issue',
headers=headers, data=json.dumps(data), auth=(user, password))
If everything is ok, the output will be empty and the STATUS of the request will be 204.
Using these calls, I was able to close old Sprints, create new ones and move active Issues from old sprints to new ones. Read more about Jira automation in my posts “Automated task processing with JIRA API” and “Atlassian Jira, Python and automated labeling“
Hi! My name is Alexander and I am a Vulnerability Management specialist. You can read more about me here. Currently, the best way to follow me is my Telegram channel @avleonovcom. I update it more often than this site. If you haven’t used Telegram yet, give it a try. It’s great. You can discuss my posts or ask questions at @avleonovchat.
А всех русскоязычных я приглашаю в ещё один телеграмм канал @avleonovrus, первым делом теперь пишу туда.
Thanks a lot. It was very helpful. I have one query – how can we find the sprint-ID programmatically by sprint-name?
https://jira.atlassian.com/browse/JSWSERVER-15503 is a problem for maxResults and startAt