This plugin collects Jira data through Jira Cloud REST API. It then computes and visualizes various engineering metrics from the Jira data.
| Metric Name | Description |
|---|---|
| Requirement Count | Number of issues with type “Requirement” |
| Requirement Lead Time | Lead time of issues with type “Requirement” |
| Requirement Delivery Rate | Ratio of delivered requirements to all requirements |
| Requirement Granularity | Number of story points associated with an issue |
| Bug Count | Number of issues with type “Bug” bugs are found during testing |
| Bug Age | Lead time of issues with type “Bug” both new and deleted lines count |
| Bugs Count per 1k Lines of Code | Amount of bugs per 1000 lines of code |
| Incident Count | Number of issues with type “Incident” incidents are found when running in production |
| Incident Age | Lead time of issues with type “Incident” |
| Incident Count per 1k Lines of Code | Amount of incidents per 1000 lines of code |
Configuring Jira via config-ui.
To collect data, select Advanced Mode on the Create Pipeline Run page and paste a JSON config like the following:
Warning: Data collection only supports single-task execution, and the results of concurrent multi-task execution may not meet expectations.
[
[
{
"plugin": "jira",
"options": {
"connectionId": 1,
"boardId": 8,
"since": "2006-01-02T15:04:05Z"
}
}
]
]
connectionId: The ID field from JIRA Integration page.boardId: JIRA board id, see “Find Board Id” for details.since: optional, download data since a specified date only.[ { "ID": 14, "CreatedAt": "2021-10-11T11:49:19.029Z", "UpdatedAt": "2021-10-11T11:49:19.029Z", "name": "test-jira-connection", "endpoint": "https://merico.atlassian.net/rest", "basicAuthEncoded": "basicAuth", "epicKeyField": "epicKeyField", "storyPointField": "storyPointField" } ]
{ "name": "jira data connection name", "endpoint": "jira api endpoint, i.e. https://merico.atlassian.net/rest", "basicAuthEncoded": "generated by `echo -n {jira login email}:{jira token} | base64`", "epicKeyField": "name of customfield of epic key", "storyPointField": "name of customfield of story point", "typeMappings": { // optional, send empty object to delete all typeMappings of the data connection "userType": { "standardType": "devlake standard type" } } }
{ "name": "jira data connection name", "endpoint": "jira api endpoint, i.e. https://merico.atlassian.net/rest", "basicAuthEncoded": "generated by `echo -n {jira login email}:{jira token} | base64`", "epicKeyField": "name of customfield of epic key", "storyPointField": "name of customfield of story point", "typeMappings": { // optional, send empty object to delete all typeMappings of the data connection "userType": { "standardType": "devlake standard type", } } }
{ "name": "jira data connection name", "endpoint": "jira api endpoint, i.e. https://merico.atlassian.net/rest", "basicAuthEncoded": "generated by `echo -n {jira login email}:{jira token} | base64`", "epicKeyField": "name of customfield of epic key", "storyPointField": "name of customfield of story point", "typeMappings": { // optional, send empty object to delete all typeMappings of the data connection "userType": { "standardType": "devlake standard type", } } }
{ "settings": { "connections": [{ "scope": [{ "transformation": { "epicKeyField": "", "storyPointField": "", "remotelinkCommitShaPattern": "", "typeMappings": { "<USER_TYPE_1>": { "standardType": "<STD_TYPE_1>", "statusMappings": { "<USER_STATUS_a_from_USER_TYPE_1>": { "standardStatus": "<STD_STATUS_1>" }, "<USER_STATUS_a_from_USER_TYPE_2>": { "standardStatus": "<STD_STATUS_2>" } } } } } }] }] } }
{ "name": "jira-test", "mode": "NORMAL", "plan": [ [ { "plugin": "jira", "subtasks": [ "collectStatus", "extractStatus", "collectProjects", "extractProjects", "collectBoard", "extractBoard", "collectIssueTypes", "extractIssueType", "collectIssues", "extractIssues", "collectIssueChangelogs", "extractIssueChangelogs", "collectAccounts", "collectWorklogs", "extractWorklogs", "collectRemotelinks", "extractRemotelinks", "collectSprints", "extractSprints", "convertBoard", "convertIssues", "convertWorklogs", "convertIssueChangelogs", "convertSprints", "convertSprintIssues", "convertIssueCommits", "extractAccounts", "convertAccounts", "collectEpics", "extractEpics" ] } ] ], "enable": true, "cronConfig": "0 0 * * *", "isManual": true, "settings": { "connections": [{ "connectionId": 1, "plugin": "jira", "scope": [{ "entities": [ "TICKET", "CROSS" ], "options": { "boardId": 1 }, "transformation": { "epicKeyField": "", "storyPointField": "", "remotelinkCommitShaPattern": "", "typeMappings": { "Task1": { "standardType": "Task1", "statusMappings": { "done": { "standardStatus": "hello world" }, "new": { "standardStatus": "nice to meet you" } } }, "Task2": { "standardType": "Task2", "statusMappings": { "done": { "standardStatus": "hello world" }, "new": { "standardStatus": "nice to meet you too" } } } } } }] }], "version": "1.0.0" }, "id": 1, "createdAt": "2022-08-30T11:25:10.699Z", "updatedAt": "2022-08-30T11:28:22.891Z" }
http://your_devlake_host/plugins/jira/connections/1/proxy/rest/agile/1.0/board/8/sprint would be forwarded to https://your_jira_host/rest/agile/1.0/board/8/sprint{ "maxResults": 1, "startAt": 0, "isLast": false, "values": [ { "id": 7, "self": "https://merico.atlassian.net/rest/agile/1.0/sprint/7", "state": "closed", "name": "EE Sprint 7", "startDate": "2020-06-12T00:38:51.882Z", "endDate": "2020-06-26T00:38:00.000Z", "completeDate": "2020-06-22T05:59:58.980Z", "originBoardId": 8, "goal": "" } ] }