Skip to content
This repository was archived by the owner on Jan 9, 2025. It is now read-only.

Commit 51f3ed7

Browse files
YCK1130donch1989
andauthored
feat: add Jira component (#205)
Because - We need a Jira component to complete some development automation tasks - Related Issue: instill-ai/instill-core#1022 This commit - Support get boards/issue/epic/sprint TODO - [x] TASK_LIST_BOARDS: list all boards in Jira - [x] TASK_LIST_ISSUES: list issues in Jira by various methods - [x] TASK_GET_ISSUE: get an issue by ID or key - Note: This API can get issue/epic with the key since they use the same indexing system. - [x] TASK_GET_SPRINT: get a sprint by ID Next PR - create issue - create epic - create sprint Added by @chuang8511 to visualise Jira's design ![image](https://github.com/user-attachments/assets/17ff0aaf-5ab0-458c-95cd-a147f12e314a) --------- Co-authored-by: Chang, Hui-Tang <[email protected]>
1 parent 810f850 commit 51f3ed7

17 files changed

+3435
-1
lines changed

application/jira/v0/README.mdx

+186
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
---
2+
title: "Jira"
3+
lang: "en-US"
4+
draft: false
5+
description: "Learn about how to set up a VDP Jira component https://github.com/instill-ai/instill-core"
6+
---
7+
8+
The Jira component is an application component that allows users to do anything available on Jira.
9+
It can carry out the following tasks:
10+
11+
- [List Boards](#list-boards)
12+
- [List Issues](#list-issues)
13+
- [List Sprints](#list-sprints)
14+
- [Get Issue](#get-issue)
15+
- [Get Sprint](#get-sprint)
16+
17+
18+
19+
## Release Stage
20+
21+
`Alpha`
22+
23+
24+
25+
## Configuration
26+
27+
The component configuration is defined and maintained [here](https://github.com/instill-ai/component/blob/main/application/jira/v0/config/definition.json).
28+
29+
30+
31+
32+
## Setup
33+
34+
35+
| Field | Field ID | Type | Note |
36+
| :--- | :--- | :--- | :--- |
37+
| Token (required) | `token` | string | Fill in your Jira API token. You can generate one from your Jira account "settings > security > API tokens". |
38+
| Base URL (required) | `base-url` | string | Fill in your Jira base URL. For example, if your Jira URL is https://mycompany.atlassian.net, then your base URL is https://mycompany.atlassian.net. |
39+
| Email (required) | `email` | string | Fill in your Jira email address. |
40+
41+
42+
43+
44+
## Supported Tasks
45+
46+
### List Boards
47+
48+
List all boards in Jira
49+
50+
51+
| Input | ID | Type | Description |
52+
| :--- | :--- | :--- | :--- |
53+
| Task ID (required) | `task` | string | `TASK_LIST_BOARDS` |
54+
| Project Key or ID | `project-key-or-id` | string | This filters results to boards that are relevant to a project. Relevance meaning that the JQL filter defined in board contains a reference to a project. |
55+
| Board Type | `board-type` | string | The type of board, can be: scrum, kanban, simple. Default is simple |
56+
| Name | `name` | string | Name filters results to boards that match or partially match the specified name. Default is empty |
57+
| Start At | `start-at` | integer | The starting index of the returned boards. Base index: 0. Default is 0 |
58+
| Max Results | `max-results` | integer | The maximum number of boards to return. Default is 50 |
59+
60+
61+
62+
| Output | ID | Type | Description |
63+
| :--- | :--- | :--- | :--- |
64+
| Boards (optional) | `boards` | array[object] | A array of boards in Jira |
65+
| Start At | `start-at` | integer | The starting index of the returned boards. Base index: 0 |
66+
| Max Results | `max-results` | integer | The maximum number of boards |
67+
| Total | `total` | integer | The total number of boards |
68+
| Is Last | `is-last` | boolean | Whether the last board is reached |
69+
70+
71+
72+
73+
74+
75+
### List Issues
76+
77+
List issues in Jira
78+
79+
80+
| Input | ID | Type | Description |
81+
| :--- | :--- | :--- | :--- |
82+
| Task ID (required) | `task` | string | `TASK_LIST_ISSUES` |
83+
| Board ID (required) | `board-id` | integer | The ID of the board |
84+
| Range | `range` | object | Choose the range of issues to return. Default is `all` |
85+
| Start At | `start-at` | integer | The starting index of the returned boards. Base index: 0. Default is 0 |
86+
| Max Results | `max-results` | integer | The maximum number of boards to return. Default is 50 |
87+
88+
89+
90+
| Output | ID | Type | Description |
91+
| :--- | :--- | :--- | :--- |
92+
| Issues (optional) | `issues` | array[object] | A array of issues in Jira |
93+
| Start At | `start-at` | integer | The starting index of the returned boards. Base index: 0 |
94+
| Max Results | `max-results` | integer | The maximum number of boards |
95+
| Total | `total` | integer | The total number of boards |
96+
97+
98+
99+
100+
101+
102+
### List Sprints
103+
104+
List sprints in Jira
105+
106+
107+
| Input | ID | Type | Description |
108+
| :--- | :--- | :--- | :--- |
109+
| Task ID (required) | `task` | string | `TASK_LIST_SPRINTS` |
110+
| Board ID (required) | `board-id` | integer | The ID of the board |
111+
| Start At | `start-at` | integer | The starting index of the returned boards. Base index: 0. Default is 0 |
112+
| Max Results | `max-results` | integer | The maximum number of boards to return. Default is 50 |
113+
114+
115+
116+
| Output | ID | Type | Description |
117+
| :--- | :--- | :--- | :--- |
118+
| Sprints (optional) | `sprints` | array[object] | A array of sprints in Jira |
119+
| Start At | `start-at` | integer | The starting index of the returned boards. Base index: 0 |
120+
| Max Results | `max-results` | integer | The maximum number of boards |
121+
| Total | `total` | integer | The total number of boards |
122+
123+
124+
125+
126+
127+
128+
### Get Issue
129+
130+
Get an issue in Jira
131+
132+
133+
| Input | ID | Type | Description |
134+
| :--- | :--- | :--- | :--- |
135+
| Task ID (required) | `task` | string | `TASK_GET_ISSUE` |
136+
| Issue ID or Key (required) | `issue-id-or-key` | string | The ID or key of the issue |
137+
| Update History | `update-history` | boolean | Whether the project in which the issue is created is added to the user's Recently viewed project list, as shown under Projects in Jira. |
138+
139+
140+
141+
| Output | ID | Type | Description |
142+
| :--- | :--- | :--- | :--- |
143+
| ID | `id` | string | The ID of the issue |
144+
| Key | `key` | string | The key of the issue |
145+
| Self | `self` | string | The URL of the issue |
146+
| Fields | `fields` | object | The fields of the issue. All navigable and Agile fields are returned |
147+
| Issue Type (optional) | `issue-type` | string | The type of the issue, can be: `Task`, `Epic` |
148+
| Summary (optional) | `summary` | string | The summary of the issue |
149+
| Description (optional) | `description` | string | The description of the issue |
150+
| Status (optional) | `status` | string | The status of the issue, can be: `To Do`, `In Progress`, `Done` |
151+
152+
153+
154+
155+
156+
157+
### Get Sprint
158+
159+
Get a sprint in Jira
160+
161+
162+
| Input | ID | Type | Description |
163+
| :--- | :--- | :--- | :--- |
164+
| Task ID (required) | `task` | string | `TASK_GET_SPRINT` |
165+
| Sprint ID (required) | `sprint-id` | integer | The ID of the sprint. The sprint will only be returned if you can view the board that the sprint was created on, or view at least one of the issues in the sprint. |
166+
167+
168+
169+
| Output | ID | Type | Description |
170+
| :--- | :--- | :--- | :--- |
171+
| ID (optional) | `id` | integer | The ID of the sprint |
172+
| Self (optional) | `self` | string | The URL of the sprint |
173+
| State (optional) | `state` | string | The state of the sprint, can be: `active`, `closed`, `future` |
174+
| Name (optional) | `name` | string | The name of the sprint |
175+
| Start Date (optional) | `start-date` | string | The start date of the sprint. In the RFC3339 format, e.g. 2018-03-05T00:00:00Z |
176+
| End Date (optional) | `end-date` | string | The end date of the sprint. In the RFC3339 format, e.g. 2018-03-05T00:00:00Z |
177+
| Complete Date (optional) | `complete-date` | string | The complete date of the sprint. In the RFC3339 format, e.g. 2018-03-05T00:00:00Z |
178+
| Origin Board ID (optional) | `origin-board-id` | integer | The ID of the origin board |
179+
| Goal (optional) | `goal` | string | The Goal of the sprint |
180+
181+
182+
183+
184+
185+
186+

application/jira/v0/assets/jira.svg

+15
Loading

application/jira/v0/boards.go

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package jira
2+
3+
import (
4+
"context"
5+
_ "embed"
6+
"fmt"
7+
8+
"github.com/instill-ai/component/base"
9+
"github.com/instill-ai/x/errmsg"
10+
"google.golang.org/protobuf/types/known/structpb"
11+
)
12+
13+
type Board struct {
14+
ID int `json:"id"`
15+
Name string `json:"name"`
16+
Self string `json:"self"`
17+
BoardType string `json:"type"`
18+
}
19+
20+
type ListBoardsInput struct {
21+
ProjectKeyOrID string `json:"project-key-or-id,omitempty" api:"projectKeyOrId"`
22+
BoardType string `json:"board-type,omitempty" api:"type"`
23+
Name string `json:"name,omitempty" api:"name"`
24+
StartAt int `json:"start-at,omitempty" api:"startAt"`
25+
MaxResults int `json:"max-results,omitempty" api:"maxResults"`
26+
}
27+
type ListBoardsResp struct {
28+
Values []Board `json:"values"`
29+
StartAt int `json:"startAt"`
30+
MaxResults int `json:"maxResults"`
31+
Total int `json:"total"`
32+
IsLast bool `json:"isLast"`
33+
}
34+
35+
type ListBoardsOutput struct {
36+
Boards []Board `json:"boards"`
37+
StartAt int `json:"start-at"`
38+
MaxResults int `json:"max-results"`
39+
Total int `json:"total"`
40+
IsLast bool `json:"is-last"`
41+
}
42+
43+
func (jiraClient *Client) listBoardsTask(ctx context.Context, props *structpb.Struct) (*structpb.Struct, error) {
44+
var opt ListBoardsInput
45+
if err := base.ConvertFromStructpb(props, &opt); err != nil {
46+
return nil, err
47+
}
48+
49+
boards, err := jiraClient.listBoards(ctx, &opt)
50+
if err != nil {
51+
return nil, err
52+
}
53+
var output ListBoardsOutput
54+
output.Boards = append(output.Boards, boards.Values...)
55+
if output.Boards == nil {
56+
output.Boards = []Board{}
57+
}
58+
output.StartAt = boards.StartAt
59+
output.MaxResults = boards.MaxResults
60+
output.IsLast = boards.IsLast
61+
output.Total = boards.Total
62+
return base.ConvertToStructpb(output)
63+
}
64+
65+
func (jiraClient *Client) listBoards(_ context.Context, opt *ListBoardsInput) (*ListBoardsResp, error) {
66+
apiEndpoint := "rest/agile/1.0/board"
67+
68+
req := jiraClient.Client.R().SetResult(&ListBoardsResp{})
69+
err := addQueryOptions(req, *opt)
70+
if err != nil {
71+
return nil, err
72+
}
73+
resp, err := req.Get(apiEndpoint)
74+
75+
if err != nil {
76+
return nil, err
77+
}
78+
boards := resp.Result().(*ListBoardsResp)
79+
return boards, err
80+
}
81+
82+
type GetBoardResp struct {
83+
Location struct {
84+
DisplayName string `json:"displayName"`
85+
Name string `json:"name"`
86+
ProjectKey string `json:"projectKey"`
87+
ProjectID int `json:"projectId"`
88+
ProjectName string `json:"projectName"`
89+
ProjectTypeKey string `json:"projectTypeKey"`
90+
UserAccountID string `json:"userAccountId"`
91+
UserID string `json:"userId"`
92+
} `json:"location"`
93+
Board
94+
}
95+
96+
func (jiraClient *Client) getBoard(_ context.Context, boardID int) (*GetBoardResp, error) {
97+
apiEndpoint := fmt.Sprintf("rest/agile/1.0/board/%v", boardID)
98+
99+
req := jiraClient.Client.R().SetResult(&GetBoardResp{})
100+
resp, err := req.Get(apiEndpoint)
101+
if err != nil {
102+
return nil, fmt.Errorf(
103+
err.Error(), errmsg.Message(err),
104+
)
105+
}
106+
result := resp.Result().(*GetBoardResp)
107+
108+
return result, err
109+
}

0 commit comments

Comments
 (0)