Skip to content

Commit aeff901

Browse files
committed
Cloud/Component: Review service "Component" in the Cloud Jira client for latest API changes
1 parent 2671c36 commit aeff901

File tree

5 files changed

+131
-20
lines changed

5 files changed

+131
-20
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,7 @@ client, err := jira.NewClient("https://...", tp.Client())
396396
* Cloud/Authentication: Removed `PATAuthTransport`, because it was a (kind of) duplicate of `BasicAuthTransport`
397397
* Cloud/Authentication: `BasicAuthTransport.Password` was renamed to `BasicAuthTransport.APIToken`
398398
* Cloud/Authentication: Removes `CookieAuthTransport` and `AuthenticationService`, because this type of auth is not supported by the Jira cloud offering
399+
* Cloud/Component: The type `CreateComponentOptions` was renamed to `ComponentCreateOptions`
399400

400401
### Features
401402

cloud/component.go

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,36 +6,67 @@ import (
66
"net/http"
77
)
88

9-
// ComponentService handles components for the Jira instance / API.//
10-
// Jira API docs: https://docs.atlassian.com/software/jira/docs/api/REST/7.10.1/#api/2/component
9+
// ComponentService represents project components.
10+
// Use it to get, create, update, and delete project components.
11+
// Also get components for project and get a count of issues by component.
12+
//
13+
// Jira API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-project-components/#api-group-project-components
1114
type ComponentService service
1215

