diff --git a/jira/agile/api_client_impl.go b/jira/agile/api_client_impl.go index 8fb86161..2b838bd0 100644 --- a/jira/agile/api_client_impl.go +++ b/jira/agile/api_client_impl.go @@ -4,10 +4,8 @@ import ( "bytes" "context" "encoding/json" - "errors" "github.com/ctreminiom/go-atlassian/jira/agile/internal" "github.com/ctreminiom/go-atlassian/pkg/infra/models" - "github.com/ctreminiom/go-atlassian/service/agile" "github.com/ctreminiom/go-atlassian/service/common" "io" "io/ioutil" @@ -64,9 +62,9 @@ type Client struct { HTTP common.HttpClient Site *url.URL Auth common.Authentication - Board agile.Board - Epic agile.Epic - Sprint agile.Sprint + Board *internal.BoardService + Epic *internal.EpicService + Sprint *internal.SprintService } func (c *Client) NewFormRequest(ctx context.Context, method, apiEndpoint, contentType string, payload io.Reader) (*http.Request, error) { @@ -107,11 +105,15 @@ func (c *Client) NewRequest(ctx context.Context, method, apiEndpoint string, pay func (c *Client) Call(request *http.Request, structure interface{}) (*models.ResponseScheme, error) { response, err := c.HTTP.Do(request) - if err != nil { return nil, err } + return c.TransformTheHTTPResponse(response, structure) +} + +func (c *Client) TransformTheHTTPResponse(response *http.Response, structure interface{}) (*models.ResponseScheme, error) { + responseTransformed := &models.ResponseScheme{ Response: response, Code: response.StatusCode, @@ -119,49 +121,16 @@ func (c *Client) Call(request *http.Request, structure interface{}) (*models.Res Method: response.Request.Method, } - if !(response.StatusCode >= 200 && response.StatusCode < 300) { - return responseTransformed, models.ErrInvalidStatusCodeError - } - responseAsBytes, err := ioutil.ReadAll(response.Body) if err != nil { return responseTransformed, err } - if structure != nil { - if err = json.Unmarshal(responseAsBytes, &structure); err != nil { - return responseTransformed, err - } - } - - _, err = responseTransformed.Bytes.Write(responseAsBytes) - if err != nil { - return nil, err - } - - return responseTransformed, nil -} - -func (c *Client) TransformTheHTTPResponse(response *http.Response, structure interface{}) (*models.ResponseScheme, error) { - - if response == nil { - return nil, errors.New("validation failed, please provide a http.Response pointer") - } - - responseTransformed := &models.ResponseScheme{} - responseTransformed.Code = response.StatusCode - responseTransformed.Endpoint = response.Request.URL.String() - responseTransformed.Method = response.Request.Method + responseTransformed.Bytes.Write(responseAsBytes) var wasSuccess = response.StatusCode >= 200 && response.StatusCode < 300 if !wasSuccess { - - return responseTransformed, errors.New("TODO") - } - - responseAsBytes, err := ioutil.ReadAll(response.Body) - if err != nil { - return responseTransformed, err + return responseTransformed, models.ErrInvalidStatusCodeError } if structure != nil { @@ -170,7 +139,6 @@ func (c *Client) TransformTheHTTPResponse(response *http.Response, structure int } } - responseTransformed.Bytes.Write(responseAsBytes) return responseTransformed, nil } diff --git a/jira/agile/api_client_impl_test.go b/jira/agile/api_client_impl_test.go index 5a8dd5db..1952a511 100644 --- a/jira/agile/api_client_impl_test.go +++ b/jira/agile/api_client_impl_test.go @@ -4,8 +4,8 @@ import ( "bytes" "encoding/json" "errors" + "github.com/ctreminiom/go-atlassian/jira/agile/internal" "github.com/ctreminiom/go-atlassian/pkg/infra/models" - "github.com/ctreminiom/go-atlassian/service/agile" "github.com/ctreminiom/go-atlassian/service/common" "github.com/ctreminiom/go-atlassian/service/mocks" "github.com/stretchr/testify/assert" @@ -41,9 +41,9 @@ func TestClient_Call(t *testing.T) { HTTP common.HttpClient Site *url.URL Authentication common.Authentication - Board agile.Board - Epic agile.Epic - Sprint agile.Sprint + Board *internal.BoardService + Epic *internal.EpicService + Sprint *internal.SprintService } type args struct { @@ -253,9 +253,9 @@ func TestClient_TransformTheHTTPResponse(t *testing.T) { HTTP common.HttpClient Site *url.URL Authentication common.Authentication - Board agile.Board - Epic agile.Epic - Sprint agile.Sprint + Board *internal.BoardService + Epic *internal.EpicService + Sprint *internal.SprintService } type args struct { @@ -321,7 +321,7 @@ func TestClient_TransformTheHTTPResponse(t *testing.T) { func TestClient_TransformStructToReader(t *testing.T) { expectedBytes, err := json.Marshal(&models.BoardScheme{ - Name: "Board Sample", + Name: "BoardConnector Sample", Type: "Scrum", }) @@ -333,9 +333,9 @@ func TestClient_TransformStructToReader(t *testing.T) { HTTP common.HttpClient Site *url.URL Authentication common.Authentication - Board agile.Board - Epic agile.Epic - Sprint agile.Sprint + Board *internal.BoardService + Epic *internal.EpicService + Sprint *internal.SprintService } type args struct { @@ -354,7 +354,7 @@ func TestClient_TransformStructToReader(t *testing.T) { name: "when the parameters are correct", args: args{ structure: &models.BoardScheme{ - Name: "Board Sample", + Name: "BoardConnector Sample", Type: "Scrum", }, }, @@ -366,7 +366,7 @@ func TestClient_TransformStructToReader(t *testing.T) { name: "when the payload provided is not a pointer", args: args{ structure: models.BoardScheme{ - Name: "Board Sample", + Name: "BoardConnector Sample", Type: "Scrum", }, }, diff --git a/jira/agile/internal/board_impl.go b/jira/agile/internal/board_impl.go index 6dcee305..0b5e6eaa 100644 --- a/jira/agile/internal/board_impl.go +++ b/jira/agile/internal/board_impl.go @@ -12,68 +12,288 @@ import ( "strings" ) -func NewBoardService(client service.Client, version string) (agile.Board, error) { +func NewBoardService(client service.Client, version string) (*BoardService, error) { if version == "" { return nil, model.ErrNoVersionProvided } - return &BoardService{client, version}, nil + return &BoardService{ + internalClient: &internalBoardImpl{c: client, version: version}, + }, nil } type BoardService struct { + internalClient agile.BoardConnector +} + +// Get returns the board for the given board ID. +// This board will only be returned if the user has permission to view it. +// +// +// Admins without the view permission will see the board as a private one, +// +// so will see only a subset of the board's data (board location for instance). +// +// GET /rest/agile/1.0/board/{boardId} +// +// https://docs.go-atlassian.io/jira-agile/boards#get-board +func (b *BoardService) Get(ctx context.Context, boardID int) (*model.BoardScheme, *model.ResponseScheme, error) { + return b.internalClient.Get(ctx, boardID) +} + +// Create creates a new board. Board name, type and filter ID is required. +// +// POST /rest/agile/1.0/board +// +// Docs: https://docs.go-atlassian.io/jira-agile/boards#create-board +func (b *BoardService) Create(ctx context.Context, payload *model.BoardPayloadScheme) (*model.BoardScheme, *model.ResponseScheme, error) { + return b.internalClient.Create(ctx, payload) +} + +// Filter returns any boards which use the provided filter id. +// +// This method can be executed by users without a valid software license in order +// +// to find which boards are using a particular filter. +// +// GET /rest/agile/1.0/board/filter/{filterId} +// +// https://docs.go-atlassian.io/jira-agile/boards#get-board-by-filter-id +func (b *BoardService) Filter(ctx context.Context, filterID, startAt, maxResults int) (*model.BoardPageScheme, *model.ResponseScheme, error) { + return b.internalClient.Filter(ctx, filterID, startAt, maxResults) +} + +// Backlog returns all issues from the board's backlog, for the given board ID. +// +// This only includes issues that the user has permission to view. +// +// The backlog contains incomplete issues that are not assigned to any future or active sprint. +// +// Note, if the user does not have permission to view the board, no issues will be returned at all. +// +// Issues returned from this resource include Agile fields, like sprint, closedSprints, flagged, and epic. +// +// By default, the returned issues are ordered by rank. +// +// GET /rest/agile/1.0/board/{boardId}/backlog +// +// https://docs.go-atlassian.io/jira-agile/boards#get-issues-for-backlog +func (b *BoardService) Backlog(ctx context.Context, boardID int, opts *model.IssueOptionScheme, startAt, maxResults int) (*model.BoardIssuePageScheme, *model.ResponseScheme, error) { + return b.internalClient.Backlog(ctx, boardID, opts, startAt, maxResults) +} + +// Configuration get the board configuration. +// +// GET /rest/agile/1.0/board/{boardId}/configuration +// +// https://docs.go-atlassian.io/jira-agile/boards#get-configuration +func (b *BoardService) Configuration(ctx context.Context, boardID int) (*model.BoardConfigurationScheme, *model.ResponseScheme, error) { + return b.internalClient.Configuration(ctx, boardID) +} + +// Epics returns all epics from the board, for the given board ID. +// +// This only includes epics that the user has permission to view. +// +// Note, if the user does not have permission to view the board, no epics will be returned at all. +// +// GET /rest/agile/1.0/board/{boardId}/epic +// +// https://docs.go-atlassian.io/jira-agile/boards#get-epics +func (b *BoardService) Epics(ctx context.Context, boardID, startAt, maxResults int, done bool) (*model.BoardEpicPageScheme, *model.ResponseScheme, error) { + return b.internalClient.Epics(ctx, boardID, startAt, maxResults, done) +} + +// IssuesWithoutEpic returns all issues that do not belong to any epic on a board, for a given board ID. +// +// This only includes issues that the user has permission to view. +// +// Issues returned from this resource include Agile fields, like sprint, closedSprints, flagged, and epic. +// +// By default, the returned issues are ordered by rank. +// +// GET /rest/agile/1.0/board/{boardId}/epic/none/issue +// +// Docs: https://docs.go-atlassian.io/jira-agile/boards#get-issues-without-epic-for-board +func (b *BoardService) IssuesWithoutEpic(ctx context.Context, boardID int, opts *model.IssueOptionScheme, startAt, maxResults int) (*model.BoardIssuePageScheme, *model.ResponseScheme, error) { + return b.internalClient.IssuesWithoutEpic(ctx, boardID, opts, startAt, maxResults) +} + +// IssuesByEpic returns all issues that belong to an epic on the board, for the given epic ID and the board ID. +// +// This only includes issues that the user has permission to view. +// +// Issues returned from this resource include Agile fields, like sprint, closedSprints, +// +// flagged, and epic. By default, the returned issues are ordered by rank. +// +// GET /rest/agile/1.0/board/{boardId}/epic/none/issue +// +// https://docs.go-atlassian.io/jira-agile/boards#get-board-issues-for-epic +func (b *BoardService) IssuesByEpic(ctx context.Context, boardID, epicID int, opts *model.IssueOptionScheme, startAt, maxResults int) (*model.BoardIssuePageScheme, *model.ResponseScheme, error) { + return b.internalClient.IssuesByEpic(ctx, boardID, epicID, opts, startAt, maxResults) +} + +// Issues returns all issues from a board, for a given board ID. +// +// This only includes issues that the user has permission to view. +// +// An issue belongs to the board if its status is mapped to the board's column. +// +// Epic issues do not belong to the scrum boards. Note, if the user does not have permission to view the board, +// +// no issues will be returned at all. +// +// Issues returned from this resource include Agile fields, like sprint, closedSprints, flagged, and epic. +// +// By default, the returned issues are ordered by rank. +// +// GET /rest/agile/1.0/board/{boardId}/issue +// +// https://docs.go-atlassian.io/jira-agile/boards#get-issues-for-board +func (b *BoardService) Issues(ctx context.Context, boardID int, opts *model.IssueOptionScheme, startAt, maxResults int) (*model.BoardIssuePageScheme, *model.ResponseScheme, error) { + return b.internalClient.Issues(ctx, boardID, opts, startAt, maxResults) +} + +// Move issues from the backlog to the board (if they are already in the backlog of that board). +// +// This operation either moves an issue(s) onto a board from the backlog (by adding it to the issueList for the board) +// +// Or transitions the issue(s) to the first column for a kanban board with backlog. +// +// At most 50 issues may be moved at once. +// +// POST /rest/agile/1.0/board/{boardId}/issue +// +// https://docs.go-atlassian.io/jira-agile/boards#move-issues-to-backlog-for-board +func (b *BoardService) Move(ctx context.Context, boardID int, payload *model.BoardMovementPayloadScheme) (*model.ResponseScheme, error) { + return b.internalClient.Move(ctx, boardID, payload) +} + +// Projects returns all projects that are associated with the board, for the given board ID. +// +// If the user does not have permission to view the board, no projects will be returned at all. +// +// Returned projects are ordered by the name. +// +// GET /rest/agile/1.0/board/{boardId}/project +// +// https://docs.go-atlassian.io/jira-agile/boards#get-projects +func (b *BoardService) Projects(ctx context.Context, boardID, startAt, maxResults int) (*model.BoardProjectPageScheme, *model.ResponseScheme, error) { + return b.internalClient.Projects(ctx, boardID, startAt, maxResults) +} + +// Sprints returns all sprints from a board, for a given board ID. +// +// This only includes sprints that the user has permission to view. +// +// GET /rest/agile/1.0/board/{boardId}/sprint +// +// https://docs.go-atlassian.io/jira-agile/boards#get-all-sprints +func (b *BoardService) Sprints(ctx context.Context, boardID, startAt, maxResults int, states []string) (*model.BoardSprintPageScheme, *model.ResponseScheme, error) { + return b.internalClient.Sprints(ctx, boardID, startAt, maxResults, states) +} + +// IssuesBySprint get all issues you have access to that belong to the sprint from the board. +// +// Issue returned from this resource contains additional fields like: sprint, closedSprints, flagged and epic. +// +// Issues are returned ordered by rank. JQL order has higher priority than default rank. +// +// GET /rest/agile/1.0/board/{boardId}/sprint/{sprintId}/issue +// +// https://docs.go-atlassian.io/jira-agile/boards#get-board-issues-for-sprint +func (b *BoardService) IssuesBySprint(ctx context.Context, boardID, sprintID int, opts *model.IssueOptionScheme, startAt, maxResults int) (*model.BoardIssuePageScheme, *model.ResponseScheme, error) { + return b.internalClient.IssuesBySprint(ctx, boardID, sprintID, opts, startAt, maxResults) +} + +// Versions returns all versions from a board, for a given board ID. +// +// This only includes versions that the user has permission to view. +// +// Note, if the user does not have permission to view the board, no versions will be returned at all. +// +// Returned versions are ordered by the name of the project from which they belong and then by sequence defined by user. +// +// GET /rest/agile/1.0/board/{boardId}/sprint/{sprintId}/issue +// +// https://docs.go-atlassian.io/jira-agile/boards#get-all-versions +func (b *BoardService) Versions(ctx context.Context, boardID, startAt, maxResults int, released bool) (*model.BoardVersionPageScheme, *model.ResponseScheme, error) { + return b.internalClient.Versions(ctx, boardID, startAt, maxResults, released) +} + +// Delete deletes the board. Admin without the view permission can still remove the board. +// +// DELETE /rest/agile/1.0/board/{boardId} +// +// https://docs.go-atlassian.io/jira-agile/boards#delete-board +func (b *BoardService) Delete(ctx context.Context, boardID int) (*model.ResponseScheme, error) { + return b.internalClient.Delete(ctx, boardID) +} + +// Gets returns all boards. This only includes boards that the user has permission to view. +// +// GET /rest/agile/1.0/board +// +// https://docs.go-atlassian.io/jira-agile/boards#get-boards +func (b *BoardService) Gets(ctx context.Context, opts *model.GetBoardsOptions, startAt, maxResults int) (*model.BoardPageScheme, *model.ResponseScheme, error) { + return b.internalClient.Gets(ctx, opts, startAt, maxResults) +} + +type internalBoardImpl struct { c service.Client version string } -func (b BoardService) Get(ctx context.Context, boardId int) (*model.BoardScheme, *model.ResponseScheme, error) { +func (i *internalBoardImpl) Get(ctx context.Context, boardID int) (*model.BoardScheme, *model.ResponseScheme, error) { - if boardId == 0 { + if boardID == 0 { return nil, nil, model.ErrNoBoardIDError } - endpoint := fmt.Sprintf("/rest/agile/%v/board/%v", b.version, boardId) + endpoint := fmt.Sprintf("rest/agile/%v/board/%v", i.version, boardID) - request, err := b.c.NewRequest(ctx, http.MethodGet, endpoint, nil) + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, nil) if err != nil { return nil, nil, err } - var boards model.BoardScheme - response, err := b.c.Call(request, &boards) + boards := new(model.BoardScheme) + response, err := i.c.Call(request, boards) if err != nil { return nil, response, err } - return &boards, response, nil + return boards, response, nil } -func (b BoardService) Create(ctx context.Context, payload *model.BoardPayloadScheme) (*model.BoardScheme, *model.ResponseScheme, error) { +func (i *internalBoardImpl) Create(ctx context.Context, payload *model.BoardPayloadScheme) (*model.BoardScheme, *model.ResponseScheme, error) { - reader, err := b.c.TransformStructToReader(payload) + reader, err := i.c.TransformStructToReader(payload) if err != nil { return nil, nil, err } - endpoint := fmt.Sprintf("/rest/agile/%v/board", b.version) + endpoint := fmt.Sprintf("rest/agile/%v/board", i.version) - request, err := b.c.NewRequest(ctx, http.MethodPost, endpoint, reader) + request, err := i.c.NewRequest(ctx, http.MethodPost, endpoint, reader) if err != nil { return nil, nil, err } - var board model.BoardScheme - response, err := b.c.Call(request, &board) + board := new(model.BoardScheme) + response, err := i.c.Call(request, board) if err != nil { return nil, response, err } - return &board, response, nil + return board, response, nil } -func (b BoardService) Filter(ctx context.Context, filterId, startAt, maxResults int) (*model.BoardPageScheme, *model.ResponseScheme, error) { +func (i *internalBoardImpl) Filter(ctx context.Context, filterID, startAt, maxResults int) (*model.BoardPageScheme, *model.ResponseScheme, error) { - if filterId == 0 { + if filterID == 0 { return nil, nil, model.ErrNoFilterIDError } @@ -81,25 +301,25 @@ func (b BoardService) Filter(ctx context.Context, filterId, startAt, maxResults params.Add("startAt", strconv.Itoa(startAt)) params.Add("maxResults", strconv.Itoa(maxResults)) - endpoint := fmt.Sprintf("/rest/agile/%v/board/filter/%v?%v", b.version, filterId, params.Encode()) + endpoint := fmt.Sprintf("rest/agile/%v/board/filter/%v?%v", i.version, filterID, params.Encode()) - request, err := b.c.NewRequest(ctx, http.MethodGet, endpoint, nil) + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, nil) if err != nil { return nil, nil, err } - var page model.BoardPageScheme - response, err := b.c.Call(request, &page) + page := new(model.BoardPageScheme) + response, err := i.c.Call(request, page) if err != nil { return nil, response, err } - return &page, response, nil + return page, response, nil } -func (b BoardService) Backlog(ctx context.Context, boardId, startAt, maxResults int, opts *model.IssueOptionScheme) (*model.BoardIssuePageScheme, *model.ResponseScheme, error) { +func (i *internalBoardImpl) Backlog(ctx context.Context, boardID int, opts *model.IssueOptionScheme, startAt, maxResults int) (*model.BoardIssuePageScheme, *model.ResponseScheme, error) { - if boardId == 0 { + if boardID == 0 { return nil, nil, model.ErrNoBoardIDError } @@ -109,13 +329,9 @@ func (b BoardService) Backlog(ctx context.Context, boardId, startAt, maxResults if opts != nil { - if !opts.ValidateQuery { - params.Add("validateQuery", "false") - } else { - params.Add("validateQuery", "true") - } + params.Add("validateQuery", fmt.Sprintf("%v", opts.ValidateQuery)) - if len(opts.JQL) != 0 { + if opts.JQL != "" { params.Add("jql", opts.JQL) } @@ -128,47 +344,47 @@ func (b BoardService) Backlog(ctx context.Context, boardId, startAt, maxResults } } - endpoint := fmt.Sprintf("/rest/agile/%v/board/%v/backlog?%v", b.version, boardId, params.Encode()) + endpoint := fmt.Sprintf("rest/agile/%v/board/%v/backlog?%v", i.version, boardID, params.Encode()) - request, err := b.c.NewRequest(ctx, http.MethodGet, endpoint, nil) + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, nil) if err != nil { return nil, nil, err } - var issues model.BoardIssuePageScheme - response, err := b.c.Call(request, &issues) + issues := new(model.BoardIssuePageScheme) + response, err := i.c.Call(request, issues) if err != nil { return nil, response, err } - return &issues, response, nil + return issues, response, nil } -func (b BoardService) Configuration(ctx context.Context, boardId int) (*model.BoardConfigurationScheme, *model.ResponseScheme, error) { +func (i *internalBoardImpl) Configuration(ctx context.Context, boardID int) (*model.BoardConfigurationScheme, *model.ResponseScheme, error) { - if boardId == 0 { + if boardID == 0 { return nil, nil, model.ErrNoBoardIDError } - endpoint := fmt.Sprintf("/rest/agile/%v/board/%v/configuration", b.version, boardId) + endpoint := fmt.Sprintf("rest/agile/%v/board/%v/configuration", i.version, boardID) - request, err := b.c.NewRequest(ctx, http.MethodGet, endpoint, nil) + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, nil) if err != nil { return nil, nil, err } - var configuration model.BoardConfigurationScheme - response, err := b.c.Call(request, &configuration) + configuration := new(model.BoardConfigurationScheme) + response, err := i.c.Call(request, configuration) if err != nil { return nil, response, err } - return &configuration, response, nil + return configuration, response, nil } -func (b BoardService) Epics(ctx context.Context, boardId, startAt, maxResults int, done bool) (*model.BoardEpicPageScheme, *model.ResponseScheme, error) { +func (i *internalBoardImpl) Epics(ctx context.Context, boardID, startAt, maxResults int, done bool) (*model.BoardEpicPageScheme, *model.ResponseScheme, error) { - if boardId == 0 { + if boardID == 0 { return nil, nil, model.ErrNoBoardIDError } @@ -177,25 +393,25 @@ func (b BoardService) Epics(ctx context.Context, boardId, startAt, maxResults in params.Add("maxResults", strconv.Itoa(maxResults)) params.Add("done", fmt.Sprintf("%t", done)) - endpoint := fmt.Sprintf("/rest/agile/%v/board/%v/epic?%v", b.version, boardId, params.Encode()) + endpoint := fmt.Sprintf("rest/agile/%v/board/%v/epic?%v", i.version, boardID, params.Encode()) - request, err := b.c.NewRequest(ctx, http.MethodGet, endpoint, nil) + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, nil) if err != nil { return nil, nil, err } - var epics model.BoardEpicPageScheme - response, err := b.c.Call(request, &epics) + epics := new(model.BoardEpicPageScheme) + response, err := i.c.Call(request, epics) if err != nil { return nil, response, err } - return &epics, response, nil + return epics, response, nil } -func (b BoardService) IssuesWithoutEpic(ctx context.Context, boardId, startAt, maxResults int, opts *model.IssueOptionScheme) (*model.BoardIssuePageScheme, *model.ResponseScheme, error) { +func (i *internalBoardImpl) IssuesWithoutEpic(ctx context.Context, boardID int, opts *model.IssueOptionScheme, startAt, maxResults int) (*model.BoardIssuePageScheme, *model.ResponseScheme, error) { - if boardId == 0 { + if boardID == 0 { return nil, nil, model.ErrNoBoardIDError } @@ -222,29 +438,29 @@ func (b BoardService) IssuesWithoutEpic(ctx context.Context, boardId, startAt, m } } - endpoint := fmt.Sprintf("/rest/agile/%v/board/%v/epic/none/issue?%v", b.version, boardId, params.Encode()) + endpoint := fmt.Sprintf("rest/agile/%v/board/%v/epic/none/issue?%v", i.version, boardID, params.Encode()) - request, err := b.c.NewRequest(ctx, http.MethodGet, endpoint, nil) + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, nil) if err != nil { return nil, nil, err } - var issues model.BoardIssuePageScheme - response, err := b.c.Call(request, &issues) + page := new(model.BoardIssuePageScheme) + response, err := i.c.Call(request, page) if err != nil { return nil, response, err } - return &issues, response, nil + return page, response, nil } -func (b BoardService) IssuesByEpic(ctx context.Context, boardId, epicId, startAt, maxResults int, opts *model.IssueOptionScheme) (*model.BoardIssuePageScheme, *model.ResponseScheme, error) { +func (i *internalBoardImpl) IssuesByEpic(ctx context.Context, boardID, epicID int, opts *model.IssueOptionScheme, startAt, maxResults int) (*model.BoardIssuePageScheme, *model.ResponseScheme, error) { - if boardId == 0 { + if boardID == 0 { return nil, nil, model.ErrNoBoardIDError } - if epicId == 0 { + if epicID == 0 { return nil, nil, model.ErrNoEpicIDError } @@ -255,7 +471,7 @@ func (b BoardService) IssuesByEpic(ctx context.Context, boardId, epicId, startAt if opts != nil { if !opts.ValidateQuery { - params.Add("validateQuery ", "false") + params.Add("validateQuery", "false") } if len(opts.JQL) != 0 { @@ -271,25 +487,25 @@ func (b BoardService) IssuesByEpic(ctx context.Context, boardId, epicId, startAt } } - endpoint := fmt.Sprintf("/rest/agile/%v/board/%v/epic/%v/issue?%v", b.version, boardId, epicId, params.Encode()) + endpoint := fmt.Sprintf("rest/agile/%v/board/%v/epic/%v/issue?%v", i.version, boardID, epicID, params.Encode()) - request, err := b.c.NewRequest(ctx, http.MethodGet, endpoint, nil) + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, nil) if err != nil { return nil, nil, err } - var issues model.BoardIssuePageScheme - response, err := b.c.Call(request, &issues) + page := new(model.BoardIssuePageScheme) + response, err := i.c.Call(request, page) if err != nil { return nil, response, err } - return &issues, response, nil + return page, response, nil } -func (b BoardService) Issues(ctx context.Context, boardId, startAt, maxResults int, opts *model.IssueOptionScheme) (*model.BoardIssuePageScheme, *model.ResponseScheme, error) { +func (i *internalBoardImpl) Issues(ctx context.Context, boardID int, opts *model.IssueOptionScheme, startAt, maxResults int) (*model.BoardIssuePageScheme, *model.ResponseScheme, error) { - if boardId == 0 { + if boardID == 0 { return nil, nil, model.ErrNoBoardIDError } @@ -317,41 +533,41 @@ func (b BoardService) Issues(ctx context.Context, boardId, startAt, maxResults i } - endpoint := fmt.Sprintf("/rest/agile/%v/board/%v/issue?%v", b.version, boardId, params.Encode()) + endpoint := fmt.Sprintf("rest/agile/%v/board/%v/issue?%v", i.version, boardID, params.Encode()) - request, err := b.c.NewRequest(ctx, http.MethodGet, endpoint, nil) + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, nil) if err != nil { return nil, nil, err } - var issues model.BoardIssuePageScheme - response, err := b.c.Call(request, &issues) + page := new(model.BoardIssuePageScheme) + response, err := i.c.Call(request, page) if err != nil { return nil, response, err } - return &issues, response, nil + return page, response, nil } -func (b BoardService) Move(ctx context.Context, boardId int, payload *model.BoardMovementPayloadScheme) (*model.ResponseScheme, error) { +func (i *internalBoardImpl) Move(ctx context.Context, boardID int, payload *model.BoardMovementPayloadScheme) (*model.ResponseScheme, error) { - if boardId == 0 { + if boardID == 0 { return nil, model.ErrNoBoardIDError } - reader, err := b.c.TransformStructToReader(payload) + reader, err := i.c.TransformStructToReader(payload) if err != nil { return nil, err } - endpoint := fmt.Sprintf("/rest/agile/%v/board/%v/issue", b.version, boardId) + endpoint := fmt.Sprintf("rest/agile/%v/board/%v/issue", i.version, boardID) - request, err := b.c.NewRequest(ctx, http.MethodPost, endpoint, reader) + request, err := i.c.NewRequest(ctx, http.MethodPost, endpoint, reader) if err != nil { return nil, err } - response, err := b.c.Call(request, nil) + response, err := i.c.Call(request, nil) if err != nil { return response, err } @@ -359,9 +575,9 @@ func (b BoardService) Move(ctx context.Context, boardId int, payload *model.Boar return response, nil } -func (b BoardService) Projects(ctx context.Context, boardId, startAt, maxResults int) (*model.BoardProjectPageScheme, *model.ResponseScheme, error) { +func (i *internalBoardImpl) Projects(ctx context.Context, boardID, startAt, maxResults int) (*model.BoardProjectPageScheme, *model.ResponseScheme, error) { - if boardId == 0 { + if boardID == 0 { return nil, nil, model.ErrNoBoardIDError } @@ -369,25 +585,25 @@ func (b BoardService) Projects(ctx context.Context, boardId, startAt, maxResults params.Add("startAt", strconv.Itoa(startAt)) params.Add("maxResults", strconv.Itoa(maxResults)) - endpoint := fmt.Sprintf("/rest/agile/%v/board/%v/project?%v", b.version, boardId, params.Encode()) + endpoint := fmt.Sprintf("rest/agile/%v/board/%v/project?%v", i.version, boardID, params.Encode()) - request, err := b.c.NewRequest(ctx, http.MethodGet, endpoint, nil) + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, nil) if err != nil { return nil, nil, err } - var projects model.BoardProjectPageScheme - response, err := b.c.Call(request, &projects) + page := new(model.BoardProjectPageScheme) + response, err := i.c.Call(request, page) if err != nil { return nil, response, err } - return &projects, response, nil + return page, response, nil } -func (b BoardService) Sprints(ctx context.Context, boardId, startAt, maxResults int, states []string) (*model.BoardSprintPageScheme, *model.ResponseScheme, error) { +func (i *internalBoardImpl) Sprints(ctx context.Context, boardID, startAt, maxResults int, states []string) (*model.BoardSprintPageScheme, *model.ResponseScheme, error) { - if boardId == 0 { + if boardID == 0 { return nil, nil, model.ErrNoBoardIDError } @@ -396,29 +612,29 @@ func (b BoardService) Sprints(ctx context.Context, boardId, startAt, maxResults params.Add("maxResults", strconv.Itoa(maxResults)) params.Add("state", strings.Join(states, ",")) - endpoint := fmt.Sprintf("/rest/agile/%v/board/%v/sprint?%v", b.version, boardId, params.Encode()) + endpoint := fmt.Sprintf("rest/agile/%v/board/%v/sprint?%v", i.version, boardID, params.Encode()) - request, err := b.c.NewRequest(ctx, http.MethodGet, endpoint, nil) + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, nil) if err != nil { return nil, nil, err } - var sprints model.BoardSprintPageScheme - response, err := b.c.Call(request, &sprints) + page := new(model.BoardSprintPageScheme) + response, err := i.c.Call(request, page) if err != nil { return nil, response, err } - return &sprints, response, nil + return page, response, nil } -func (b BoardService) IssuesBySprint(ctx context.Context, boardId, sprintId, startAt, maxResults int, opts *model.IssueOptionScheme) (*model.BoardIssuePageScheme, *model.ResponseScheme, error) { +func (i *internalBoardImpl) IssuesBySprint(ctx context.Context, boardID, sprintID int, opts *model.IssueOptionScheme, startAt, maxResults int) (*model.BoardIssuePageScheme, *model.ResponseScheme, error) { - if boardId == 0 { + if boardID == 0 { return nil, nil, model.ErrNoBoardIDError } - if sprintId == 0 { + if sprintID == 0 { return nil, nil, model.ErrNoSprintIDError } @@ -429,7 +645,7 @@ func (b BoardService) IssuesBySprint(ctx context.Context, boardId, sprintId, sta if opts != nil { if !opts.ValidateQuery { - params.Add("validateQuery ", "false") + params.Add("validateQuery", "false") } if len(opts.JQL) != 0 { @@ -445,25 +661,25 @@ func (b BoardService) IssuesBySprint(ctx context.Context, boardId, sprintId, sta } } - endpoint := fmt.Sprintf("/rest/agile/%v/board/%v/sprint/%v/issue?%v", b.version, boardId, sprintId, params.Encode()) + endpoint := fmt.Sprintf("rest/agile/%v/board/%v/sprint/%v/issue?%v", i.version, boardID, sprintID, params.Encode()) - request, err := b.c.NewRequest(ctx, http.MethodGet, endpoint, nil) + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, nil) if err != nil { return nil, nil, err } - var issues model.BoardIssuePageScheme - response, err := b.c.Call(request, &issues) + page := new(model.BoardIssuePageScheme) + response, err := i.c.Call(request, page) if err != nil { return nil, response, err } - return &issues, response, nil + return page, response, nil } -func (b BoardService) Versions(ctx context.Context, boardId, startAt, maxResults int, released bool) (*model.BoardVersionPageScheme, *model.ResponseScheme, error) { +func (i *internalBoardImpl) Versions(ctx context.Context, boardID, startAt, maxResults int, released bool) (*model.BoardVersionPageScheme, *model.ResponseScheme, error) { - if boardId == 0 { + if boardID == 0 { return nil, nil, model.ErrNoBoardIDError } @@ -472,36 +688,36 @@ func (b BoardService) Versions(ctx context.Context, boardId, startAt, maxResults params.Add("maxResults", strconv.Itoa(maxResults)) params.Add("released", fmt.Sprintf("%t", released)) - endpoint := fmt.Sprintf("/rest/agile/%v/board/%v/version?%v", b.version, boardId, params.Encode()) + endpoint := fmt.Sprintf("rest/agile/%v/board/%v/version?%v", i.version, boardID, params.Encode()) - request, err := b.c.NewRequest(ctx, http.MethodGet, endpoint, nil) + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, nil) if err != nil { return nil, nil, err } - var versions model.BoardVersionPageScheme - response, err := b.c.Call(request, &versions) + page := new(model.BoardVersionPageScheme) + response, err := i.c.Call(request, page) if err != nil { return nil, response, err } - return &versions, response, nil + return page, response, nil } -func (b BoardService) Delete(ctx context.Context, boardId int) (*model.ResponseScheme, error) { +func (i *internalBoardImpl) Delete(ctx context.Context, boardID int) (*model.ResponseScheme, error) { - if boardId == 0 { + if boardID == 0 { return nil, model.ErrNoBoardIDError } - endpoint := fmt.Sprintf("/rest/agile/%v/board/%v", b.version, boardId) + endpoint := fmt.Sprintf("rest/agile/%v/board/%v", i.version, boardID) - request, err := b.c.NewRequest(ctx, http.MethodDelete, endpoint, nil) + request, err := i.c.NewRequest(ctx, http.MethodDelete, endpoint, nil) if err != nil { return nil, err } - response, err := b.c.Call(request, nil) + response, err := i.c.Call(request, nil) if err != nil { return response, err } @@ -509,7 +725,7 @@ func (b BoardService) Delete(ctx context.Context, boardId int) (*model.ResponseS return response, nil } -func (b BoardService) Gets(ctx context.Context, opts *model.GetBoardsOptions, startAt, maxResults int) (*model.BoardPageScheme, *model.ResponseScheme, error) { +func (i *internalBoardImpl) Gets(ctx context.Context, opts *model.GetBoardsOptions, startAt, maxResults int) (*model.BoardPageScheme, *model.ResponseScheme, error) { params := url.Values{} params.Add("startAt", strconv.Itoa(startAt)) @@ -558,18 +774,18 @@ func (b BoardService) Gets(ctx context.Context, opts *model.GetBoardsOptions, st } } - endpoint := fmt.Sprintf("/rest/agile/%v/board?%v", b.version, params.Encode()) + endpoint := fmt.Sprintf("rest/agile/%v/board?%v", i.version, params.Encode()) - request, err := b.c.NewRequest(ctx, http.MethodGet, endpoint, nil) + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, nil) if err != nil { return nil, nil, err } - var boards model.BoardPageScheme - response, err := b.c.Call(request, &boards) + page := new(model.BoardPageScheme) + response, err := i.c.Call(request, page) if err != nil { return nil, response, err } - return &boards, response, nil + return page, response, nil } diff --git a/jira/agile/internal/board_impl_test.go b/jira/agile/internal/board_impl_test.go index dade08dc..2a7caf29 100644 --- a/jira/agile/internal/board_impl_test.go +++ b/jira/agile/internal/board_impl_test.go @@ -6,11 +6,9 @@ import ( "errors" model "github.com/ctreminiom/go-atlassian/pkg/infra/models" "github.com/ctreminiom/go-atlassian/service" - "github.com/ctreminiom/go-atlassian/service/agile" "github.com/ctreminiom/go-atlassian/service/mocks" "github.com/stretchr/testify/assert" "net/http" - "reflect" "testing" ) @@ -46,7 +44,7 @@ func Test_BoardService_Get(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1", + "rest/agile/1.0/board/1", nil). Return(&http.Request{}, nil) @@ -72,7 +70,7 @@ func Test_BoardService_Get(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1", + "rest/agile/1.0/board/1", nil). Return(&http.Request{}, nil) @@ -100,7 +98,7 @@ func Test_BoardService_Get(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1", + "rest/agile/1.0/board/1", nil). Return(&http.Request{}, errors.New("unable to create the http request")) @@ -179,7 +177,7 @@ func Test_BoardService_Create(t *testing.T) { args: args{ ctx: context.Background(), payload: &model.BoardPayloadScheme{ - Name: "Board Name Sample", + Name: "BoardConnector Name Sample", Type: "scrum", FilterID: 1002, }, @@ -190,7 +188,7 @@ func Test_BoardService_Create(t *testing.T) { client.On("TransformStructToReader", &model.BoardPayloadScheme{ - Name: "Board Name Sample", + Name: "BoardConnector Name Sample", Type: "scrum", FilterID: 1002, }). @@ -199,7 +197,7 @@ func Test_BoardService_Create(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodPost, - "/rest/agile/1.0/board", + "rest/agile/1.0/board", bytes.NewReader([]byte{})). Return(&http.Request{}, nil) @@ -217,7 +215,7 @@ func Test_BoardService_Create(t *testing.T) { args: args{ ctx: context.Background(), payload: &model.BoardPayloadScheme{ - Name: "Board Name Sample", + Name: "BoardConnector Name Sample", Type: "scrum", FilterID: 1002, }, @@ -228,7 +226,7 @@ func Test_BoardService_Create(t *testing.T) { client.On("TransformStructToReader", &model.BoardPayloadScheme{ - Name: "Board Name Sample", + Name: "BoardConnector Name Sample", Type: "scrum", FilterID: 1002, }). @@ -237,7 +235,7 @@ func Test_BoardService_Create(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodPost, - "/rest/agile/1.0/board", + "rest/agile/1.0/board", bytes.NewReader([]byte{})). Return(&http.Request{}, nil) @@ -257,7 +255,7 @@ func Test_BoardService_Create(t *testing.T) { args: args{ ctx: context.Background(), payload: &model.BoardPayloadScheme{ - Name: "Board Name Sample", + Name: "BoardConnector Name Sample", Type: "scrum", FilterID: 1002, }, @@ -268,7 +266,7 @@ func Test_BoardService_Create(t *testing.T) { client.On("TransformStructToReader", &model.BoardPayloadScheme{ - Name: "Board Name Sample", + Name: "BoardConnector Name Sample", Type: "scrum", FilterID: 1002, }). @@ -277,7 +275,7 @@ func Test_BoardService_Create(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodPost, - "/rest/agile/1.0/board", + "rest/agile/1.0/board", bytes.NewReader([]byte{})). Return(&http.Request{}, errors.New("unable to create the http request")) @@ -381,7 +379,7 @@ func Test_BoardService_Backlog(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1001/backlog?expand=changelogs+&fields=status%2Cdescription&jql=project+%3D+ACA&maxResults=50&startAt=0&validateQuery=true", + "rest/agile/1.0/board/1001/backlog?expand=changelogs+&fields=status%2Cdescription&jql=project+%3D+ACA&maxResults=50&startAt=0&validateQuery=true", nil). Return(&http.Request{}, nil) @@ -415,7 +413,7 @@ func Test_BoardService_Backlog(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1001/backlog?expand=changelogs+&fields=status%2Cdescription&jql=project+%3D+ACA&maxResults=50&startAt=0&validateQuery=true", + "rest/agile/1.0/board/1001/backlog?expand=changelogs+&fields=status%2Cdescription&jql=project+%3D+ACA&maxResults=50&startAt=0&validateQuery=true", nil). Return(&http.Request{}, nil) @@ -451,7 +449,7 @@ func Test_BoardService_Backlog(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1001/backlog?expand=changelogs+&fields=status%2Cdescription&jql=project+%3D+ACA&maxResults=50&startAt=0&validateQuery=true", + "rest/agile/1.0/board/1001/backlog?expand=changelogs+&fields=status%2Cdescription&jql=project+%3D+ACA&maxResults=50&startAt=0&validateQuery=true", nil). Return(&http.Request{}, errors.New("client: no http request created")) @@ -492,8 +490,8 @@ func Test_BoardService_Backlog(t *testing.T) { service, err := NewBoardService(testCase.fields.c, "1.0") assert.NoError(t, err) - gotResult, gotResponse, err := service.Backlog(testCase.args.ctx, testCase.args.boardId, testCase.args.startAt, - testCase.args.maxResults, testCase.args.opts) + gotResult, gotResponse, err := service.Backlog(testCase.args.ctx, testCase.args.boardId, testCase.args.opts, testCase.args.startAt, + testCase.args.maxResults) if testCase.wantErr { @@ -544,7 +542,7 @@ func Test_BoardService_Configuration(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1001/configuration", + "rest/agile/1.0/board/1001/configuration", nil). Return(&http.Request{}, nil) @@ -570,7 +568,7 @@ func Test_BoardService_Configuration(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1001/configuration", + "rest/agile/1.0/board/1001/configuration", nil). Return(&http.Request{}, nil) @@ -598,7 +596,7 @@ func Test_BoardService_Configuration(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1001/configuration", + "rest/agile/1.0/board/1001/configuration", nil). Return(&http.Request{}, errors.New("client: no http request created")) @@ -689,7 +687,7 @@ func Test_BoardService_Epics(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1001/epic?done=false&maxResults=50&startAt=0", + "rest/agile/1.0/board/1001/epic?done=false&maxResults=50&startAt=0", nil). Return(&http.Request{}, nil) @@ -718,7 +716,7 @@ func Test_BoardService_Epics(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1001/epic?done=false&maxResults=50&startAt=0", + "rest/agile/1.0/board/1001/epic?done=false&maxResults=50&startAt=0", nil). Return(&http.Request{}, nil) @@ -749,7 +747,7 @@ func Test_BoardService_Epics(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1001/epic?done=false&maxResults=50&startAt=0", + "rest/agile/1.0/board/1001/epic?done=false&maxResults=50&startAt=0", nil). Return(&http.Request{}, errors.New("client: no http request created")) @@ -835,7 +833,7 @@ func Test_BoardService_Delete(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodDelete, - "/rest/agile/1.0/board/1001", + "rest/agile/1.0/board/1001", nil). Return(&http.Request{}, nil) @@ -861,7 +859,7 @@ func Test_BoardService_Delete(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodDelete, - "/rest/agile/1.0/board/1001", + "rest/agile/1.0/board/1001", nil). Return(&http.Request{}, nil) @@ -889,7 +887,7 @@ func Test_BoardService_Delete(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodDelete, - "/rest/agile/1.0/board/1001", + "rest/agile/1.0/board/1001", nil). Return(&http.Request{}, errors.New("client: no http request created")) @@ -977,7 +975,7 @@ func Test_BoardService_Filter(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/filter/1001?maxResults=50&startAt=0", + "rest/agile/1.0/board/filter/1001?maxResults=50&startAt=0", nil). Return(&http.Request{}, nil) @@ -1005,7 +1003,7 @@ func Test_BoardService_Filter(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/filter/1001?maxResults=50&startAt=0", + "rest/agile/1.0/board/filter/1001?maxResults=50&startAt=0", nil). Return(&http.Request{}, nil) @@ -1035,7 +1033,7 @@ func Test_BoardService_Filter(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/filter/1001?maxResults=50&startAt=0", + "rest/agile/1.0/board/filter/1001?maxResults=50&startAt=0", nil). Return(&http.Request{}, errors.New("client: no http request created")) @@ -1124,7 +1122,7 @@ func Test_BoardService_Gets(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board?maxResults=50&startAt=0", + "rest/agile/1.0/board?maxResults=50&startAt=0", nil). Return(&http.Request{}, nil) @@ -1163,7 +1161,7 @@ func Test_BoardService_Gets(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board?accountIdLocation=uuid-sample&expand=issues&filterId=100&includePrivate=true&"+ + "rest/agile/1.0/board?accountIdLocation=uuid-sample&expand=issues&filterId=100&includePrivate=true&"+ "maxResults=50&name=Sample+Name&negateLocationFiltering=true&orderBy=issues&projectKeyOrId=DUMMY&proj"+ "ectLocation=uuid-sample&startAt=0&type=scrum", nil). @@ -1192,7 +1190,7 @@ func Test_BoardService_Gets(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board?maxResults=50&startAt=0", + "rest/agile/1.0/board?maxResults=50&startAt=0", nil). Return(&http.Request{}, nil) @@ -1221,7 +1219,7 @@ func Test_BoardService_Gets(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board?maxResults=50&startAt=0", + "rest/agile/1.0/board?maxResults=50&startAt=0", nil). Return(&http.Request{}, errors.New("client: no http request created")) @@ -1300,7 +1298,7 @@ func Test_BoardService_Issues(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/issue?maxResults=50&startAt=0", + "rest/agile/1.0/board/1000/issue?maxResults=50&startAt=0", nil). Return(&http.Request{}, nil) @@ -1334,7 +1332,7 @@ func Test_BoardService_Issues(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/issue?expand=orders&fields=fields&jql=project+%3D+DUMMY&maxResults=50&startAt=0", + "rest/agile/1.0/board/1000/issue?expand=orders&fields=fields&jql=project+%3D+DUMMY&maxResults=50&startAt=0", nil). Return(&http.Request{}, nil) @@ -1362,7 +1360,7 @@ func Test_BoardService_Issues(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/issue?maxResults=50&startAt=0", + "rest/agile/1.0/board/1000/issue?maxResults=50&startAt=0", nil). Return(&http.Request{}, nil) @@ -1392,7 +1390,7 @@ func Test_BoardService_Issues(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/issue?maxResults=50&startAt=0", + "rest/agile/1.0/board/1000/issue?maxResults=50&startAt=0", nil). Return(&http.Request{}, errors.New("client: no http request created")) @@ -1427,8 +1425,8 @@ func Test_BoardService_Issues(t *testing.T) { service, err := NewBoardService(testCase.fields.c, "1.0") assert.NoError(t, err) - gotResult, gotResponse, err := service.Issues(testCase.args.ctx, testCase.args.boardId, testCase.args.startAt, - testCase.args.maxResults, testCase.args.opts) + gotResult, gotResponse, err := service.Issues(testCase.args.ctx, testCase.args.boardId, testCase.args.opts, + testCase.args.startAt, testCase.args.maxResults) if testCase.wantErr { @@ -1487,7 +1485,7 @@ func Test_BoardService_IssuesByEpic(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/epic/102/issue?maxResults=50&startAt=0", + "rest/agile/1.0/board/1000/epic/102/issue?maxResults=50&startAt=0", nil). Return(&http.Request{}, nil) @@ -1522,7 +1520,7 @@ func Test_BoardService_IssuesByEpic(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/epic/102/issue?expand=orders&fields=fields&jql=project+%3D+DUMMY&maxResults=50&startAt=0", + "rest/agile/1.0/board/1000/epic/102/issue?expand=orders&fields=fields&jql=project+%3D+DUMMY&maxResults=50&startAt=0", nil). Return(&http.Request{}, nil) @@ -1551,7 +1549,7 @@ func Test_BoardService_IssuesByEpic(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/epic/102/issue?maxResults=50&startAt=0", + "rest/agile/1.0/board/1000/epic/102/issue?maxResults=50&startAt=0", nil). Return(&http.Request{}, nil) @@ -1582,7 +1580,7 @@ func Test_BoardService_IssuesByEpic(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/epic/102/issue?maxResults=50&startAt=0", + "rest/agile/1.0/board/1000/epic/102/issue?maxResults=50&startAt=0", nil). Return(&http.Request{}, errors.New("client: no http request created")) @@ -1633,8 +1631,7 @@ func Test_BoardService_IssuesByEpic(t *testing.T) { assert.NoError(t, err) gotResult, gotResponse, err := service.IssuesByEpic(testCase.args.ctx, testCase.args.boardId, testCase.args.epicId, - testCase.args.startAt, - testCase.args.maxResults, testCase.args.opts) + testCase.args.opts, testCase.args.startAt, testCase.args.maxResults) if testCase.wantErr { @@ -1693,7 +1690,7 @@ func Test_BoardService_IssuesBySprint(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/sprint/102/issue?maxResults=50&startAt=0", + "rest/agile/1.0/board/1000/sprint/102/issue?maxResults=50&startAt=0", nil). Return(&http.Request{}, nil) @@ -1728,7 +1725,7 @@ func Test_BoardService_IssuesBySprint(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/sprint/102/issue?expand=orders&fields=fields&jql=project+%3D+DUMMY&maxResults=50&startAt=0&validateQuery+=false", + "rest/agile/1.0/board/1000/sprint/102/issue?expand=orders&fields=fields&jql=project+%3D+DUMMY&maxResults=50&startAt=0&validateQuery=false", nil). Return(&http.Request{}, nil) @@ -1757,7 +1754,7 @@ func Test_BoardService_IssuesBySprint(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/sprint/102/issue?maxResults=50&startAt=0", + "rest/agile/1.0/board/1000/sprint/102/issue?maxResults=50&startAt=0", nil). Return(&http.Request{}, nil) @@ -1788,7 +1785,7 @@ func Test_BoardService_IssuesBySprint(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/sprint/102/issue?maxResults=50&startAt=0", + "rest/agile/1.0/board/1000/sprint/102/issue?maxResults=50&startAt=0", nil). Return(&http.Request{}, errors.New("client: no http request created")) @@ -1839,8 +1836,7 @@ func Test_BoardService_IssuesBySprint(t *testing.T) { assert.NoError(t, err) gotResult, gotResponse, err := service.IssuesBySprint(testCase.args.ctx, testCase.args.boardId, testCase.args.sprintId, - testCase.args.startAt, - testCase.args.maxResults, testCase.args.opts) + testCase.args.opts, testCase.args.startAt, testCase.args.maxResults) if testCase.wantErr { @@ -1897,7 +1893,7 @@ func Test_BoardService_IssuesWithoutEpic(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/epic/none/issue?maxResults=50&startAt=0", + "rest/agile/1.0/board/1000/epic/none/issue?maxResults=50&startAt=0", nil). Return(&http.Request{}, nil) @@ -1931,7 +1927,7 @@ func Test_BoardService_IssuesWithoutEpic(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/epic/none/issue?expand=orders&fields=fields&jql=project+%3D+DUMMY&maxResults=50&startAt=0&validateQuery=false", + "rest/agile/1.0/board/1000/epic/none/issue?expand=orders&fields=fields&jql=project+%3D+DUMMY&maxResults=50&startAt=0&validateQuery=false", nil). Return(&http.Request{}, nil) @@ -1959,7 +1955,7 @@ func Test_BoardService_IssuesWithoutEpic(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/epic/none/issue?maxResults=50&startAt=0", + "rest/agile/1.0/board/1000/epic/none/issue?maxResults=50&startAt=0", nil). Return(&http.Request{}, nil) @@ -1989,7 +1985,7 @@ func Test_BoardService_IssuesWithoutEpic(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/epic/none/issue?maxResults=50&startAt=0", + "rest/agile/1.0/board/1000/epic/none/issue?maxResults=50&startAt=0", nil). Return(&http.Request{}, errors.New("client: no http request created")) @@ -2024,8 +2020,8 @@ func Test_BoardService_IssuesWithoutEpic(t *testing.T) { service, err := NewBoardService(testCase.fields.c, "1.0") assert.NoError(t, err) - gotResult, gotResponse, err := service.IssuesWithoutEpic(testCase.args.ctx, testCase.args.boardId, testCase.args.startAt, - testCase.args.maxResults, testCase.args.opts) + gotResult, gotResponse, err := service.IssuesWithoutEpic(testCase.args.ctx, testCase.args.boardId, testCase.args.opts, + testCase.args.startAt, testCase.args.maxResults) if testCase.wantErr { @@ -2090,7 +2086,7 @@ func Test_BoardService_Move(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodPost, - "/rest/agile/1.0/board/1000/issue", + "rest/agile/1.0/board/1000/issue", bytes.NewReader([]byte{})). Return(&http.Request{}, nil) @@ -2128,7 +2124,7 @@ func Test_BoardService_Move(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodPost, - "/rest/agile/1.0/board/1000/issue", + "rest/agile/1.0/board/1000/issue", bytes.NewReader([]byte{})). Return(&http.Request{}, nil) @@ -2168,7 +2164,7 @@ func Test_BoardService_Move(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodPost, - "/rest/agile/1.0/board/1000/issue", + "rest/agile/1.0/board/1000/issue", bytes.NewReader([]byte{})). Return(&http.Request{}, errors.New("client: no http request created")) @@ -2260,7 +2256,7 @@ func Test_BoardService_Projects(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/project?maxResults=50&startAt=0", + "rest/agile/1.0/board/1000/project?maxResults=50&startAt=0", nil). Return(&http.Request{}, nil) @@ -2288,7 +2284,7 @@ func Test_BoardService_Projects(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/project?maxResults=50&startAt=0", + "rest/agile/1.0/board/1000/project?maxResults=50&startAt=0", nil). Return(&http.Request{}, nil) @@ -2318,7 +2314,7 @@ func Test_BoardService_Projects(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/project?maxResults=50&startAt=0", + "rest/agile/1.0/board/1000/project?maxResults=50&startAt=0", nil). Return(&http.Request{}, errors.New("client: no http request created")) @@ -2410,7 +2406,7 @@ func Test_BoardService_Sprints(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/sprint?maxResults=50&startAt=0&state=active", + "rest/agile/1.0/board/1000/sprint?maxResults=50&startAt=0&state=active", nil). Return(&http.Request{}, nil) @@ -2439,7 +2435,7 @@ func Test_BoardService_Sprints(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/sprint?maxResults=50&startAt=0&state=active", + "rest/agile/1.0/board/1000/sprint?maxResults=50&startAt=0&state=active", nil). Return(&http.Request{}, nil) @@ -2470,7 +2466,7 @@ func Test_BoardService_Sprints(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/sprint?maxResults=50&startAt=0&state=active", + "rest/agile/1.0/board/1000/sprint?maxResults=50&startAt=0&state=active", nil). Return(&http.Request{}, errors.New("client: no http request created")) @@ -2562,7 +2558,7 @@ func Test_BoardService_Versions(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/version?maxResults=50&released=true&startAt=0", + "rest/agile/1.0/board/1000/version?maxResults=50&released=true&startAt=0", nil). Return(&http.Request{}, nil) @@ -2591,7 +2587,7 @@ func Test_BoardService_Versions(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/version?maxResults=50&released=false&startAt=0", + "rest/agile/1.0/board/1000/version?maxResults=50&released=false&startAt=0", nil). Return(&http.Request{}, nil) @@ -2620,7 +2616,7 @@ func Test_BoardService_Versions(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/version?maxResults=50&released=true&startAt=0", + "rest/agile/1.0/board/1000/version?maxResults=50&released=true&startAt=0", nil). Return(&http.Request{}, nil) @@ -2651,7 +2647,7 @@ func Test_BoardService_Versions(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/board/1000/version?maxResults=50&released=true&startAt=0", + "rest/agile/1.0/board/1000/version?maxResults=50&released=true&startAt=0", nil). Return(&http.Request{}, errors.New("client: no http request created")) @@ -2706,44 +2702,3 @@ func Test_BoardService_Versions(t *testing.T) { }) } } - -func TestNewBoardService(t *testing.T) { - - type args struct { - client service.Client - version string - } - - testCases := []struct { - name string - args args - want agile.Board - wantErr bool - }{ - { - name: "when the agile version is not provided", - args: args{ - client: mocks.NewClient(t), - version: "", - }, - want: nil, - wantErr: true, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - - got, err := NewBoardService(testCase.args.client, testCase.args.version) - - if (err != nil) != testCase.wantErr { - t.Errorf("NewBoardService() error = %v, wantErr %v", err, testCase.wantErr) - return - } - - if !reflect.DeepEqual(got, testCase.want) { - t.Errorf("NewBoardService() got = %v, want %v", got, testCase.want) - } - }) - } -} diff --git a/jira/agile/internal/epic_impl.go b/jira/agile/internal/epic_impl.go index dd036375..5f8214c0 100644 --- a/jira/agile/internal/epic_impl.go +++ b/jira/agile/internal/epic_impl.go @@ -12,43 +12,93 @@ import ( "strings" ) -func NewEpicService(client service.Client, version string) (agile.Epic, error) { +func NewEpicService(client service.Client, version string) (*EpicService, error) { if version == "" { return nil, model.ErrNoVersionProvided } - return &EpicService{client, version}, nil + return &EpicService{ + internalClient: &internalEpicImpl{c: client, version: version}, + }, nil } type EpicService struct { + internalClient agile.EpicConnector +} + +// Get returns the epic for a given epic ID. +// +// This epic will only be returned if the user has permission to view it. +// +// Note: This operation does not work for epics in next-gen projects. +// +// GET /rest/agile/1.0/epic/{epicIdOrKey} +// +// https://docs.go-atlassian.io/jira-agile/epics#get-epic +func (e *EpicService) Get(ctx context.Context, epicIdOrKey string) (*model.EpicScheme, *model.ResponseScheme, error) { + return e.internalClient.Get(ctx, epicIdOrKey) +} + +// Issues returns all issues that belong to the epic, for the given epic ID. +// +// This only includes issues that the user has permission to view. +// +// Issues returned from this resource include Agile fields, like sprint, closedSprints, flagged, and epic. +// +// By default, the returned issues are ordered by rank. +// +// GET /rest/agile/1.0/epic/{epicIdOrKey}/issue +// +// https://docs.go-atlassian.io/jira-agile/epics#get-issues-for-epic +func (e *EpicService) Issues(ctx context.Context, epicIdOrKey string, opts *model.IssueOptionScheme, startAt, maxResults int) (*model.BoardIssuePageScheme, *model.ResponseScheme, error) { + return e.internalClient.Issues(ctx, epicIdOrKey, opts, startAt, maxResults) +} + +// Move moves issues to an epic, for a given epic id. +// +// Issues can be only in a single epic at the same time. +// That means that already assigned issues to an epic, will not be assigned to the previous epic anymore. +// +// The user needs to have the edit issue permission for all issue they want to move and to the epic. +// +// The maximum number of issues that can be moved in one operation is 50. +// +// POST /rest/agile/1.0/epic/{epicIdOrKey}/issue +// +// https://docs.go-atlassian.io/jira-agile/epics#move-issues-to-epic +func (e *EpicService) Move(ctx context.Context, epicIdOrKey string, issues []string) (*model.ResponseScheme, error) { + return e.internalClient.Move(ctx, epicIdOrKey, issues) +} + +type internalEpicImpl struct { c service.Client version string } -func (e EpicService) Get(ctx context.Context, epicIdOrKey string) (*model.EpicScheme, *model.ResponseScheme, error) { +func (i *internalEpicImpl) Get(ctx context.Context, epicIdOrKey string) (*model.EpicScheme, *model.ResponseScheme, error) { if epicIdOrKey == "" { return nil, nil, model.ErrNoEpicIDError } - endpoint := fmt.Sprintf("/rest/agile/%v/epic/%v", e.version, epicIdOrKey) + endpoint := fmt.Sprintf("rest/agile/%v/epic/%v", i.version, epicIdOrKey) - request, err := e.c.NewRequest(ctx, http.MethodGet, endpoint, nil) + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, nil) if err != nil { return nil, nil, err } - var epic model.EpicScheme - response, err := e.c.Call(request, &epic) + epic := new(model.EpicScheme) + response, err := i.c.Call(request, epic) if err != nil { return nil, response, err } - return &epic, response, nil + return epic, response, nil } -func (e EpicService) Issues(ctx context.Context, epicIdOrKey string, startAt, maxResults int, opts *model.IssueOptionScheme) (*model.BoardIssuePageScheme, *model.ResponseScheme, error) { +func (i *internalEpicImpl) Issues(ctx context.Context, epicIdOrKey string, opts *model.IssueOptionScheme, startAt, maxResults int) (*model.BoardIssuePageScheme, *model.ResponseScheme, error) { if epicIdOrKey == "" { return nil, nil, model.ErrNoEpicIDError @@ -75,44 +125,39 @@ func (e EpicService) Issues(ctx context.Context, epicIdOrKey string, startAt, ma } } - endpoint := fmt.Sprintf("/rest/agile/%v/epic/%v/issue?%v", e.version, epicIdOrKey, params.Encode()) + endpoint := fmt.Sprintf("rest/agile/%v/epic/%v/issue?%v", i.version, epicIdOrKey, params.Encode()) - request, err := e.c.NewRequest(ctx, http.MethodGet, endpoint, nil) + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, nil) if err != nil { return nil, nil, err } - var issues model.BoardIssuePageScheme - response, err := e.c.Call(request, &issues) + page := new(model.BoardIssuePageScheme) + response, err := i.c.Call(request, page) if err != nil { return nil, response, err } - return &issues, response, nil + return page, response, nil } -func (e EpicService) Move(ctx context.Context, epicIdOrKey string, issues []string) (*model.ResponseScheme, error) { +func (i *internalEpicImpl) Move(ctx context.Context, epicIdOrKey string, issues []string) (*model.ResponseScheme, error) { if epicIdOrKey == "" { return nil, model.ErrNoEpicIDError } - reader, err := e.c.TransformStructToReader(map[string]interface{}{"issues": issues}) + reader, err := i.c.TransformStructToReader(map[string]interface{}{"issues": issues}) if err != nil { return nil, err } - endpoint := fmt.Sprintf("/rest/agile/%v/epic/%v/issue", e.version, epicIdOrKey) + endpoint := fmt.Sprintf("rest/agile/%v/epic/%v/issue", i.version, epicIdOrKey) - request, err := e.c.NewRequest(ctx, http.MethodPost, endpoint, reader) + request, err := i.c.NewRequest(ctx, http.MethodPost, endpoint, reader) if err != nil { return nil, err } - response, err := e.c.Call(request, nil) - if err != nil { - return response, err - } - - return response, nil + return i.c.Call(request, nil) } diff --git a/jira/agile/internal/epic_impl_test.go b/jira/agile/internal/epic_impl_test.go index 29be121f..1c4a2b5c 100644 --- a/jira/agile/internal/epic_impl_test.go +++ b/jira/agile/internal/epic_impl_test.go @@ -6,11 +6,9 @@ import ( "errors" model "github.com/ctreminiom/go-atlassian/pkg/infra/models" "github.com/ctreminiom/go-atlassian/service" - "github.com/ctreminiom/go-atlassian/service/agile" "github.com/ctreminiom/go-atlassian/service/mocks" "github.com/stretchr/testify/assert" "net/http" - "reflect" "testing" ) @@ -46,7 +44,7 @@ func Test_EpicService_Get(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/epic/EPIC-1", + "rest/agile/1.0/epic/EPIC-1", nil). Return(&http.Request{}, nil) @@ -72,7 +70,7 @@ func Test_EpicService_Get(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/epic/EPIC-1", + "rest/agile/1.0/epic/EPIC-1", nil). Return(&http.Request{}, nil) @@ -100,7 +98,7 @@ func Test_EpicService_Get(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/epic/EPIC-1", + "rest/agile/1.0/epic/EPIC-1", nil). Return(&http.Request{}, errors.New("unable to create the http request")) @@ -198,7 +196,7 @@ func Test_EpicService_Issues(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/epic/EPIC-1/issue?expand=changelogs&fields=status%2Csummary&jql=project+%3D+EPIC&maxResults=50&startAt=10&validateQuery=true", + "rest/agile/1.0/epic/EPIC-1/issue?expand=changelogs&fields=status%2Csummary&jql=project+%3D+EPIC&maxResults=50&startAt=10&validateQuery=true", nil). Return(&http.Request{}, nil) @@ -232,7 +230,7 @@ func Test_EpicService_Issues(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/epic/EPIC-1/issue?expand=changelogs&fields=status%2Csummary&jql=project+%3D+EPIC&maxResults=50&startAt=10&validateQuery=true", + "rest/agile/1.0/epic/EPIC-1/issue?expand=changelogs&fields=status%2Csummary&jql=project+%3D+EPIC&maxResults=50&startAt=10&validateQuery=true", nil). Return(&http.Request{}, nil) @@ -268,7 +266,7 @@ func Test_EpicService_Issues(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodGet, - "/rest/agile/1.0/epic/EPIC-1/issue?expand=changelogs&fields=status%2Csummary&jql=project+%3D+EPIC&maxResults=50&startAt=10&validateQuery=true", + "rest/agile/1.0/epic/EPIC-1/issue?expand=changelogs&fields=status%2Csummary&jql=project+%3D+EPIC&maxResults=50&startAt=10&validateQuery=true", nil). Return(&http.Request{}, errors.New("unable to create the http request")) @@ -303,8 +301,8 @@ func Test_EpicService_Issues(t *testing.T) { service, err := NewEpicService(testCase.fields.c, "1.0") assert.NoError(t, err) - gotResult, gotResponse, err := service.Issues(testCase.args.ctx, testCase.args.epicIdOrKey, testCase.args.startAt, - testCase.args.maxResults, testCase.args.opts) + gotResult, gotResponse, err := service.Issues(testCase.args.ctx, testCase.args.epicIdOrKey, testCase.args.opts, + testCase.args.startAt, testCase.args.maxResults) if testCase.wantErr { @@ -362,7 +360,7 @@ func Test_EpicService_Move(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodPost, - "/rest/agile/1.0/epic/EPIC-1/issue", + "rest/agile/1.0/epic/EPIC-1/issue", bytes.NewReader([]byte{})). Return(&http.Request{}, nil) @@ -393,7 +391,7 @@ func Test_EpicService_Move(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodPost, - "/rest/agile/1.0/epic/EPIC-1/issue", + "rest/agile/1.0/epic/EPIC-1/issue", bytes.NewReader([]byte{})). Return(&http.Request{}, nil) @@ -426,7 +424,7 @@ func Test_EpicService_Move(t *testing.T) { client.On("NewRequest", context.Background(), http.MethodPost, - "/rest/agile/1.0/epic/EPIC-1/issue", + "rest/agile/1.0/epic/EPIC-1/issue", bytes.NewReader([]byte{})). Return(&http.Request{}, errors.New("unable to create the http request")) @@ -479,44 +477,3 @@ func Test_EpicService_Move(t *testing.T) { }) } } - -func TestNewEpicService(t *testing.T) { - - type args struct { - client service.Client - version string - } - - testCases := []struct { - name string - args args - want agile.Epic - wantErr bool - }{ - { - name: "when the agile version is not provided", - args: args{ - client: mocks.NewClient(t), - version: "", - }, - want: nil, - wantErr: true, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - - got, err := NewEpicService(testCase.args.client, testCase.args.version) - - if (err != nil) != testCase.wantErr { - t.Errorf("NewBoardService() error = %v, wantErr %v", err, testCase.wantErr) - return - } - - if !reflect.DeepEqual(got, testCase.want) { - t.Errorf("NewBoardService() got = %v, want %v", got, testCase.want) - } - }) - } -} diff --git a/jira/agile/internal/sprint_impl.go b/jira/agile/internal/sprint_impl.go index b7ada2dc..2942320f 100644 --- a/jira/agile/internal/sprint_impl.go +++ b/jira/agile/internal/sprint_impl.go @@ -12,139 +12,236 @@ import ( "strings" ) -func NewSprintService(client service.Client, version string) (agile.Sprint, error) { +func NewSprintService(client service.Client, version string) (*SprintService, error) { if version == "" { return nil, model.ErrNoVersionProvided } - return &SprintService{client, version}, nil + return &SprintService{ + internalClient: &internalSprintImpl{c: client, version: version}, + }, nil } type SprintService struct { + internalClient agile.SprintConnector +} + +// Get Returns the sprint for a given sprint ID. +// +// The sprint will only be returned if the user can view the board that the sprint was created on, +// +// or view at least one of the issues in the sprint. +// +// GET /rest/agile/1.0/sprint/{sprintId} +// +// https://docs.go-atlassian.io/jira-agile/sprints#get-sprint +func (s *SprintService) Get(ctx context.Context, sprintID int) (*model.SprintScheme, *model.ResponseScheme, error) { + return s.internalClient.Get(ctx, sprintID) +} + +// Create creates a future sprint. +// +// Sprint name and origin board id are required. +// +// Start date, end date, and goal are optional. +// +// POST /rest/agile/1.0/sprint +// +// https://docs.go-atlassian.io/jira-agile/sprints#create-print +func (s *SprintService) Create(ctx context.Context, payload *model.SprintPayloadScheme) (*model.SprintScheme, *model.ResponseScheme, error) { + return s.internalClient.Create(ctx, payload) +} + +// Update Performs a full update of a sprint. +// +// A full update means that the result will be exactly the same as the request body. +// +// Any fields not present in the request JSON will be set to null. +// +// PUT /rest/agile/1.0/sprint/{sprintId} +// +// https://docs.go-atlassian.io/jira-agile/sprints#update-sprint +func (s *SprintService) Update(ctx context.Context, sprintID int, payload *model.SprintPayloadScheme) (*model.SprintScheme, *model.ResponseScheme, error) { + return s.internalClient.Update(ctx, sprintID, payload) +} + +// Path Performs a partial update of a sprint. +// +// A partial update means that fields not present in the request JSON will not be updated. +// +// POST /rest/agile/1.0/sprint/{sprintId} +// +// https://docs.go-atlassian.io/jira-agile/sprints#partially-update-sprint +func (s *SprintService) Path(ctx context.Context, sprintID int, payload *model.SprintPayloadScheme) (*model.SprintScheme, *model.ResponseScheme, error) { + return s.internalClient.Path(ctx, sprintID, payload) +} + +// Delete deletes a sprint. +// +// Once a sprint is deleted, all open issues in the sprint will be moved to the backlog. +// +// DELETE /rest/agile/1.0/sprint/{sprintId} +// +// https://docs.go-atlassian.io/jira-agile/sprints#delete-sprint +func (s *SprintService) Delete(ctx context.Context, sprintID int) (*model.ResponseScheme, error) { + return s.internalClient.Delete(ctx, sprintID) +} + +// Issues returns all issues in a sprint, for a given sprint ID. +// +// This only includes issues that the user has permission to view. +// +// By default, the returned issues are ordered by rank. +// +// GET /rest/agile/1.0/sprint/{sprintId}/issue +// +// https://docs.go-atlassian.io/jira-agile/sprints#get-issues-for-sprint +func (s *SprintService) Issues(ctx context.Context, sprintID int, opts *model.IssueOptionScheme, startAt, maxResults int) (*model.SprintIssuePageScheme, *model.ResponseScheme, error) { + return s.internalClient.Issues(ctx, sprintID, opts, startAt, maxResults) +} + +// Start initiate the Sprint +// +// PUT /rest/agile/1.0/sprint/{sprintId} +// +// https://docs.go-atlassian.io/jira-agile/sprints#start-sprint +func (s *SprintService) Start(ctx context.Context, sprintID int) (*model.ResponseScheme, error) { + return s.internalClient.Start(ctx, sprintID) +} + +// Close closes the Sprint +// +// PUT /rest/agile/1.0/sprint/{sprintId} +// +// https://docs.go-atlassian.io/jira-agile/sprints#close-sprint +func (s *SprintService) Close(ctx context.Context, sprintID int) (*model.ResponseScheme, error) { + return s.internalClient.Close(ctx, sprintID) +} + +type internalSprintImpl struct { c service.Client version string } -func (s SprintService) Get(ctx context.Context, sprintId int) (*model.SprintScheme, *model.ResponseScheme, error) { +func (i *internalSprintImpl) Get(ctx context.Context, sprintID int) (*model.SprintScheme, *model.ResponseScheme, error) { - if sprintId == 0 { + if sprintID == 0 { return nil, nil, model.ErrNoSprintIDError } - endpoint := fmt.Sprintf("rest/agile/%v/sprint/%v", s.version, sprintId) + endpoint := fmt.Sprintf("rest/agile/%v/sprint/%v", i.version, sprintID) - request, err := s.c.NewRequest(ctx, http.MethodGet, endpoint, nil) + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, nil) if err != nil { return nil, nil, err } - var sprint model.SprintScheme - response, err := s.c.Call(request, &sprint) + sprint := new(model.SprintScheme) + response, err := i.c.Call(request, sprint) if err != nil { return nil, response, err } - return &sprint, response, nil + return sprint, response, nil } -func (s SprintService) Create(ctx context.Context, payload *model.SprintPayloadScheme) (*model.SprintScheme, *model.ResponseScheme, - error) { +func (i *internalSprintImpl) Create(ctx context.Context, payload *model.SprintPayloadScheme) (*model.SprintScheme, *model.ResponseScheme, error) { - reader, err := s.c.TransformStructToReader(payload) + reader, err := i.c.TransformStructToReader(payload) if err != nil { return nil, nil, err } - endpoint := fmt.Sprintf("rest/agile/%v/sprint", s.version) + endpoint := fmt.Sprintf("rest/agile/%v/sprint", i.version) - request, err := s.c.NewRequest(ctx, http.MethodPost, endpoint, reader) + request, err := i.c.NewRequest(ctx, http.MethodPost, endpoint, reader) if err != nil { return nil, nil, err } - var sprint model.SprintScheme - response, err := s.c.Call(request, &sprint) + sprint := new(model.SprintScheme) + response, err := i.c.Call(request, sprint) if err != nil { return nil, response, err } - return &sprint, response, nil + return sprint, response, nil } -func (s SprintService) Update(ctx context.Context, sprintId int, payload *model.SprintPayloadScheme) (*model.SprintScheme, - *model.ResponseScheme, error) { +func (i *internalSprintImpl) Update(ctx context.Context, sprintID int, payload *model.SprintPayloadScheme) (*model.SprintScheme, *model.ResponseScheme, error) { + + if sprintID == 0 { + return nil, nil, model.ErrNoSprintIDError + } - reader, err := s.c.TransformStructToReader(payload) + reader, err := i.c.TransformStructToReader(payload) if err != nil { return nil, nil, err } - endpoint := fmt.Sprintf("rest/agile/%v/sprint/%v", s.version, sprintId) + endpoint := fmt.Sprintf("rest/agile/%v/sprint/%v", i.version, sprintID) - request, err := s.c.NewRequest(ctx, http.MethodPut, endpoint, reader) + request, err := i.c.NewRequest(ctx, http.MethodPut, endpoint, reader) if err != nil { return nil, nil, err } - var sprint model.SprintScheme - response, err := s.c.Call(request, &sprint) + sprint := new(model.SprintScheme) + response, err := i.c.Call(request, sprint) if err != nil { return nil, response, err } - return &sprint, response, nil + return sprint, response, nil } -func (s SprintService) Path(ctx context.Context, sprintId int, payload *model.SprintPayloadScheme) (*model.SprintScheme, - *model.ResponseScheme, error) { +func (i *internalSprintImpl) Path(ctx context.Context, sprintID int, payload *model.SprintPayloadScheme) (*model.SprintScheme, *model.ResponseScheme, error) { - reader, err := s.c.TransformStructToReader(payload) + if sprintID == 0 { + return nil, nil, model.ErrNoSprintIDError + } + + reader, err := i.c.TransformStructToReader(payload) if err != nil { return nil, nil, err } - endpoint := fmt.Sprintf("rest/agile/%v/sprint/%v", s.version, sprintId) + endpoint := fmt.Sprintf("rest/agile/%v/sprint/%v", i.version, sprintID) - request, err := s.c.NewRequest(ctx, http.MethodPost, endpoint, reader) + request, err := i.c.NewRequest(ctx, http.MethodPost, endpoint, reader) if err != nil { return nil, nil, err } - var sprint model.SprintScheme - response, err := s.c.Call(request, &sprint) + sprint := new(model.SprintScheme) + response, err := i.c.Call(request, sprint) if err != nil { return nil, response, err } - return &sprint, response, nil + return sprint, response, nil } -func (s SprintService) Delete(ctx context.Context, sprintId int) (*model.ResponseScheme, error) { +func (i *internalSprintImpl) Delete(ctx context.Context, sprintID int) (*model.ResponseScheme, error) { - if sprintId == 0 { + if sprintID == 0 { return nil, model.ErrNoSprintIDError } - endpoint := fmt.Sprintf("rest/agile/%v/sprint/%v", s.version, sprintId) + endpoint := fmt.Sprintf("rest/agile/%v/sprint/%v", i.version, sprintID) - request, err := s.c.NewRequest(ctx, http.MethodDelete, endpoint, nil) + request, err := i.c.NewRequest(ctx, http.MethodDelete, endpoint, nil) if err != nil { return nil, err } - response, err := s.c.Call(request, nil) - if err != nil { - return response, err - } - - return response, nil + return i.c.Call(request, nil) } -func (s SprintService) Issues(ctx context.Context, sprintId int, opts *model.IssueOptionScheme, startAt, maxResults int) ( - *model.SprintIssuePageScheme, *model.ResponseScheme, error) { +func (i *internalSprintImpl) Issues(ctx context.Context, sprintID int, opts *model.IssueOptionScheme, startAt, maxResults int) (*model.SprintIssuePageScheme, *model.ResponseScheme, error) { - if sprintId == 0 { + if sprintID == 0 { return nil, nil, model.ErrNoSprintIDError } @@ -155,7 +252,7 @@ func (s SprintService) Issues(ctx context.Context, sprintId int, opts *model.Iss if opts != nil { if !opts.ValidateQuery { - params.Add("validateQuery ", "false") + params.Add("validateQuery", "false") } if len(opts.JQL) != 0 { @@ -171,25 +268,25 @@ func (s SprintService) Issues(ctx context.Context, sprintId int, opts *model.Iss } } - endpoint := fmt.Sprintf("rest/agile/%v/sprint/%v/issue?%v", s.version, sprintId, params.Encode()) + endpoint := fmt.Sprintf("rest/agile/%v/sprint/%v/issue?%v", i.version, sprintID, params.Encode()) - request, err := s.c.NewRequest(ctx, http.MethodGet, endpoint, nil) + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, nil) if err != nil { return nil, nil, err } - var issues model.SprintIssuePageScheme - response, err := s.c.Call(request, &issues) + page := new(model.SprintIssuePageScheme) + response, err := i.c.Call(request, page) if err != nil { return nil, response, err } - return &issues, response, nil + return page, response, nil } -func (s SprintService) Start(ctx context.Context, sprintId int) (*model.ResponseScheme, error) { +func (i *internalSprintImpl) Start(ctx context.Context, sprintID int) (*model.ResponseScheme, error) { - if sprintId == 0 { + if sprintID == 0 { return nil, model.ErrNoSprintIDError } @@ -197,29 +294,24 @@ func (s SprintService) Start(ctx context.Context, sprintId int) (*model.Response State: "Active", } - reader, err := s.c.TransformStructToReader(payload) + reader, err := i.c.TransformStructToReader(payload) if err != nil { return nil, err } - endpoint := fmt.Sprintf("rest/agile/%v/sprint/%v", s.version, sprintId) + endpoint := fmt.Sprintf("rest/agile/%v/sprint/%v", i.version, sprintID) - request, err := s.c.NewRequest(ctx, http.MethodPost, endpoint, reader) + request, err := i.c.NewRequest(ctx, http.MethodPost, endpoint, reader) if err != nil { return nil, err } - response, err := s.c.Call(request, nil) - if err != nil { - return response, err - } - - return response, nil + return i.c.Call(request, nil) } -func (s SprintService) Close(ctx context.Context, sprintId int) (*model.ResponseScheme, error) { +func (i *internalSprintImpl) Close(ctx context.Context, sprintID int) (*model.ResponseScheme, error) { - if sprintId == 0 { + if sprintID == 0 { return nil, model.ErrNoSprintIDError } @@ -227,22 +319,17 @@ func (s SprintService) Close(ctx context.Context, sprintId int) (*model.Response State: "Closed", } - reader, err := s.c.TransformStructToReader(payload) + reader, err := i.c.TransformStructToReader(payload) if err != nil { return nil, err } - endpoint := fmt.Sprintf("rest/agile/%v/sprint/%v", s.version, sprintId) + endpoint := fmt.Sprintf("rest/agile/%v/sprint/%v", i.version, sprintID) - request, err := s.c.NewRequest(ctx, http.MethodPost, endpoint, reader) + request, err := i.c.NewRequest(ctx, http.MethodPost, endpoint, reader) if err != nil { return nil, err } - response, err := s.c.Call(request, nil) - if err != nil { - return response, err - } - - return response, nil + return i.c.Call(request, nil) } diff --git a/jira/v2/api_client_impl.go b/jira/v2/api_client_impl.go index b8c50596..43489f12 100644 --- a/jira/v2/api_client_impl.go +++ b/jira/v2/api_client_impl.go @@ -4,11 +4,9 @@ import ( "bytes" "context" "encoding/json" - "errors" "github.com/ctreminiom/go-atlassian/jira/internal" "github.com/ctreminiom/go-atlassian/pkg/infra/models" "github.com/ctreminiom/go-atlassian/service/common" - "github.com/ctreminiom/go-atlassian/service/jira" "io" "io/ioutil" "net/http" @@ -355,10 +353,10 @@ func New(httpClient common.HttpClient, site string) (*Client, error) { type Client struct { HTTP common.HttpClient - Site *url.URL Auth common.Authentication - Role jira.AppRoleConnector - Dashboard jira.DashboardConnector + Site *url.URL + Role *internal.ApplicationRoleService + Dashboard *internal.DashboardService Filter *internal.FilterService Group *internal.GroupService Issue *internal.IssueRichTextService @@ -435,11 +433,15 @@ func (c *Client) NewRequest(ctx context.Context, method, apiEndpoint string, pay func (c *Client) Call(request *http.Request, structure interface{}) (*models.ResponseScheme, error) { response, err := c.HTTP.Do(request) - if err != nil { return nil, err } + return c.TransformTheHTTPResponse(response, structure) +} + +func (c *Client) TransformTheHTTPResponse(response *http.Response, structure interface{}) (*models.ResponseScheme, error) { + responseTransformed := &models.ResponseScheme{ Response: response, Code: response.StatusCode, @@ -447,49 +449,16 @@ func (c *Client) Call(request *http.Request, structure interface{}) (*models.Res Method: response.Request.Method, } - if !(response.StatusCode >= 200 && response.StatusCode < 300) { - return responseTransformed, models.ErrInvalidStatusCodeError - } - responseAsBytes, err := ioutil.ReadAll(response.Body) if err != nil { return responseTransformed, err } - if structure != nil { - if err = json.Unmarshal(responseAsBytes, &structure); err != nil { - return responseTransformed, err - } - } - - _, err = responseTransformed.Bytes.Write(responseAsBytes) - if err != nil { - return nil, err - } - - return responseTransformed, nil -} - -func (c *Client) TransformTheHTTPResponse(response *http.Response, structure interface{}) (*models.ResponseScheme, error) { - - if response == nil { - return nil, errors.New("validation failed, please provide a http.Response pointer") - } - - responseTransformed := &models.ResponseScheme{} - responseTransformed.Code = response.StatusCode - responseTransformed.Endpoint = response.Request.URL.String() - responseTransformed.Method = response.Request.Method + responseTransformed.Bytes.Write(responseAsBytes) var wasSuccess = response.StatusCode >= 200 && response.StatusCode < 300 if !wasSuccess { - - return responseTransformed, errors.New("TODO") - } - - responseAsBytes, err := ioutil.ReadAll(response.Body) - if err != nil { - return responseTransformed, err + return responseTransformed, models.ErrInvalidStatusCodeError } if structure != nil { @@ -498,7 +467,6 @@ func (c *Client) TransformTheHTTPResponse(response *http.Response, structure int } } - responseTransformed.Bytes.Write(responseAsBytes) return responseTransformed, nil } diff --git a/jira/v2/api_client_impl_test.go b/jira/v2/api_client_impl_test.go index 6571dc05..1ea3a70d 100644 --- a/jira/v2/api_client_impl_test.go +++ b/jira/v2/api_client_impl_test.go @@ -279,17 +279,6 @@ func TestClient_TransformTheHTTPResponse(t *testing.T) { }, wantErr: false, }, - - { - name: "when the payload is not provided", - fields: fields{}, - args: args{ - response: nil, - structure: models.BoardScheme{}, - }, - wantErr: true, - Err: errors.New("validation failed, please provide a http.Response pointer"), - }, } for _, testCase := range testCases { diff --git a/jira/v3/api_client_impl.go b/jira/v3/api_client_impl.go index 7c405756..7b1ccb3a 100644 --- a/jira/v3/api_client_impl.go +++ b/jira/v3/api_client_impl.go @@ -4,11 +4,9 @@ import ( "bytes" "context" "encoding/json" - "errors" "github.com/ctreminiom/go-atlassian/jira/internal" "github.com/ctreminiom/go-atlassian/pkg/infra/models" "github.com/ctreminiom/go-atlassian/service/common" - "github.com/ctreminiom/go-atlassian/service/jira" "io" "io/ioutil" "net/http" @@ -355,10 +353,10 @@ func New(httpClient common.HttpClient, site string) (*Client, error) { type Client struct { HTTP common.HttpClient - Site *url.URL Auth common.Authentication - Role jira.AppRoleConnector - Dashboard jira.DashboardConnector + Site *url.URL + Role *internal.ApplicationRoleService + Dashboard *internal.DashboardService Filter *internal.FilterService Group *internal.GroupService Issue *internal.IssueADFService @@ -435,11 +433,15 @@ func (c *Client) NewRequest(ctx context.Context, method, apiEndpoint string, pay func (c *Client) Call(request *http.Request, structure interface{}) (*models.ResponseScheme, error) { response, err := c.HTTP.Do(request) - if err != nil { return nil, err } + return c.TransformTheHTTPResponse(response, structure) +} + +func (c *Client) TransformTheHTTPResponse(response *http.Response, structure interface{}) (*models.ResponseScheme, error) { + responseTransformed := &models.ResponseScheme{ Response: response, Code: response.StatusCode, @@ -447,49 +449,16 @@ func (c *Client) Call(request *http.Request, structure interface{}) (*models.Res Method: response.Request.Method, } - if !(response.StatusCode >= 200 && response.StatusCode < 300) { - return responseTransformed, models.ErrInvalidStatusCodeError - } - responseAsBytes, err := ioutil.ReadAll(response.Body) if err != nil { return responseTransformed, err } - if structure != nil { - if err = json.Unmarshal(responseAsBytes, &structure); err != nil { - return responseTransformed, err - } - } - - _, err = responseTransformed.Bytes.Write(responseAsBytes) - if err != nil { - return nil, err - } - - return responseTransformed, nil -} - -func (c *Client) TransformTheHTTPResponse(response *http.Response, structure interface{}) (*models.ResponseScheme, error) { - - if response == nil { - return nil, errors.New("validation failed, please provide a http.Response pointer") - } - - responseTransformed := &models.ResponseScheme{} - responseTransformed.Code = response.StatusCode - responseTransformed.Endpoint = response.Request.URL.String() - responseTransformed.Method = response.Request.Method + responseTransformed.Bytes.Write(responseAsBytes) var wasSuccess = response.StatusCode >= 200 && response.StatusCode < 300 if !wasSuccess { - - return responseTransformed, errors.New("TODO") - } - - responseAsBytes, err := ioutil.ReadAll(response.Body) - if err != nil { - return responseTransformed, err + return responseTransformed, models.ErrInvalidStatusCodeError } if structure != nil { @@ -498,7 +467,6 @@ func (c *Client) TransformTheHTTPResponse(response *http.Response, structure int } } - responseTransformed.Bytes.Write(responseAsBytes) return responseTransformed, nil } diff --git a/jira/v3/api_client_impl_test.go b/jira/v3/api_client_impl_test.go index aded8d5e..d07802ab 100644 --- a/jira/v3/api_client_impl_test.go +++ b/jira/v3/api_client_impl_test.go @@ -279,17 +279,6 @@ func TestClient_TransformTheHTTPResponse(t *testing.T) { }, wantErr: false, }, - - { - name: "when the payload is not provided", - fields: fields{}, - args: args{ - response: nil, - structure: models.BoardScheme{}, - }, - wantErr: true, - Err: errors.New("validation failed, please provide a http.Response pointer"), - }, } for _, testCase := range testCases { diff --git a/service/agile/board.go b/service/agile/board.go index c55479e8..6623a3ff 100644 --- a/service/agile/board.go +++ b/service/agile/board.go @@ -5,112 +5,196 @@ import ( model "github.com/ctreminiom/go-atlassian/pkg/infra/models" ) -type Board interface { +// BoardConnector represents the Jira boards. +// Use it to search, get, create, delete, and change boards. +type BoardConnector interface { // Get returns the board for the given board ID. // This board will only be returned if the user has permission to view it. + // + // // Admins without the view permission will see the board as a private one, + // // so will see only a subset of the board's data (board location for instance). - // Docs: https://docs.go-atlassian.io/jira-agile/boards#get-board - Get(ctx context.Context, boardId int) (*model.BoardScheme, *model.ResponseScheme, error) + // + // GET /rest/agile/1.0/board/{boardId} + // + // https://docs.go-atlassian.io/jira-agile/boards#get-board + Get(ctx context.Context, boardID int) (*model.BoardScheme, *model.ResponseScheme, error) // Create creates a new board. Board name, type and filter ID is required. + // + // POST /rest/agile/1.0/board + // // Docs: https://docs.go-atlassian.io/jira-agile/boards#create-board Create(ctx context.Context, payload *model.BoardPayloadScheme) (*model.BoardScheme, *model.ResponseScheme, error) // Filter returns any boards which use the provided filter id. + // // This method can be executed by users without a valid software license in order + // // to find which boards are using a particular filter. - // Docs: https://docs.go-atlassian.io/jira-agile/boards#get-board-by-filter-id - Filter(ctx context.Context, filterId, startAt, maxResults int) (*model.BoardPageScheme, *model.ResponseScheme, error) + // + // GET /rest/agile/1.0/board/filter/{filterId} + // + // https://docs.go-atlassian.io/jira-agile/boards#get-board-by-filter-id + Filter(ctx context.Context, filterID, startAt, maxResults int) (*model.BoardPageScheme, *model.ResponseScheme, error) // Backlog returns all issues from the board's backlog, for the given board ID. + // // This only includes issues that the user has permission to view. + // // The backlog contains incomplete issues that are not assigned to any future or active sprint. + // // Note, if the user does not have permission to view the board, no issues will be returned at all. + // // Issues returned from this resource include Agile fields, like sprint, closedSprints, flagged, and epic. + // // By default, the returned issues are ordered by rank. - // Docs: https://docs.go-atlassian.io/jira-agile/boards#get-issues-for-backlog - Backlog(ctx context.Context, boardId, startAt, maxResults int, opts *model.IssueOptionScheme) ( - *model.BoardIssuePageScheme, *model.ResponseScheme, error) + // + // GET /rest/agile/1.0/board/{boardId}/backlog + // + // https://docs.go-atlassian.io/jira-agile/boards#get-issues-for-backlog + Backlog(ctx context.Context, boardID int, opts *model.IssueOptionScheme, startAt, maxResults int) (*model.BoardIssuePageScheme, *model.ResponseScheme, error) // Configuration get the board configuration. - // Docs: https://docs.go-atlassian.io/jira-agile/boards#get-configuration - Configuration(ctx context.Context, boardId int) (*model.BoardConfigurationScheme, *model.ResponseScheme, error) + // + // GET /rest/agile/1.0/board/{boardId}/configuration + // + // https://docs.go-atlassian.io/jira-agile/boards#get-configuration + Configuration(ctx context.Context, boardID int) (*model.BoardConfigurationScheme, *model.ResponseScheme, error) // Epics returns all epics from the board, for the given board ID. + // // This only includes epics that the user has permission to view. + // // Note, if the user does not have permission to view the board, no epics will be returned at all. - // Docs: https://docs.go-atlassian.io/jira-agile/boards#get-epics - Epics(ctx context.Context, boardId, startAt, maxResults int, done bool) (*model.BoardEpicPageScheme, *model.ResponseScheme, error) + // + // GET /rest/agile/1.0/board/{boardId}/epic + // + // https://docs.go-atlassian.io/jira-agile/boards#get-epics + Epics(ctx context.Context, boardID, startAt, maxResults int, done bool) (*model.BoardEpicPageScheme, *model.ResponseScheme, error) // IssuesWithoutEpic returns all issues that do not belong to any epic on a board, for a given board ID. + // // This only includes issues that the user has permission to view. + // // Issues returned from this resource include Agile fields, like sprint, closedSprints, flagged, and epic. + // // By default, the returned issues are ordered by rank. + // + // GET /rest/agile/1.0/board/{boardId}/epic/none/issue + // // Docs: https://docs.go-atlassian.io/jira-agile/boards#get-issues-without-epic-for-board - IssuesWithoutEpic(ctx context.Context, boardId, startAt, maxResults int, opts *model.IssueOptionScheme) ( + IssuesWithoutEpic(ctx context.Context, boardID int, opts *model.IssueOptionScheme, startAt, maxResults int) ( *model.BoardIssuePageScheme, *model.ResponseScheme, error) // IssuesByEpic returns all issues that belong to an epic on the board, for the given epic ID and the board ID. + // // This only includes issues that the user has permission to view. + // // Issues returned from this resource include Agile fields, like sprint, closedSprints, + // // flagged, and epic. By default, the returned issues are ordered by rank. - // Docs: https://docs.go-atlassian.io/jira-agile/boards#get-board-issues-for-epic - IssuesByEpic(ctx context.Context, boardId, epicId, startAt, maxResults int, opts *model.IssueOptionScheme) ( + // + // GET /rest/agile/1.0/board/{boardId}/epic/none/issue + // + // https://docs.go-atlassian.io/jira-agile/boards#get-board-issues-for-epic + IssuesByEpic(ctx context.Context, boardID, epicID int, opts *model.IssueOptionScheme, startAt, maxResults int) ( *model.BoardIssuePageScheme, *model.ResponseScheme, error) // Issues returns all issues from a board, for a given board ID. + // // This only includes issues that the user has permission to view. + // // An issue belongs to the board if its status is mapped to the board's column. + // // Epic issues do not belong to the scrum boards. Note, if the user does not have permission to view the board, + // // no issues will be returned at all. + // // Issues returned from this resource include Agile fields, like sprint, closedSprints, flagged, and epic. + // // By default, the returned issues are ordered by rank. - // Docs: https://docs.go-atlassian.io/jira-agile/boards#get-issues-for-board - Issues(ctx context.Context, boardId, startAt, maxResults int, opts *model.IssueOptionScheme) (*model.BoardIssuePageScheme, + // + // GET /rest/agile/1.0/board/{boardId}/issue + // + // https://docs.go-atlassian.io/jira-agile/boards#get-issues-for-board + Issues(ctx context.Context, boardID int, opts *model.IssueOptionScheme, startAt, maxResults int) (*model.BoardIssuePageScheme, *model.ResponseScheme, error) // Move issues from the backlog to the board (if they are already in the backlog of that board). + // // This operation either moves an issue(s) onto a board from the backlog (by adding it to the issueList for the board) + // // Or transitions the issue(s) to the first column for a kanban board with backlog. + // // At most 50 issues may be moved at once. - // Docs: https://docs.go-atlassian.io/jira-agile/boards#move-issues-to-backlog-for-board - Move(ctx context.Context, boardId int, payload *model.BoardMovementPayloadScheme) (*model.ResponseScheme, error) + // + // POST /rest/agile/1.0/board/{boardId}/issue + // + // https://docs.go-atlassian.io/jira-agile/boards#move-issues-to-backlog-for-board + Move(ctx context.Context, boardID int, payload *model.BoardMovementPayloadScheme) (*model.ResponseScheme, error) // Projects returns all projects that are associated with the board, for the given board ID. + // // If the user does not have permission to view the board, no projects will be returned at all. + // // Returned projects are ordered by the name. - // Docs: https://docs.go-atlassian.io/jira-agile/boards#get-projects - Projects(ctx context.Context, boardId, startAt, maxResults int) (*model.BoardProjectPageScheme, *model.ResponseScheme, error) + // + // GET /rest/agile/1.0/board/{boardId}/project + // + // https://docs.go-atlassian.io/jira-agile/boards#get-projects + Projects(ctx context.Context, boardID, startAt, maxResults int) (*model.BoardProjectPageScheme, *model.ResponseScheme, error) // Sprints returns all sprints from a board, for a given board ID. + // // This only includes sprints that the user has permission to view. - // Docs: https://docs.go-atlassian.io/jira-agile/boards#get-all-sprints - Sprints(ctx context.Context, boardId, startAt, maxResults int, states []string) (*model.BoardSprintPageScheme, + // + // GET /rest/agile/1.0/board/{boardId}/sprint + // + // https://docs.go-atlassian.io/jira-agile/boards#get-all-sprints + Sprints(ctx context.Context, boardID, startAt, maxResults int, states []string) (*model.BoardSprintPageScheme, *model.ResponseScheme, error) // IssuesBySprint get all issues you have access to that belong to the sprint from the board. + // // Issue returned from this resource contains additional fields like: sprint, closedSprints, flagged and epic. + // // Issues are returned ordered by rank. JQL order has higher priority than default rank. - // Docs: https://docs.go-atlassian.io/jira-agile/boards#get-board-issues-for-sprint - IssuesBySprint(ctx context.Context, boardId, sprintId, startAt, maxResults int, opts *model.IssueOptionScheme) ( + // + // GET /rest/agile/1.0/board/{boardId}/sprint/{sprintId}/issue + // + // https://docs.go-atlassian.io/jira-agile/boards#get-board-issues-for-sprint + IssuesBySprint(ctx context.Context, boardID, sprintID int, opts *model.IssueOptionScheme, startAt, maxResults int) ( *model.BoardIssuePageScheme, *model.ResponseScheme, error) // Versions returns all versions from a board, for a given board ID. + // // This only includes versions that the user has permission to view. + // // Note, if the user does not have permission to view the board, no versions will be returned at all. + // // Returned versions are ordered by the name of the project from which they belong and then by sequence defined by user. - // Docs: https://docs.go-atlassian.io/jira-agile/boards#get-all-versions - Versions(ctx context.Context, boardId, startAt, maxResults int, released bool) (*model.BoardVersionPageScheme, + // + // GET /rest/agile/1.0/board/{boardId}/sprint/{sprintId}/issue + // + // https://docs.go-atlassian.io/jira-agile/boards#get-all-versions + Versions(ctx context.Context, boardID, startAt, maxResults int, released bool) (*model.BoardVersionPageScheme, *model.ResponseScheme, error) // Delete deletes the board. Admin without the view permission can still remove the board. - // Docs: N/A - Delete(ctx context.Context, boardId int) (*model.ResponseScheme, error) + // + // DELETE /rest/agile/1.0/board/{boardId} + // + // https://docs.go-atlassian.io/jira-agile/boards#delete-board + Delete(ctx context.Context, boardID int) (*model.ResponseScheme, error) // Gets returns all boards. This only includes boards that the user has permission to view. - // Docs: N/A + // + // GET /rest/agile/1.0/board + // + // https://docs.go-atlassian.io/jira-agile/boards#get-boards Gets(ctx context.Context, opts *model.GetBoardsOptions, startAt, maxResults int) (*model.BoardPageScheme, *model.ResponseScheme, error) } diff --git a/service/agile/epic.go b/service/agile/epic.go index 6fc6d006..1d3f14d6 100644 --- a/service/agile/epic.go +++ b/service/agile/epic.go @@ -5,28 +5,44 @@ import ( model "github.com/ctreminiom/go-atlassian/pkg/infra/models" ) -type Epic interface { +type EpicConnector interface { // Get returns the epic for a given epic ID. + // // This epic will only be returned if the user has permission to view it. + // // Note: This operation does not work for epics in next-gen projects. - // Docs: https://docs.go-atlassian.io/jira-agile/epics#get-epic + // + // GET /rest/agile/1.0/epic/{epicIdOrKey} + // + // https://docs.go-atlassian.io/jira-agile/epics#get-epic Get(ctx context.Context, epicIdOrKey string) (*model.EpicScheme, *model.ResponseScheme, error) // Issues returns all issues that belong to the epic, for the given epic ID. + // // This only includes issues that the user has permission to view. - // Issues returned from this resource include Agile fields, like sprint, closedSprints, - // flagged, and epic. + // + // Issues returned from this resource include Agile fields, like sprint, closedSprints, flagged, and epic. + // // By default, the returned issues are ordered by rank. - // Docs: https://docs.go-atlassian.io/jira-agile/epics#get-issues-for-epic - Issues(ctx context.Context, epicIdOrKey string, startAt, maxResults int, opts *model.IssueOptionScheme) (*model.BoardIssuePageScheme, + // + // GET /rest/agile/1.0/epic/{epicIdOrKey}/issue + // + // https://docs.go-atlassian.io/jira-agile/epics#get-issues-for-epic + Issues(ctx context.Context, epicIdOrKey string, opts *model.IssueOptionScheme, startAt, maxResults int) (*model.BoardIssuePageScheme, *model.ResponseScheme, error) // Move moves issues to an epic, for a given epic id. + // // Issues can be only in a single epic at the same time. // That means that already assigned issues to an epic, will not be assigned to the previous epic anymore. + // // The user needs to have the edit issue permission for all issue they want to move and to the epic. + // // The maximum number of issues that can be moved in one operation is 50. - // Docs: TODO: The documentation needs to be created, raise a ticket here: https://github.com/ctreminiom/go-atlassian/issues + // + // POST /rest/agile/1.0/epic/{epicIdOrKey}/issue + // + // https://docs.go-atlassian.io/jira-agile/epics#move-issues-to-epic Move(ctx context.Context, epicIdOrKey string, issues []string) (*model.ResponseScheme, error) } diff --git a/service/agile/sprint.go b/service/agile/sprint.go index 7607e85c..e80d585e 100644 --- a/service/agile/sprint.go +++ b/service/agile/sprint.go @@ -5,49 +5,81 @@ import ( "github.com/ctreminiom/go-atlassian/pkg/infra/models" ) -type Sprint interface { +type SprintConnector interface { // Get Returns the sprint for a given sprint ID. + // // The sprint will only be returned if the user can view the board that the sprint was created on, + // // or view at least one of the issues in the sprint. - // Docs: https://docs.go-atlassian.io/jira-agile/sprints#get-sprint - Get(ctx context.Context, sprintId int) (*models.SprintScheme, *models.ResponseScheme, error) + // + // GET /rest/agile/1.0/sprint/{sprintId} + // + // https://docs.go-atlassian.io/jira-agile/sprints#get-sprint + Get(ctx context.Context, sprintID int) (*models.SprintScheme, *models.ResponseScheme, error) // Create creates a future sprint. + // // Sprint name and origin board id are required. + // // Start date, end date, and goal are optional. - // Docs: https://docs.go-atlassian.io/jira-agile/sprints#create-print + // + // POST /rest/agile/1.0/sprint + // + // https://docs.go-atlassian.io/jira-agile/sprints#create-print Create(ctx context.Context, payload *models.SprintPayloadScheme) (*models.SprintScheme, *models.ResponseScheme, error) // Update Performs a full update of a sprint. + // // A full update means that the result will be exactly the same as the request body. + // // Any fields not present in the request JSON will be set to null. - // Docs: https://docs.go-atlassian.io/jira-agile/sprints#update-sprint - Update(ctx context.Context, sprintId int, payload *models.SprintPayloadScheme) (*models.SprintScheme, *models.ResponseScheme, - error) + // + // PUT /rest/agile/1.0/sprint/{sprintId} + // + // https://docs.go-atlassian.io/jira-agile/sprints#update-sprint + Update(ctx context.Context, sprintID int, payload *models.SprintPayloadScheme) (*models.SprintScheme, *models.ResponseScheme, error) // Path Performs a partial update of a sprint. + // // A partial update means that fields not present in the request JSON will not be updated. - // Docs: https://docs.go-atlassian.io/jira-agile/sprints#partially-update-sprint - Path(ctx context.Context, sprintId int, payload *models.SprintPayloadScheme) (*models.SprintScheme, *models.ResponseScheme, - error) + // + // POST /rest/agile/1.0/sprint/{sprintId} + // + // https://docs.go-atlassian.io/jira-agile/sprints#partially-update-sprint + Path(ctx context.Context, sprintID int, payload *models.SprintPayloadScheme) (*models.SprintScheme, *models.ResponseScheme, error) // Delete deletes a sprint. + // // Once a sprint is deleted, all open issues in the sprint will be moved to the backlog. - Delete(ctx context.Context, sprintId int) (*models.ResponseScheme, error) + // + // DELETE /rest/agile/1.0/sprint/{sprintId} + // + // https://docs.go-atlassian.io/jira-agile/sprints#delete-sprint + Delete(ctx context.Context, sprintID int) (*models.ResponseScheme, error) // Issues returns all issues in a sprint, for a given sprint ID. + // // This only includes issues that the user has permission to view. + // // By default, the returned issues are ordered by rank. - // Docs: https://docs.go-atlassian.io/jira-agile/sprints#get-issues-for-sprint - Issues(ctx context.Context, sprintId int, opts *models.IssueOptionScheme, startAt, maxResults int) (*models.SprintIssuePageScheme, - *models.ResponseScheme, error) + // + // GET /rest/agile/1.0/sprint/{sprintId}/issue + // + // https://docs.go-atlassian.io/jira-agile/sprints#get-issues-for-sprint + Issues(ctx context.Context, sprintID int, opts *models.IssueOptionScheme, startAt, maxResults int) (*models.SprintIssuePageScheme, *models.ResponseScheme, error) // Start initiate the Sprint - // Docs: https://docs.go-atlassian.io/jira-agile/sprints#start-sprint - Start(ctx context.Context, sprintId int) (*models.ResponseScheme, error) + // + // PUT /rest/agile/1.0/sprint/{sprintId} + // + // https://docs.go-atlassian.io/jira-agile/sprints#start-sprint + Start(ctx context.Context, sprintID int) (*models.ResponseScheme, error) // Close closes the Sprint - // Docs: https://docs.go-atlassian.io/jira-agile/sprints#close-sprint - Close(ctx context.Context, sprintId int) (*models.ResponseScheme, error) + // + // PUT /rest/agile/1.0/sprint/{sprintId} + // + // https://docs.go-atlassian.io/jira-agile/sprints#close-sprint + Close(ctx context.Context, sprintID int) (*models.ResponseScheme, error) }