diff --git a/jira/agile/board.go b/jira/agile/board.go index 08a0f73d..2a94e107 100644 --- a/jira/agile/board.go +++ b/jira/agile/board.go @@ -81,6 +81,7 @@ func (b *BoardService) Create(ctx context.Context, payload *BoardPayloadScheme) type BoardPageScheme struct { MaxResults int `json:"maxResults"` StartAt int `json:"startAt"` + Total int `json:"total"` IsLast bool `json:"isLast"` Values []*BoardScheme `json:"values"` } @@ -808,3 +809,84 @@ func (b *BoardService) Delete(ctx context.Context, boardID int) (response *Respo return } + +type GetBoardsOptions struct { + BoardType string + BoardName string + ProjectKeyOrID string + AccountIDLocation string + ProjectIDLocation string + IncludePrivate bool + NegateLocationFiltering bool + OrderBy string + Expand string + FilterID int +} + +// Gets returns all boards. This only includes boards that the user has permission to view. +// Docs: https://developer.atlassian.com/cloud/jira/software/rest/api-group-other-operations/#api-agile-1-0-board-get +func (b *BoardService) Gets(ctx context.Context, opts *GetBoardsOptions, startAt, maxResults int) (result *BoardPageScheme, response *ResponseScheme, err error) { + + params := url.Values{} + params.Add("startAt", strconv.Itoa(startAt)) + params.Add("maxResults", strconv.Itoa(maxResults)) + + if opts != nil { + + if opts.BoardType != "" { + params.Add("type", opts.BoardType) + } + + if opts.BoardName != "" { + params.Add("name", opts.BoardName) + } + + if opts.ProjectKeyOrID != "" { + params.Add("projectKeyOrId", opts.ProjectKeyOrID) + } + + if opts.AccountIDLocation != "" { + params.Add("accountIdLocation", opts.AccountIDLocation) + } + + if opts.ProjectIDLocation != "" { + params.Add("projectLocation", opts.ProjectIDLocation) + } + + if opts.IncludePrivate { + params.Add("includePrivate", "true") + } + + if opts.NegateLocationFiltering { + params.Add("negateLocationFiltering", "true") + } + + if opts.OrderBy != "" { + params.Add("orderBy", opts.OrderBy) + } + + if opts.Expand != "" { + params.Add("expand", opts.Expand) + } + + if opts.FilterID != 0 { + params.Add("filterId", strconv.Itoa(opts.FilterID)) + } + } + + var endpoint = fmt.Sprintf("/rest/agile/1.0/board?%v", params.Encode()) + + request, err := b.client.newRequest(ctx, http.MethodGet, endpoint, nil) + if err != nil { + return + } + + request.Header.Set("Accept", "application/json") + + response, err = b.client.Call(request, &result) + if err != nil { + return nil, response, err + } + + return +} diff --git a/jira/agile/board_test.go b/jira/agile/board_test.go index c48b4019..bf00ca75 100644 --- a/jira/agile/board_test.go +++ b/jira/agile/board_test.go @@ -339,6 +339,209 @@ func TestBoardService_Create(t *testing.T) { } +func TestBoardService_Gets(t *testing.T) { + + testCases := []struct { + name string + opts *GetBoardsOptions + startAt, maxResults int + mockFile string + wantHTTPMethod string + endpoint string + context context.Context + wantHTTPCodeReturn int + wantErr bool + }{ + { + name: "GetBoardsTheParametersAreCorrect", + opts: &GetBoardsOptions{ + BoardType: "scrum", + BoardName: "board-name", + ProjectKeyOrID: "CID", + AccountIDLocation: "account-id-sample", + ProjectIDLocation: "2345", + IncludePrivate: true, + NegateLocationFiltering: true, + OrderBy: "name", + Expand: "permissions", + FilterID: 111234, + }, + startAt: 0, + maxResults: 50, + mockFile: "./mocks/get-boards-by-filter-id.json", + wantHTTPMethod: http.MethodGet, + endpoint: "/rest/agile/1.0/board?accountIdLocation=account-id-sample&expand=permissions&filterId=111234&includePrivate=true&maxResults=50&name=board-name&negateLocationFiltering=true&orderBy=name&projectKeyOrId=CID&projectLocation=2345&startAt=0&type=scrum", + context: context.Background(), + wantHTTPCodeReturn: http.StatusOK, + wantErr: false, + }, + + { + name: "GetBoardByFilterWhenTheRequestMethodIsIncorrect", + opts: &GetBoardsOptions{ + BoardType: "scrum", + BoardName: "board-name", + ProjectKeyOrID: "CID", + AccountIDLocation: "account-id-sample", + ProjectIDLocation: "2345", + IncludePrivate: true, + NegateLocationFiltering: true, + OrderBy: "name", + Expand: "permissions", + FilterID: 111234, + }, + startAt: 0, + maxResults: 50, + mockFile: "./mocks/get-board.json", + wantHTTPCodeReturn: http.StatusOK, + wantHTTPMethod: http.MethodHead, + endpoint: "/rest/agile/1.0/board?accountIdLocation=account-id-sample&expand=permissions&filterId=111234&includePrivate=true&maxResults=50&name=board-name&negateLocationFiltering=true&orderBy=name&projectKeyOrId=CID&projectLocation=2345&startAt=0&type=scrum", + context: context.Background(), + wantErr: true, + }, + + { + name: "GetBoardByFilterWhenTheContextIsNil", + opts: &GetBoardsOptions{ + BoardType: "scrum", + BoardName: "board-name", + ProjectKeyOrID: "CID", + AccountIDLocation: "account-id-sample", + ProjectIDLocation: "2345", + IncludePrivate: true, + NegateLocationFiltering: true, + OrderBy: "name", + Expand: "permissions", + FilterID: 111234, + }, + startAt: 0, + maxResults: 50, + mockFile: "./mocks/get-board.json", + wantHTTPCodeReturn: http.StatusOK, + wantHTTPMethod: http.MethodGet, + endpoint: "/rest/agile/1.0/board?accountIdLocation=account-id-sample&expand=permissions&filterId=111234&includePrivate=true&maxResults=50&name=board-name&negateLocationFiltering=true&orderBy=name&projectKeyOrId=CID&projectLocation=2345&startAt=0&type=scrum", + context: nil, + wantErr: true, + }, + + { + name: "GetBoardByFilterWhenTheResponseStatusCodeIsIncorrect", + opts: &GetBoardsOptions{ + BoardType: "scrum", + BoardName: "board-name", + ProjectKeyOrID: "CID", + AccountIDLocation: "account-id-sample", + ProjectIDLocation: "2345", + IncludePrivate: true, + NegateLocationFiltering: true, + OrderBy: "name", + Expand: "permissions", + FilterID: 111234, + }, + startAt: 0, + maxResults: 50, + mockFile: "./mocks/get-board.json", + wantHTTPCodeReturn: http.StatusBadGateway, + wantHTTPMethod: http.MethodGet, + endpoint: "/rest/agile/1.0/board?accountIdLocation=account-id-sample&expand=permissions&filterId=111234&includePrivate=true&maxResults=50&name=board-name&negateLocationFiltering=true&orderBy=name&projectKeyOrId=CID&projectLocation=2345&startAt=0&type=scrum", + context: context.Background(), + wantErr: true, + }, + + { + name: "GetBoardByFilterWhenTheResponseBodyIsEmpty", + opts: &GetBoardsOptions{ + BoardType: "scrum", + BoardName: "board-name", + ProjectKeyOrID: "CID", + AccountIDLocation: "account-id-sample", + ProjectIDLocation: "2345", + IncludePrivate: true, + NegateLocationFiltering: true, + OrderBy: "name", + Expand: "permissions", + FilterID: 111234, + }, + startAt: 0, + maxResults: 50, + mockFile: "./mocks/empty-json.json", + wantHTTPCodeReturn: http.StatusOK, + wantHTTPMethod: http.MethodGet, + endpoint: "/rest/agile/1.0/board?accountIdLocation=account-id-sample&expand=permissions&filterId=111234&includePrivate=true&maxResults=50&name=board-name&negateLocationFiltering=true&orderBy=name&projectKeyOrId=CID&projectLocation=2345&startAt=0&type=scrum", + context: context.Background(), + wantErr: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + + //Init a new HTTP mock server + mockOptions := mockServerOptions{ + Endpoint: testCase.endpoint, + MockFilePath: testCase.mockFile, + MethodAccepted: testCase.wantHTTPMethod, + ResponseCodeWanted: testCase.wantHTTPCodeReturn, + } + + mockServer, err := startMockServer(&mockOptions) + if err != nil { + t.Fatal(err) + } + + defer mockServer.Close() + + //Init the library instance + mockClient, err := startMockClient(mockServer.URL) + if err != nil { + t.Fatal(err) + } + + service := &BoardService{client: mockClient} + gotResult, gotResponse, err := service.Gets(testCase.context, testCase.opts, + testCase.startAt, testCase.maxResults) + + if testCase.wantErr { + + if err != nil { + t.Logf("error returned: %v", err.Error()) + } + + assert.Error(t, err) + + if gotResponse != nil { + t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code) + } + } else { + + assert.NoError(t, err) + assert.NotEqual(t, gotResponse, nil) + assert.NotEqual(t, gotResult, nil) + + apiEndpoint, err := url.Parse(gotResponse.Endpoint) + if err != nil { + t.Fatal(err) + } + + var endpointToAssert string + + if apiEndpoint.Query().Encode() != "" { + endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode()) + } else { + endpointToAssert = apiEndpoint.Path + } + + t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert) + assert.Equal(t, testCase.endpoint, endpointToAssert) + + t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code) + assert.Equal(t, gotResponse.Code, testCase.wantHTTPCodeReturn) + } + }) + } + +} + func TestBoardService_Filter(t *testing.T) { testCases := []struct {