13-
// CreateComponentOptions are passed to the ComponentService.Create function to create a new Jira component
14-
type CreateComponentOptions struct {
15-
Name string `json:"name,omitempty" structs:"name,omitempty"`
16-
Description string `json:"description,omitempty" structs:"description,omitempty"`
17-
Lead *User `json:"lead,omitempty" structs:"lead,omitempty"`
18-
LeadUserName string `json:"leadUserName,omitempty" structs:"leadUserName,omitempty"`
16+
const (
17+
AssigneeTypeProjectLead = "PROJECT_LEAD"
18+
AssigneeTypeComponentLead = "COMPONENT_LEAD"
19+
AssigneeTypeUnassigned = "UNASSIGNED"
20+
AssigneeTypeProjectDefault = "PROJECT_DEFAULT"
21+
)
22+
23+
// ComponentCreateOptions are passed to the ComponentService.Create function to create a new Jira component
24+
type ComponentCreateOptions struct {
25+
// Name: The unique name for the component in the project.
26+
// Required when creating a component.
27+
// Optional when updating a component.
28+
// The maximum length is 255 characters.
29+
Name string `json:"name,omitempty" structs:"name,omitempty"`
30+
31+
// Description: The description for the component.
32+
// Optional when creating or updating a component.
33+
Description string `json:"description,omitempty" structs:"description,omitempty"`
34+
35+
// LeadAccountId: The accountId of the component's lead user.
36+
// The accountId uniquely identifies the user across all Atlassian products.
37+
// For example, 5b10ac8d82e05b22cc7d4ef5.
38+
LeadAccountId string `json:"leadAccountId,omitempty" structs:"leadAccountId,omitempty"`
39+
40+
// AssigneeType: The nominal user type used to determine the assignee for issues created with this component.
41+
// Can take the following values:
42+
// PROJECT_LEAD the assignee to any issues created with this component is nominally the lead for the project the component is in.
43+
// COMPONENT_LEAD the assignee to any issues created with this component is nominally the lead for the component.
44+
// UNASSIGNED an assignee is not set for issues created with this component.
45+
// PROJECT_DEFAULT the assignee to any issues created with this component is nominally the default assignee for the project that the component is in.
46+
//
47+
// Default value: PROJECT_DEFAULT.
48+
// Optional when creating or updating a component.
1949
AssigneeType string `json:"assigneeType,omitempty" structs:"assigneeType,omitempty"`
20-
Assignee *User `json:"assignee,omitempty" structs:"assignee,omitempty"`
21-
Project string `json:"project,omitempty" structs:"project,omitempty"`
22-
ProjectID int `json:"projectId,omitempty" structs:"projectId,omitempty"`
50+
51+
// Project: The key of the project the component is assigned to.
52+
// Required when creating a component.
53+
// Can't be updated.
54+
Project string `json:"project,omitempty" structs:"project,omitempty"`
2355
}
2456

25-
// Create creates a new Jira component based on the given options.
57+
// Create creates a component.
58+
// Use components to provide containers for issues within a project.
2659
//
27-
// TODO Double check this method if this works as expected, is using the latest API and the response is complete
28-
// This double check effort is done for v2 - Remove this two lines if this is completed.
29-
func (s *ComponentService) Create(ctx context.Context, options *CreateComponentOptions) (*ProjectComponent, *Response, error) {
30-
apiEndpoint := "rest/api/2/component"
60+
// Jira API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-project-components/#api-rest-api-3-component-post
61+
func (s *ComponentService) Create(ctx context.Context, options *ComponentCreateOptions) (*ProjectComponent, *Response, error) {
62+
apiEndpoint := "rest/api/3/component"
3163
req, err := s.client.NewRequest(ctx, http.MethodPost, apiEndpoint, options)
3264
if err != nil {
3365
return nil, nil, err
3466
}
3567

3668
component := new(ProjectComponent)
3769
resp, err := s.client.Do(req, component)
38-
3970
if err != nil {
4071
return nil, resp, NewJiraError(resp, err)
4172
}
@@ -61,3 +92,13 @@ func (s *ComponentService) Get(ctx context.Context, componentID string) (*Projec
6192

6293
return component, resp, nil
6394
}
95+
96+
// TODO Add "Update component" method. See https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-project-components/#api-rest-api-3-component-id-put
97+
98+
// TODO Add "Delete component" method. See https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-project-components/#api-rest-api-3-component-id-delete
99+
100+
// TODO Add "Get component issues count" method. See https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-project-components/#api-rest-api-3-component-id-relatedissuecounts-get
101+
102+
// TODO Add "Get project components paginated" method. See https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-project-components/#api-rest-api-3-project-projectidorkey-component-get
103+
104+
// TODO Add "Get project components" method. See https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-project-components/#api-rest-api-3-project-projectidorkey-components-get

cloud/component_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,17 @@ import (
1111
func TestComponentService_Create_Success(t *testing.T) {
1212
setup()
1313
defer teardown()
14-
testMux.HandleFunc("/rest/api/2/component", func(w http.ResponseWriter, r *http.Request) {
14+
testAPIEndpoint := "/rest/api/3/component"
15+
16+
testMux.HandleFunc(testAPIEndpoint, func(w http.ResponseWriter, r *http.Request) {
1517
testMethod(t, r, http.MethodPost)
16-
testRequestURL(t, r, "/rest/api/2/component")
18+
testRequestURL(t, r, testAPIEndpoint)
1719

1820
w.WriteHeader(http.StatusCreated)
1921
fmt.Fprint(w, `{ "self": "http://www.example.com/jira/rest/api/2/component/10000", "id": "10000", "name": "Component 1", "description": "This is a Jira component", "lead": { "self": "http://www.example.com/jira/rest/api/2/user?username=fred", "name": "fred", "avatarUrls": { "48x48": "http://www.example.com/jira/secure/useravatar?size=large&ownerId=fred", "24x24": "http://www.example.com/jira/secure/useravatar?size=small&ownerId=fred", "16x16": "http://www.example.com/jira/secure/useravatar?size=xsmall&ownerId=fred", "32x32": "http://www.example.com/jira/secure/useravatar?size=medium&ownerId=fred" }, "displayName": "Fred F. User", "active": false }, "assigneeType": "PROJECT_LEAD", "assignee": { "self": "http://www.example.com/jira/rest/api/2/user?username=fred", "name": "fred", "avatarUrls": { "48x48": "http://www.example.com/jira/secure/useravatar?size=large&ownerId=fred", "24x24": "http://www.example.com/jira/secure/useravatar?size=small&ownerId=fred", "16x16": "http://www.example.com/jira/secure/useravatar?size=xsmall&ownerId=fred", "32x32": "http://www.example.com/jira/secure/useravatar?size=medium&ownerId=fred" }, "displayName": "Fred F. User", "active": false }, "realAssigneeType": "PROJECT_LEAD", "realAssignee": { "self": "http://www.example.com/jira/rest/api/2/user?username=fred", "name": "fred", "avatarUrls": { "48x48": "http://www.example.com/jira/secure/useravatar?size=large&ownerId=fred", "24x24": "http://www.example.com/jira/secure/useravatar?size=small&ownerId=fred", "16x16": "http://www.example.com/jira/secure/useravatar?size=xsmall&ownerId=fred", "32x32": "http://www.example.com/jira/secure/useravatar?size=medium&ownerId=fred" }, "displayName": "Fred F. User", "active": false }, "isAssigneeTypeValid": false, "project": "HSP", "projectId": 10000 }`)
2022
})
2123

22-
component, _, err := testClient.Component.Create(context.Background(), &CreateComponentOptions{
24+
component, _, err := testClient.Component.Create(context.Background(), &ComponentCreateOptions{
2325
Name: "foo-bar",
2426
})
2527
if component == nil {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
jira "github.com/andygrunwald/go-jira/v2/cloud"
8+
)
9+
10+
func main() {
11+
jiraURL := "https://go-jira-opensource.atlassian.net/"
12+
13+
// Jira docs: https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account/
14+
// Create a new API token: https://id.atlassian.com/manage-profile/security/api-tokens
15+
tp := jira.BasicAuthTransport{
16+
Username: "<username>",
17+
APIToken: "<api-token>",
18+
}
19+
client, err := jira.NewClient(jiraURL, tp.Client())
20+
if err != nil {
21+
panic(err)
22+
}
23+
24+
c := &jira.ComponentCreateOptions{
25+
Name: "Dummy component",
26+
AssigneeType: jira.AssigneeTypeUnassigned,
27+
Project: "BUG",
28+
}
29+
component, _, err := client.Component.Create(context.Background(), c)
30+
if err != nil {
31+
panic(err)
32+
}
33+
34+
fmt.Printf("component: %+v\n", component)
35+
fmt.Println("Success!")
36+
}

cloud/examples/component_get/main.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
jira "github.com/andygrunwald/go-jira/v2/cloud"
8+
)
9+
10+
func main() {
11+
jiraURL := "https://go-jira-opensource.atlassian.net/"
12+
13+
// Jira docs: https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account/
14+
// Create a new API token: https://id.atlassian.com/manage-profile/security/api-tokens
15+
tp := jira.BasicAuthTransport{
16+
Username: "<username>",
17+
APIToken: "<api-token>",
18+
}
19+
client, err := jira.NewClient(jiraURL, tp.Client())
20+
if err != nil {
21+
panic(err)
22+
}
23+
24+
component, _, err := client.Component.Get(context.Background(), "10000")
25+
if err != nil {
26+
panic(err)
27+
}
28+
29+
fmt.Printf("component: %+v\n", component)
30+
fmt.Println("Success!")
31+
}

0 commit comments

Comments
 (0)