| --- |
| title: "Jira" |
| description: > |
| Jira Plugin |
| --- |
| |
| |
| ## Summary |
| |
| This plugin collects Jira data through Jira Cloud REST API. It then computes and visualizes various engineering metrics from the Jira data. |
| |
| <img width="2035" alt="jira metric display" src="https://user-images.githubusercontent.com/2908155/132926143-7a31d37f-22e1-487d-92a3-cf62e402e5a8.png" /> |
| |
| ## Project Metrics This Covers |
| |
| | 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"<br/><i>bugs are found during testing</i> | |
| | Bug Age | Lead time of issues with type "Bug"<br/><i>both new and deleted lines count</i> | |
| | Bugs Count per 1k Lines of Code | Amount of bugs per 1000 lines of code | |
| | Incident Count | Number of issues with type "Incident"<br/><i>incidents are found when running in production</i> | |
| | Incident Age | Lead time of issues with type "Incident" | |
| | Incident Count per 1k Lines of Code | Amount of incidents per 1000 lines of code | |
| |
| ## Configuration |
| Configuring Jira via [config-ui](/UserManuals/ConfigUI/Jira.md). |
| |
| ## Collect Data From JIRA |
| |
| To collect data, select `Advanced Mode` on the `Create Pipeline Run` page and paste a JSON config like the following: |
| |
| > <font color="#ED6A45">Warning: Data collection only supports single-task execution, and the results of concurrent multi-task execution may not meet expectations.</font> |
| |
| ``` |
| [ |
| [ |
| { |
| "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. |
| |
| |
| ## API |
| |
| ### Data Connections |
| |
| 1. Get all data connection |
| |
| ```GET /plugins/jira/connections |
| [ |
| { |
| "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" |
| } |
| ] |
| ``` |
| |
| 2. Create a new data connection |
| |
| ```POST /plugins/jira/connections |
| { |
| "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" |
| } |
| } |
| } |
| ``` |
| |
| |
| 3. Update data connection |
| |
| ```PUT /plugins/jira/connections/:connectionId |
| { |
| "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", |
| } |
| } |
| } |
| ``` |
| |
| 4. Get data connection detail |
| ```GET /plugins/jira/connections/:connectionId |
| { |
| "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", |
| } |
| } |
| } |
| ``` |
| |
| 5. Delete data connection |
| |
| ```DELETE /plugins/jira/connections/:connectionId |
| ``` |
| |
| |
| ### Type mappings setting |
| |
| 1. mappings struct |
| |
| ```json /blueprints/{blueprintId} |
| { |
| "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>" } |
| } |
| } |
| } |
| } |
| }] |
| }] |
| } |
| } |
| ``` |
| |
| 2. set mappings example: |
| |
| ```json PATCH /blueprints/{blueprintId} |
| { |
| "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" |
| } |
| ``` |
| |
| 3. API forwarding |
| For example: |
| Requests to `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` |
| |
| ```GET /plugins/jira/connections/:connectionId/proxy/rest/*path |
| { |
| "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": "" |
| } |
| ] |
| } |
| ``` |