1
0
mirror of https://github.com/interviewstreet/go-jira.git synced 2025-08-06 22:13:02 +02:00

feat(context): Add support for context package

This commit is contained in:
Suhaib Mujahid
2020-05-03 09:38:32 -04:00
committed by GitHub
parent 8b64c7f005
commit e1f4265e2b
22 changed files with 766 additions and 254 deletions

View File

@ -1,6 +1,7 @@
package jira
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
@ -47,7 +48,7 @@ type Session struct {
Cookies []*http.Cookie
}
// AcquireSessionCookie creates a new session for a user in JIRA.
// AcquireSessionCookieWithContext creates a new session for a user in JIRA.
// Once a session has been successfully created it can be used to access any of JIRA's remote APIs and also the web UI by passing the appropriate HTTP Cookie header.
// The header will by automatically applied to every API request.
// Note that it is generally preferrable to use HTTP BASIC authentication with the REST API.
@ -56,7 +57,7 @@ type Session struct {
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#auth/1/session
//
// Deprecated: Use CookieAuthTransport instead
func (s *AuthenticationService) AcquireSessionCookie(username, password string) (bool, error) {
func (s *AuthenticationService) AcquireSessionCookieWithContext(ctx context.Context, username, password string) (bool, error) {
apiEndpoint := "rest/auth/1/session"
body := struct {
Username string `json:"username"`
@ -66,7 +67,7 @@ func (s *AuthenticationService) AcquireSessionCookie(username, password string)
password,
}
req, err := s.client.NewRequest("POST", apiEndpoint, body)
req, err := s.client.NewRequestWithContext(ctx, "POST", apiEndpoint, body)
if err != nil {
return false, err
}
@ -91,6 +92,13 @@ func (s *AuthenticationService) AcquireSessionCookie(username, password string)
return true, nil
}
// AcquireSessionCookie wraps AcquireSessionCookieWithContext using the background context.
//
// Deprecated: Use CookieAuthTransport instead
func (s *AuthenticationService) AcquireSessionCookie(username, password string) (bool, error) {
return s.AcquireSessionCookieWithContext(context.Background(), username, password)
}
// SetBasicAuth sets username and password for the basic auth against the JIRA instance.
//
// Deprecated: Use BasicAuthTransport instead
@ -113,19 +121,19 @@ func (s *AuthenticationService) Authenticated() bool {
return false
}
// Logout logs out the current user that has been authenticated and the session in the client is destroyed.
// LogoutWithContext logs out the current user that has been authenticated and the session in the client is destroyed.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#auth/1/session
//
// Deprecated: Use CookieAuthTransport to create base client. Logging out is as simple as not using the
// client anymore
func (s *AuthenticationService) Logout() error {
func (s *AuthenticationService) LogoutWithContext(ctx context.Context) error {
if s.authType != authTypeSession || s.client.session == nil {
return fmt.Errorf("no user is authenticated")
}
apiEndpoint := "rest/auth/1/session"
req, err := s.client.NewRequest("DELETE", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "DELETE", apiEndpoint, nil)
if err != nil {
return fmt.Errorf("creating the request to log the user out failed : %s", err)
}
@ -145,10 +153,18 @@ func (s *AuthenticationService) Logout() error {
}
// GetCurrentUser gets the details of the current user.
// Logout wraps LogoutWithContext using the background context.
//
// Deprecated: Use CookieAuthTransport to create base client. Logging out is as simple as not using the
// client anymore
func (s *AuthenticationService) Logout() error {
return s.LogoutWithContext(context.Background())
}
// GetCurrentUserWithContext gets the details of the current user.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#auth/1/session
func (s *AuthenticationService) GetCurrentUser() (*Session, error) {
func (s *AuthenticationService) GetCurrentUserWithContext(ctx context.Context) (*Session, error) {
if s == nil {
return nil, fmt.Errorf("authenticaiton Service is not instantiated")
}
@ -157,7 +173,7 @@ func (s *AuthenticationService) GetCurrentUser() (*Session, error) {
}
apiEndpoint := "rest/auth/1/session"
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, fmt.Errorf("could not create request for getting user info : %s", err)
}
@ -185,3 +201,8 @@ func (s *AuthenticationService) GetCurrentUser() (*Session, error) {
return ret, nil
}
// GetCurrentUser wraps GetCurrentUserWithContext using the background context.
func (s *AuthenticationService) GetCurrentUser() (*Session, error) {
return s.GetCurrentUserWithContext(context.Background())
}

View File

@ -1,6 +1,7 @@
package jira
import (
"context"
"fmt"
"strconv"
"time"
@ -124,16 +125,16 @@ type BoardConfigurationColumnStatus struct {
Self string `json:"self"`
}
// GetAllBoards will returns all boards. This only includes boards that the user has permission to view.
// GetAllBoardsWithContext will returns all boards. This only includes boards that the user has permission to view.
//
// JIRA API docs: https://docs.atlassian.com/jira-software/REST/cloud/#agile/1.0/board-getAllBoards
func (s *BoardService) GetAllBoards(opt *BoardListOptions) (*BoardsList, *Response, error) {
func (s *BoardService) GetAllBoardsWithContext(ctx context.Context, opt *BoardListOptions) (*BoardsList, *Response, error) {
apiEndpoint := "rest/agile/1.0/board"
url, err := addOptions(apiEndpoint, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", url, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return nil, nil, err
}
@ -148,13 +149,18 @@ func (s *BoardService) GetAllBoards(opt *BoardListOptions) (*BoardsList, *Respon
return boards, resp, err
}
// GetBoard will returns the board for the given boardID.
// GetAllBoards wraps GetAllBoardsWithContext using the background context.
func (s *BoardService) GetAllBoards(opt *BoardListOptions) (*BoardsList, *Response, error) {
return s.GetAllBoardsWithContext(context.Background(), opt)
}
// GetBoardWithContext will returns the board for the given boardID.
// This board will only be returned if the user has permission to view it.
//
// JIRA API docs: https://docs.atlassian.com/jira-software/REST/cloud/#agile/1.0/board-getBoard
func (s *BoardService) GetBoard(boardID int) (*Board, *Response, error) {
func (s *BoardService) GetBoardWithContext(ctx context.Context, boardID int) (*Board, *Response, error) {
apiEndpoint := fmt.Sprintf("rest/agile/1.0/board/%v", boardID)
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -169,7 +175,12 @@ func (s *BoardService) GetBoard(boardID int) (*Board, *Response, error) {
return board, resp, nil
}
// CreateBoard creates a new board. Board name, type and filter Id is required.
// GetBoard wraps GetBoardWithContext using the background context.
func (s *BoardService) GetBoard(boardID int) (*Board, *Response, error) {
return s.GetBoardWithContext(context.Background(), boardID)
}
// CreateBoardWithContext creates a new board. Board name, type and filter Id is required.
// name - Must be less than 255 characters.
// type - Valid values: scrum, kanban
// filterId - Id of a filter that the user has permissions to view.
@ -177,9 +188,9 @@ func (s *BoardService) GetBoard(boardID int) (*Board, *Response, error) {
// board will be created instead (remember that board sharing depends on the filter sharing).
//
// JIRA API docs: https://docs.atlassian.com/jira-software/REST/cloud/#agile/1.0/board-createBoard
func (s *BoardService) CreateBoard(board *Board) (*Board, *Response, error) {
func (s *BoardService) CreateBoardWithContext(ctx context.Context, board *Board) (*Board, *Response, error) {
apiEndpoint := "rest/agile/1.0/board"
req, err := s.client.NewRequest("POST", apiEndpoint, board)
req, err := s.client.NewRequestWithContext(ctx, "POST", apiEndpoint, board)
if err != nil {
return nil, nil, err
}
@ -194,12 +205,17 @@ func (s *BoardService) CreateBoard(board *Board) (*Board, *Response, error) {
return responseBoard, resp, nil
}
// DeleteBoard will delete an agile board.
// CreateBoard wraps CreateBoardWithContext using the background context.
func (s *BoardService) CreateBoard(board *Board) (*Board, *Response, error) {
return s.CreateBoardWithContext(context.Background(), board)
}
// DeleteBoardWithContext will delete an agile board.
//
// JIRA API docs: https://docs.atlassian.com/jira-software/REST/cloud/#agile/1.0/board-deleteBoard
func (s *BoardService) DeleteBoard(boardID int) (*Board, *Response, error) {
func (s *BoardService) DeleteBoardWithContext(ctx context.Context, boardID int) (*Board, *Response, error) {
apiEndpoint := fmt.Sprintf("rest/agile/1.0/board/%v", boardID)
req, err := s.client.NewRequest("DELETE", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "DELETE", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -211,11 +227,16 @@ func (s *BoardService) DeleteBoard(boardID int) (*Board, *Response, error) {
return nil, resp, err
}
// GetAllSprints will return all sprints from a board, for a given board Id.
// DeleteBoard wraps DeleteBoardWithContext using the background context.
func (s *BoardService) DeleteBoard(boardID int) (*Board, *Response, error) {
return s.DeleteBoardWithContext(context.Background(), boardID)
}
// GetAllSprintsWithContext will return all sprints from a board, for a given board Id.
// This only includes sprints that the user has permission to view.
//
// JIRA API docs: https://docs.atlassian.com/jira-software/REST/cloud/#agile/1.0/board/{boardId}/sprint
func (s *BoardService) GetAllSprints(boardID string) ([]Sprint, *Response, error) {
func (s *BoardService) GetAllSprintsWithContext(ctx context.Context, boardID string) ([]Sprint, *Response, error) {
id, err := strconv.Atoi(boardID)
if err != nil {
return nil, nil, err
@ -229,17 +250,22 @@ func (s *BoardService) GetAllSprints(boardID string) ([]Sprint, *Response, error
return result.Values, response, nil
}
// GetAllSprintsWithOptions will return sprints from a board, for a given board Id and filtering options
// GetAllSprints wraps GetAllSprintsWithContext using the background context.
func (s *BoardService) GetAllSprints(boardID string) ([]Sprint, *Response, error) {
return s.GetAllSprintsWithContext(context.Background(), boardID)
}
// GetAllSprintsWithOptionsWithContext will return sprints from a board, for a given board Id and filtering options
// This only includes sprints that the user has permission to view.
//
// JIRA API docs: https://docs.atlassian.com/jira-software/REST/cloud/#agile/1.0/board/{boardId}/sprint
func (s *BoardService) GetAllSprintsWithOptions(boardID int, options *GetAllSprintsOptions) (*SprintsList, *Response, error) {
func (s *BoardService) GetAllSprintsWithOptionsWithContext(ctx context.Context, boardID int, options *GetAllSprintsOptions) (*SprintsList, *Response, error) {
apiEndpoint := fmt.Sprintf("rest/agile/1.0/board/%d/sprint", boardID)
url, err := addOptions(apiEndpoint, options)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", url, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return nil, nil, err
}
@ -253,12 +279,17 @@ func (s *BoardService) GetAllSprintsWithOptions(boardID int, options *GetAllSpri
return result, resp, err
}
// GetBoardConfiguration will return a board configuration for a given board Id
// GetAllSprintsWithOptions wraps GetAllSprintsWithOptionsWithContext using the background context.
func (s *BoardService) GetAllSprintsWithOptions(boardID int, options *GetAllSprintsOptions) (*SprintsList, *Response, error) {
return s.GetAllSprintsWithOptionsWithContext(context.Background(), boardID, options)
}
// GetBoardConfigurationWithContext will return a board configuration for a given board Id
// Jira API docs:https://developer.atlassian.com/cloud/jira/software/rest/#api-rest-agile-1-0-board-boardId-configuration-get
func (s *BoardService) GetBoardConfiguration(boardID int) (*BoardConfiguration, *Response, error) {
func (s *BoardService) GetBoardConfigurationWithContext(ctx context.Context, boardID int) (*BoardConfiguration, *Response, error) {
apiEndpoint := fmt.Sprintf("rest/agile/1.0/board/%d/configuration", boardID)
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
@ -273,3 +304,8 @@ func (s *BoardService) GetBoardConfiguration(boardID int) (*BoardConfiguration,
return result, resp, err
}
// GetBoardConfiguration wraps GetBoardConfigurationWithContext using the background context.
func (s *BoardService) GetBoardConfiguration(boardID int) (*BoardConfiguration, *Response, error) {
return s.GetBoardConfigurationWithContext(context.Background(), boardID)
}

View File

@ -1,5 +1,7 @@
package jira
import "context"
// ComponentService handles components for the JIRA instance / API.
//
// JIRA API docs: https://docs.atlassian.com/software/jira/docs/api/REST/7.10.1/#api/2/component
@ -19,10 +21,10 @@ type CreateComponentOptions struct {
ProjectID int `json:"projectId,omitempty" structs:"projectId,omitempty"`
}
// Create creates a new JIRA component based on the given options.
func (s *ComponentService) Create(options *CreateComponentOptions) (*ProjectComponent, *Response, error) {
// CreateWithContext creates a new JIRA component based on the given options.
func (s *ComponentService) CreateWithContext(ctx context.Context, options *CreateComponentOptions) (*ProjectComponent, *Response, error) {
apiEndpoint := "rest/api/2/component"
req, err := s.client.NewRequest("POST", apiEndpoint, options)
req, err := s.client.NewRequestWithContext(ctx, "POST", apiEndpoint, options)
if err != nil {
return nil, nil, err
}
@ -36,3 +38,8 @@ func (s *ComponentService) Create(options *CreateComponentOptions) (*ProjectComp
return component, resp, nil
}
// Create wraps CreateWithContext using the background context.
func (s *ComponentService) Create(options *CreateComponentOptions) (*ProjectComponent, *Response, error) {
return s.CreateWithContext(context.Background(), options)
}

View File

@ -1,5 +1,7 @@
package jira
import "context"
// FieldService handles fields for the JIRA instance / API.
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-Field
@ -24,12 +26,12 @@ type FieldSchema struct {
System string `json:"system,omitempty" structs:"system,omitempty"`
}
// GetList gets all fields from JIRA
// GetListWithContext gets all fields from JIRA
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-api-2-field-get
func (s *FieldService) GetList() ([]Field, *Response, error) {
func (s *FieldService) GetListWithContext(ctx context.Context) ([]Field, *Response, error) {
apiEndpoint := "rest/api/2/field"
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -41,3 +43,8 @@ func (s *FieldService) GetList() ([]Field, *Response, error) {
}
return fieldList, resp, nil
}
// GetList wraps GetListWithContext using the background context.
func (s *FieldService) GetList() ([]Field, *Response, error) {
return s.GetListWithContext(context.Background())
}

View File

@ -1,6 +1,9 @@
package jira
import "github.com/google/go-querystring/query"
import (
"context"
"github.com/google/go-querystring/query"
)
import "fmt"
// FilterService handles fields for the JIRA instance / API.
@ -116,12 +119,12 @@ type FilterSearchOptions struct {
Expand string `url:"expand,omitempty"`
}
// GetList retrieves all filters from Jira
func (fs *FilterService) GetList() ([]*Filter, *Response, error) {
// GetListWithContext retrieves all filters from Jira
func (fs *FilterService) GetListWithContext(ctx context.Context) ([]*Filter, *Response, error) {
options := &GetQueryOptions{}
apiEndpoint := "rest/api/2/filter"
req, err := fs.client.NewRequest("GET", apiEndpoint, nil)
req, err := fs.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -143,10 +146,15 @@ func (fs *FilterService) GetList() ([]*Filter, *Response, error) {
return filters, resp, err
}
// GetFavouriteList retrieves the user's favourited filters from Jira
func (fs *FilterService) GetFavouriteList() ([]*Filter, *Response, error) {
// GetList wraps GetListWithContext using the background context.
func (fs *FilterService) GetList() ([]*Filter, *Response, error) {
return fs.GetListWithContext(context.Background())
}
// GetFavouriteListWithContext retrieves the user's favourited filters from Jira
func (fs *FilterService) GetFavouriteListWithContext(ctx context.Context) ([]*Filter, *Response, error) {
apiEndpoint := "rest/api/2/filter/favourite"
req, err := fs.client.NewRequest("GET", apiEndpoint, nil)
req, err := fs.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -159,10 +167,15 @@ func (fs *FilterService) GetFavouriteList() ([]*Filter, *Response, error) {
return filters, resp, err
}
// Get retrieves a single Filter from Jira
func (fs *FilterService) Get(filterID int) (*Filter, *Response, error) {
// GetFavouriteList wraps GetFavouriteListWithContext using the background context.
func (fs *FilterService) GetFavouriteList() ([]*Filter, *Response, error) {
return fs.GetFavouriteListWithContext(context.Background())
}
// GetWithContext retrieves a single Filter from Jira
func (fs *FilterService) GetWithContext(ctx context.Context, filterID int) (*Filter, *Response, error) {
apiEndpoint := fmt.Sprintf("rest/api/2/filter/%d", filterID)
req, err := fs.client.NewRequest("GET", apiEndpoint, nil)
req, err := fs.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -176,16 +189,21 @@ func (fs *FilterService) Get(filterID int) (*Filter, *Response, error) {
return filter, resp, err
}
// GetMyFilters retrieves the my Filters.
// Get wraps GetWithContext using the background context.
func (fs *FilterService) Get(filterID int) (*Filter, *Response, error) {
return fs.GetWithContext(context.Background(), filterID)
}
// GetMyFiltersWithContext retrieves the my Filters.
//
// https://developer.atlassian.com/cloud/jira/platform/rest/v3/#api-rest-api-3-filter-my-get
func (fs *FilterService) GetMyFilters(opts *GetMyFiltersQueryOptions) ([]*Filter, *Response, error) {
func (fs *FilterService) GetMyFiltersWithContext(ctx context.Context, opts *GetMyFiltersQueryOptions) ([]*Filter, *Response, error) {
apiEndpoint := "rest/api/3/filter/my"
url, err := addOptions(apiEndpoint, opts)
if err != nil {
return nil, nil, err
}
req, err := fs.client.NewRequest("GET", url, nil)
req, err := fs.client.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return nil, nil, err
}
@ -199,16 +217,21 @@ func (fs *FilterService) GetMyFilters(opts *GetMyFiltersQueryOptions) ([]*Filter
return filters, resp, nil
}
// Search will search for filter according to the search options
// GetMyFilters wraps GetMyFiltersWithContext using the background context.
func (fs *FilterService) GetMyFilters(opts *GetMyFiltersQueryOptions) ([]*Filter, *Response, error) {
return fs.GetMyFiltersWithContext(context.Background(), opts)
}
// SearchWithContext will search for filter according to the search options
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v3/#api-rest-api-3-filter-search-get
func (fs *FilterService) Search(opt *FilterSearchOptions) (*FiltersList, *Response, error) {
func (fs *FilterService) SearchWithContext(ctx context.Context, opt *FilterSearchOptions) (*FiltersList, *Response, error) {
apiEndpoint := "rest/api/3/filter/search"
url, err := addOptions(apiEndpoint, opt)
if err != nil {
return nil, nil, err
}
req, err := fs.client.NewRequest("GET", url, nil)
req, err := fs.client.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return nil, nil, err
}
@ -222,3 +245,8 @@ func (fs *FilterService) Search(opt *FilterSearchOptions) (*FiltersList, *Respon
return filters, resp, err
}
// Search wraps SearchWithContext using the background context.
func (fs *FilterService) Search(opt *FilterSearchOptions) (*FiltersList, *Response, error) {
return fs.SearchWithContext(context.Background(), opt)
}

View File

@ -1,6 +1,7 @@
package jira
import (
"context"
"fmt"
"net/url"
)
@ -58,16 +59,16 @@ type GroupSearchOptions struct {
IncludeInactiveUsers bool
}
// Get returns a paginated list of users who are members of the specified group and its subgroups.
// GetWithContext returns a paginated list of users who are members of the specified group and its subgroups.
// Users in the page are ordered by user names.
// User of this resource is required to have sysadmin or admin permissions.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/server/#api/2/group-getUsersFromGroup
//
// WARNING: This API only returns the first page of group members
func (s *GroupService) Get(name string) ([]GroupMember, *Response, error) {
func (s *GroupService) GetWithContext(ctx context.Context, name string) ([]GroupMember, *Response, error) {
apiEndpoint := fmt.Sprintf("/rest/api/2/group/member?groupname=%s", url.QueryEscape(name))
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -81,12 +82,17 @@ func (s *GroupService) Get(name string) ([]GroupMember, *Response, error) {
return group.Members, resp, nil
}
// GetWithOptions returns a paginated list of members of the specified group and its subgroups.
// Get wraps GetWithContext using the background context.
func (s *GroupService) Get(name string) ([]GroupMember, *Response, error) {
return s.GetWithContext(context.Background(), name)
}
// GetWithOptionsWithContext returns a paginated list of members of the specified group and its subgroups.
// Users in the page are ordered by user names.
// User of this resource is required to have sysadmin or admin permissions.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/server/#api/2/group-getUsersFromGroup
func (s *GroupService) GetWithOptions(name string, options *GroupSearchOptions) ([]GroupMember, *Response, error) {
func (s *GroupService) GetWithOptionsWithContext(ctx context.Context, name string, options *GroupSearchOptions) ([]GroupMember, *Response, error) {
var apiEndpoint string
if options == nil {
apiEndpoint = fmt.Sprintf("/rest/api/2/group/member?groupname=%s", url.QueryEscape(name))
@ -99,7 +105,7 @@ func (s *GroupService) GetWithOptions(name string, options *GroupSearchOptions)
options.IncludeInactiveUsers,
)
}
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -112,16 +118,21 @@ func (s *GroupService) GetWithOptions(name string, options *GroupSearchOptions)
return group.Members, resp, nil
}
// Add adds user to group
// GetWithOptions wraps GetWithOptionsWithContext using the background context.
func (s *GroupService) GetWithOptions(name string, options *GroupSearchOptions) ([]GroupMember, *Response, error) {
return s.GetWithOptionsWithContext(context.Background(), name, options)
}
// AddWithContext adds user to group
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/cloud/#api/2/group-addUserToGroup
func (s *GroupService) Add(groupname string, username string) (*Group, *Response, error) {
func (s *GroupService) AddWithContext(ctx context.Context, groupname string, username string) (*Group, *Response, error) {
apiEndpoint := fmt.Sprintf("/rest/api/2/group/user?groupname=%s", groupname)
var user struct {
Name string `json:"name"`
}
user.Name = username
req, err := s.client.NewRequest("POST", apiEndpoint, &user)
req, err := s.client.NewRequestWithContext(ctx, "POST", apiEndpoint, &user)
if err != nil {
return nil, nil, err
}
@ -136,12 +147,17 @@ func (s *GroupService) Add(groupname string, username string) (*Group, *Response
return responseGroup, resp, nil
}
// Remove removes user from group
// Add wraps AddWithContext using the background context.
func (s *GroupService) Add(groupname string, username string) (*Group, *Response, error) {
return s.AddWithContext(context.Background(), groupname, username)
}
// RemoveWithContext removes user from group
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/cloud/#api/2/group-removeUserFromGroup
func (s *GroupService) Remove(groupname string, username string) (*Response, error) {
func (s *GroupService) RemoveWithContext(ctx context.Context, groupname string, username string) (*Response, error) {
apiEndpoint := fmt.Sprintf("/rest/api/2/group/user?groupname=%s&username=%s", groupname, username)
req, err := s.client.NewRequest("DELETE", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "DELETE", apiEndpoint, nil)
if err != nil {
return nil, err
}
@ -154,3 +170,8 @@ func (s *GroupService) Remove(groupname string, username string) (*Response, err
return resp, nil
}
// Remove wraps RemoveWithContext using the background context.
func (s *GroupService) Remove(groupname string, username string) (*Response, error) {
return s.RemoveWithContext(context.Background(), groupname, username)
}

306
issue.go
View File

@ -2,6 +2,7 @@ package jira
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
@ -588,7 +589,7 @@ type RemoteLinkStatus struct {
Icon *RemoteLinkIcon
}
// Get returns a full representation of the issue for the given issue key.
// GetWithContext returns a full representation of the issue for the given issue key.
// JIRA will attempt to identify the issue by the issueIdOrKey path parameter.
// This can be an issue id, or an issue key.
// If the issue cannot be found via an exact match, JIRA will also look for the issue in a case-insensitive way, or by looking to see if the issue was moved.
@ -596,9 +597,9 @@ type RemoteLinkStatus struct {
// The given options will be appended to the query string
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/issue-getIssue
func (s *IssueService) Get(issueID string, options *GetQueryOptions) (*Issue, *Response, error) {
func (s *IssueService) GetWithContext(ctx context.Context, issueID string, options *GetQueryOptions) (*Issue, *Response, error) {
apiEndpoint := fmt.Sprintf("rest/api/2/issue/%s", issueID)
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -621,13 +622,18 @@ func (s *IssueService) Get(issueID string, options *GetQueryOptions) (*Issue, *R
return issue, resp, nil
}
// DownloadAttachment returns a Response of an attachment for a given attachmentID.
// Get wraps GetWithContext using the background context.
func (s *IssueService) Get(issueID string, options *GetQueryOptions) (*Issue, *Response, error) {
return s.GetWithContext(context.Background(), issueID, options)
}
// DownloadAttachmentWithContext returns a Response of an attachment for a given attachmentID.
// The attachment is in the Response.Body of the response.
// This is an io.ReadCloser.
// The caller should close the resp.Body.
func (s *IssueService) DownloadAttachment(attachmentID string) (*Response, error) {
func (s *IssueService) DownloadAttachmentWithContext(ctx context.Context, attachmentID string) (*Response, error) {
apiEndpoint := fmt.Sprintf("secure/attachment/%s/", attachmentID)
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, err
}
@ -641,8 +647,13 @@ func (s *IssueService) DownloadAttachment(attachmentID string) (*Response, error
return resp, nil
}
// PostAttachment uploads r (io.Reader) as an attachment to a given issueID
func (s *IssueService) PostAttachment(issueID string, r io.Reader, attachmentName string) (*[]Attachment, *Response, error) {
// DownloadAttachment wraps DownloadAttachmentWithContext using the background context.
func (s *IssueService) DownloadAttachment(attachmentID string) (*Response, error) {
return s.DownloadAttachmentWithContext(context.Background(), attachmentID)
}
// PostAttachmentWithContext uploads r (io.Reader) as an attachment to a given issueID
func (s *IssueService) PostAttachmentWithContext(ctx context.Context, issueID string, r io.Reader, attachmentName string) (*[]Attachment, *Response, error) {
apiEndpoint := fmt.Sprintf("rest/api/2/issue/%s/attachments", issueID)
b := new(bytes.Buffer)
@ -661,7 +672,7 @@ func (s *IssueService) PostAttachment(issueID string, r io.Reader, attachmentNam
}
writer.Close()
req, err := s.client.NewMultiPartRequest("POST", apiEndpoint, b)
req, err := s.client.NewMultiPartRequestWithContext(ctx, "POST", apiEndpoint, b)
if err != nil {
return nil, nil, err
}
@ -679,11 +690,16 @@ func (s *IssueService) PostAttachment(issueID string, r io.Reader, attachmentNam
return attachment, resp, nil
}
// DeleteAttachment deletes an attachment of a given attachmentID
func (s *IssueService) DeleteAttachment(attachmentID string) (*Response, error) {
// PostAttachment wraps PostAttachmentWithContext using the background context.
func (s *IssueService) PostAttachment(issueID string, r io.Reader, attachmentName string) (*[]Attachment, *Response, error) {
return s.PostAttachmentWithContext(context.Background(), issueID, r, attachmentName)
}
// DeleteAttachmentWithContext deletes an attachment of a given attachmentID
func (s *IssueService) DeleteAttachmentWithContext(ctx context.Context, attachmentID string) (*Response, error) {
apiEndpoint := fmt.Sprintf("rest/api/2/attachment/%s", attachmentID)
req, err := s.client.NewRequest("DELETE", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "DELETE", apiEndpoint, nil)
if err != nil {
return nil, err
}
@ -697,14 +713,19 @@ func (s *IssueService) DeleteAttachment(attachmentID string) (*Response, error)
return resp, nil
}
// GetWorklogs gets all the worklogs for an issue.
// DeleteAttachment wraps DeleteAttachmentWithContext using the background context.
func (s *IssueService) DeleteAttachment(attachmentID string) (*Response, error) {
return s.DeleteAttachmentWithContext(context.Background(), attachmentID)
}
// GetWorklogsWithContext gets all the worklogs for an issue.
// This method is especially important if you need to read all the worklogs, not just the first page.
//
// https://docs.atlassian.com/jira/REST/cloud/#api/2/issue/{issueIdOrKey}/worklog-getIssueWorklog
func (s *IssueService) GetWorklogs(issueID string, options ...func(*http.Request) error) (*Worklog, *Response, error) {
func (s *IssueService) GetWorklogsWithContext(ctx context.Context, issueID string, options ...func(*http.Request) error) (*Worklog, *Response, error) {
apiEndpoint := fmt.Sprintf("rest/api/2/issue/%s/worklog", issueID)
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -721,6 +742,11 @@ func (s *IssueService) GetWorklogs(issueID string, options ...func(*http.Request
return v, resp, err
}
// GetWorklogs wraps GetWorklogsWithContext using the background context.
func (s *IssueService) GetWorklogs(issueID string, options ...func(*http.Request) error) (*Worklog, *Response, error) {
return s.GetWorklogsWithContext(context.Background(), issueID, options...)
}
// Applies query options to http request.
// This helper is meant to be used with all "QueryOptions" structs.
func WithQueryOptions(options interface{}) func(*http.Request) error {
@ -737,14 +763,14 @@ func WithQueryOptions(options interface{}) func(*http.Request) error {
}
}
// Create creates an issue or a sub-task from a JSON representation.
// CreateWithContext creates an issue or a sub-task from a JSON representation.
// Creating a sub-task is similar to creating a regular issue, with two important differences:
// The issueType field must correspond to a sub-task issue type and you must provide a parent field in the issue create request containing the id or key of the parent issue.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/issue-createIssues
func (s *IssueService) Create(issue *Issue) (*Issue, *Response, error) {
func (s *IssueService) CreateWithContext(ctx context.Context, issue *Issue) (*Issue, *Response, error) {
apiEndpoint := "rest/api/2/issue"
req, err := s.client.NewRequest("POST", apiEndpoint, issue)
req, err := s.client.NewRequestWithContext(ctx, "POST", apiEndpoint, issue)
if err != nil {
return nil, nil, err
}
@ -767,17 +793,22 @@ func (s *IssueService) Create(issue *Issue) (*Issue, *Response, error) {
return responseIssue, resp, nil
}
// UpdateWithOptions updates an issue from a JSON representation,
// Create wraps CreateWithContext using the background context.
func (s *IssueService) Create(issue *Issue) (*Issue, *Response, error) {
return s.CreateWithContext(context.Background(), issue)
}
// UpdateWithOptionsWithContext updates an issue from a JSON representation,
// while also specifiying query params. The issue is found by key.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-editIssue
func (s *IssueService) UpdateWithOptions(issue *Issue, opts *UpdateQueryOptions) (*Issue, *Response, error) {
func (s *IssueService) UpdateWithOptionsWithContext(ctx context.Context, issue *Issue, opts *UpdateQueryOptions) (*Issue, *Response, error) {
apiEndpoint := fmt.Sprintf("rest/api/2/issue/%v", issue.Key)
url, err := addOptions(apiEndpoint, opts)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("PUT", url, issue)
req, err := s.client.NewRequestWithContext(ctx, "PUT", url, issue)
if err != nil {
return nil, nil, err
}
@ -793,19 +824,29 @@ func (s *IssueService) UpdateWithOptions(issue *Issue, opts *UpdateQueryOptions)
return &ret, resp, nil
}
// Update updates an issue from a JSON representation. The issue is found by key.
// UpdateWithOptions wraps UpdateWithOptionsWithContext using the background context.
func (s *IssueService) UpdateWithOptions(issue *Issue, opts *UpdateQueryOptions) (*Issue, *Response, error) {
return s.UpdateWithOptionsWithContext(context.Background(), issue, opts)
}
// UpdateWithContext updates an issue from a JSON representation. The issue is found by key.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-editIssue
func (s *IssueService) Update(issue *Issue) (*Issue, *Response, error) {
func (s *IssueService) UpdateWithContext(ctx context.Context, issue *Issue) (*Issue, *Response, error) {
return s.UpdateWithOptions(issue, nil)
}
// UpdateIssue updates an issue from a JSON representation. The issue is found by key.
// Update wraps UpdateWithContext using the background context.
func (s *IssueService) Update(issue *Issue) (*Issue, *Response, error) {
return s.UpdateWithContext(context.Background(), issue)
}
// UpdateIssueWithContext updates an issue from a JSON representation. The issue is found by key.
//
// https://docs.atlassian.com/jira/REST/7.4.0/#api/2/issue-editIssue
func (s *IssueService) UpdateIssue(jiraID string, data map[string]interface{}) (*Response, error) {
func (s *IssueService) UpdateIssueWithContext(ctx context.Context, jiraID string, data map[string]interface{}) (*Response, error) {
apiEndpoint := fmt.Sprintf("rest/api/2/issue/%v", jiraID)
req, err := s.client.NewRequest("PUT", apiEndpoint, data)
req, err := s.client.NewRequestWithContext(ctx, "PUT", apiEndpoint, data)
if err != nil {
return nil, err
}
@ -819,12 +860,17 @@ func (s *IssueService) UpdateIssue(jiraID string, data map[string]interface{}) (
return resp, nil
}
// AddComment adds a new comment to issueID.
// UpdateIssue wraps UpdateIssueWithContext using the background context.
func (s *IssueService) UpdateIssue(jiraID string, data map[string]interface{}) (*Response, error) {
return s.UpdateIssueWithContext(context.Background(), jiraID, data)
}
// AddCommentWithContext adds a new comment to issueID.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/issue-addComment
func (s *IssueService) AddComment(issueID string, comment *Comment) (*Comment, *Response, error) {
func (s *IssueService) AddCommentWithContext(ctx context.Context, issueID string, comment *Comment) (*Comment, *Response, error) {
apiEndpoint := fmt.Sprintf("rest/api/2/issue/%s/comment", issueID)
req, err := s.client.NewRequest("POST", apiEndpoint, comment)
req, err := s.client.NewRequestWithContext(ctx, "POST", apiEndpoint, comment)
if err != nil {
return nil, nil, err
}
@ -839,17 +885,22 @@ func (s *IssueService) AddComment(issueID string, comment *Comment) (*Comment, *
return responseComment, resp, nil
}
// UpdateComment updates the body of a comment, identified by comment.ID, on the issueID.
// AddComment wraps AddCommentWithContext using the background context.
func (s *IssueService) AddComment(issueID string, comment *Comment) (*Comment, *Response, error) {
return s.AddCommentWithContext(context.Background(), issueID, comment)
}
// UpdateCommentWithContext updates the body of a comment, identified by comment.ID, on the issueID.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/cloud/#api/2/issue/{issueIdOrKey}/comment-updateComment
func (s *IssueService) UpdateComment(issueID string, comment *Comment) (*Comment, *Response, error) {
func (s *IssueService) UpdateCommentWithContext(ctx context.Context, issueID string, comment *Comment) (*Comment, *Response, error) {
reqBody := struct {
Body string `json:"body"`
}{
Body: comment.Body,
}
apiEndpoint := fmt.Sprintf("rest/api/2/issue/%s/comment/%s", issueID, comment.ID)
req, err := s.client.NewRequest("PUT", apiEndpoint, reqBody)
req, err := s.client.NewRequestWithContext(ctx, "PUT", apiEndpoint, reqBody)
if err != nil {
return nil, nil, err
}
@ -863,12 +914,17 @@ func (s *IssueService) UpdateComment(issueID string, comment *Comment) (*Comment
return responseComment, resp, nil
}
// DeleteComment Deletes a comment from an issueID.
// UpdateComment wraps UpdateCommentWithContext using the background context.
func (s *IssueService) UpdateComment(issueID string, comment *Comment) (*Comment, *Response, error) {
return s.UpdateCommentWithContext(context.Background(), issueID, comment)
}
// DeleteCommentWithContext Deletes a comment from an issueID.
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v3/#api-api-3-issue-issueIdOrKey-comment-id-delete
func (s *IssueService) DeleteComment(issueID, commentID string) error {
func (s *IssueService) DeleteCommentWithContext(ctx context.Context, issueID, commentID string) error {
apiEndpoint := fmt.Sprintf("rest/api/2/issue/%s/comment/%s", issueID, commentID)
req, err := s.client.NewRequest("DELETE", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "DELETE", apiEndpoint, nil)
if err != nil {
return err
}
@ -882,12 +938,17 @@ func (s *IssueService) DeleteComment(issueID, commentID string) error {
return nil
}
// AddWorklogRecord adds a new worklog record to issueID.
// DeleteComment wraps DeleteCommentWithContext using the background context.
func (s *IssueService) DeleteComment(issueID, commentID string) error {
return s.DeleteCommentWithContext(context.Background(), issueID, commentID)
}
// AddWorklogRecordWithContext adds a new worklog record to issueID.
//
// https://developer.atlassian.com/cloud/jira/platform/rest/#api-api-2-issue-issueIdOrKey-worklog-post
func (s *IssueService) AddWorklogRecord(issueID string, record *WorklogRecord, options ...func(*http.Request) error) (*WorklogRecord, *Response, error) {
func (s *IssueService) AddWorklogRecordWithContext(ctx context.Context, issueID string, record *WorklogRecord, options ...func(*http.Request) error) (*WorklogRecord, *Response, error) {
apiEndpoint := fmt.Sprintf("rest/api/2/issue/%s/worklog", issueID)
req, err := s.client.NewRequest("POST", apiEndpoint, record)
req, err := s.client.NewRequestWithContext(ctx, "POST", apiEndpoint, record)
if err != nil {
return nil, nil, err
}
@ -909,12 +970,17 @@ func (s *IssueService) AddWorklogRecord(issueID string, record *WorklogRecord, o
return responseRecord, resp, nil
}
// UpdateWorklogRecord updates a worklog record.
// AddWorklogRecord wraps AddWorklogRecordWithContext using the background context.
func (s *IssueService) AddWorklogRecord(issueID string, record *WorklogRecord, options ...func(*http.Request) error) (*WorklogRecord, *Response, error) {
return s.AddWorklogRecordWithContext(context.Background(), issueID, record, options...)
}
// UpdateWorklogRecordWithContext updates a worklog record.
//
// https://docs.atlassian.com/software/jira/docs/api/REST/7.1.2/#api/2/issue-updateWorklog
func (s *IssueService) UpdateWorklogRecord(issueID, worklogID string, record *WorklogRecord, options ...func(*http.Request) error) (*WorklogRecord, *Response, error) {
func (s *IssueService) UpdateWorklogRecordWithContext(ctx context.Context, issueID, worklogID string, record *WorklogRecord, options ...func(*http.Request) error) (*WorklogRecord, *Response, error) {
apiEndpoint := fmt.Sprintf("rest/api/2/issue/%s/worklog/%s", issueID, worklogID)
req, err := s.client.NewRequest("PUT", apiEndpoint, record)
req, err := s.client.NewRequestWithContext(ctx, "PUT", apiEndpoint, record)
if err != nil {
return nil, nil, err
}
@ -936,12 +1002,17 @@ func (s *IssueService) UpdateWorklogRecord(issueID, worklogID string, record *Wo
return responseRecord, resp, nil
}
// AddLink adds a link between two issues.
// UpdateWorklogRecord wraps UpdateWorklogRecordWithContext using the background context.
func (s *IssueService) UpdateWorklogRecord(issueID, worklogID string, record *WorklogRecord, options ...func(*http.Request) error) (*WorklogRecord, *Response, error) {
return s.UpdateWorklogRecordWithContext(context.Background(), issueID, worklogID, record, options...)
}
// AddLinkWithContext adds a link between two issues.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/issueLink
func (s *IssueService) AddLink(issueLink *IssueLink) (*Response, error) {
func (s *IssueService) AddLinkWithContext(ctx context.Context, issueLink *IssueLink) (*Response, error) {
apiEndpoint := "rest/api/2/issueLink"
req, err := s.client.NewRequest("POST", apiEndpoint, issueLink)
req, err := s.client.NewRequestWithContext(ctx, "POST", apiEndpoint, issueLink)
if err != nil {
return nil, err
}
@ -954,10 +1025,15 @@ func (s *IssueService) AddLink(issueLink *IssueLink) (*Response, error) {
return resp, err
}
// Search will search for tickets according to the jql
// AddLink wraps AddLinkWithContext using the background context.
func (s *IssueService) AddLink(issueLink *IssueLink) (*Response, error) {
return s.AddLinkWithContext(context.Background(), issueLink)
}
// SearchWithContext will search for tickets according to the jql
//
// JIRA API docs: https://developer.atlassian.com/jiradev/jira-apis/jira-rest-apis/jira-rest-api-tutorials/jira-rest-api-example-query-issues
func (s *IssueService) Search(jql string, options *SearchOptions) ([]Issue, *Response, error) {
func (s *IssueService) SearchWithContext(ctx context.Context, jql string, options *SearchOptions) ([]Issue, *Response, error) {
u := url.URL{
Path: "rest/api/2/search",
}
@ -967,6 +1043,7 @@ func (s *IssueService) Search(jql string, options *SearchOptions) ([]Issue, *Res
}
if options != nil {
if options.StartAt != 0 {
uv.Add("startAt", strconv.Itoa(options.StartAt))
}
@ -986,7 +1063,7 @@ func (s *IssueService) Search(jql string, options *SearchOptions) ([]Issue, *Res
u.RawQuery = uv.Encode()
req, err := s.client.NewRequest("GET", u.String(), nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", u.String(), nil)
if err != nil {
return []Issue{}, nil, err
}
@ -999,10 +1076,15 @@ func (s *IssueService) Search(jql string, options *SearchOptions) ([]Issue, *Res
return v.Issues, resp, err
}
// SearchPages will get issues from all pages in a search
// Search wraps SearchWithContext using the background context.
func (s *IssueService) Search(jql string, options *SearchOptions) ([]Issue, *Response, error) {
return s.SearchWithContext(context.Background(), jql, options)
}
// SearchPagesWithContext will get issues from all pages in a search
//
// JIRA API docs: https://developer.atlassian.com/jiradev/jira-apis/jira-rest-apis/jira-rest-api-tutorials/jira-rest-api-example-query-issues
func (s *IssueService) SearchPages(jql string, options *SearchOptions, f func(Issue) error) error {
func (s *IssueService) SearchPagesWithContext(ctx context.Context, jql string, options *SearchOptions, f func(Issue) error) error {
if options == nil {
options = &SearchOptions{
StartAt: 0,
@ -1043,10 +1125,15 @@ func (s *IssueService) SearchPages(jql string, options *SearchOptions, f func(Is
}
}
// GetCustomFields returns a map of customfield_* keys with string values
func (s *IssueService) GetCustomFields(issueID string) (CustomFields, *Response, error) {
// SearchPages wraps SearchPagesWithContext using the background context.
func (s *IssueService) SearchPages(jql string, options *SearchOptions, f func(Issue) error) error {
return s.SearchPagesWithContext(context.Background(), jql, options, f)
}
// GetCustomFieldsWithContext returns a map of customfield_* keys with string values
func (s *IssueService) GetCustomFieldsWithContext(ctx context.Context, issueID string) (CustomFields, *Response, error) {
apiEndpoint := fmt.Sprintf("rest/api/2/issue/%s", issueID)
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -1080,13 +1167,18 @@ func (s *IssueService) GetCustomFields(issueID string) (CustomFields, *Response,
return cf, resp, nil
}
// GetTransitions gets a list of the transitions possible for this issue by the current user,
// GetCustomFields wraps GetCustomFieldsWithContext using the background context.
func (s *IssueService) GetCustomFields(issueID string) (CustomFields, *Response, error) {
return s.GetCustomFieldsWithContext(context.Background(), issueID)
}
// GetTransitionsWithContext gets a list of the transitions possible for this issue by the current user,
// along with fields that are required and their types.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/issue-getTransitions
func (s *IssueService) GetTransitions(id string) ([]Transition, *Response, error) {
func (s *IssueService) GetTransitionsWithContext(ctx context.Context, id string) ([]Transition, *Response, error) {
apiEndpoint := fmt.Sprintf("rest/api/2/issue/%s/transitions?expand=transitions.fields", id)
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -1099,27 +1191,37 @@ func (s *IssueService) GetTransitions(id string) ([]Transition, *Response, error
return result.Transitions, resp, err
}
// DoTransition performs a transition on an issue.
// GetTransitions wraps GetTransitionsWithContext using the background context.
func (s *IssueService) GetTransitions(id string) ([]Transition, *Response, error) {
return s.GetTransitionsWithContext(context.Background(), id)
}
// DoTransitionWithContext performs a transition on an issue.
// When performing the transition you can update or set other issue fields.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/issue-doTransition
func (s *IssueService) DoTransition(ticketID, transitionID string) (*Response, error) {
func (s *IssueService) DoTransitionWithContext(ctx context.Context, ticketID, transitionID string) (*Response, error) {
payload := CreateTransitionPayload{
Transition: TransitionPayload{
ID: transitionID,
},
}
return s.DoTransitionWithPayload(ticketID, payload)
return s.DoTransitionWithPayloadWithContext(ctx, ticketID, payload)
}
// DoTransitionWithPayload performs a transition on an issue using any payload.
// DoTransition wraps DoTransitionWithContext using the background context.
func (s *IssueService) DoTransition(ticketID, transitionID string) (*Response, error) {
return s.DoTransitionWithContext(context.Background(), ticketID, transitionID)
}
// DoTransitionWithPayloadWithContext performs a transition on an issue using any payload.
// When performing the transition you can update or set other issue fields.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/issue-doTransition
func (s *IssueService) DoTransitionWithPayload(ticketID, payload interface{}) (*Response, error) {
func (s *IssueService) DoTransitionWithPayloadWithContext(ctx context.Context, ticketID, payload interface{}) (*Response, error) {
apiEndpoint := fmt.Sprintf("rest/api/2/issue/%s/transitions", ticketID)
req, err := s.client.NewRequest("POST", apiEndpoint, payload)
req, err := s.client.NewRequestWithContext(ctx, "POST", apiEndpoint, payload)
if err != nil {
return nil, err
}
@ -1132,6 +1234,11 @@ func (s *IssueService) DoTransitionWithPayload(ticketID, payload interface{}) (*
return resp, err
}
// DoTransitionWithPayload wraps DoTransitionWithPayloadWithContext using the background context.
func (s *IssueService) DoTransitionWithPayload(ticketID, payload interface{}) (*Response, error) {
return s.DoTransitionWithPayloadWithContext(context.Background(), ticketID, payload)
}
// InitIssueWithMetaAndFields returns Issue with with values from fieldsConfig properly set.
// * metaProject should contain metaInformation about the project where the issue should be created.
// * metaIssuetype is the MetaInformation about the Issuetype that needs to be created.
@ -1211,8 +1318,8 @@ func InitIssueWithMetaAndFields(metaProject *MetaProject, metaIssuetype *MetaIss
return issue, nil
}
// Delete will delete a specified issue.
func (s *IssueService) Delete(issueID string) (*Response, error) {
// DeleteWithContext will delete a specified issue.
func (s *IssueService) DeleteWithContext(ctx context.Context, issueID string) (*Response, error) {
apiEndpoint := fmt.Sprintf("rest/api/2/issue/%s", issueID)
// to enable deletion of subtasks; without this, the request will fail if the issue has subtasks
@ -1220,7 +1327,7 @@ func (s *IssueService) Delete(issueID string) (*Response, error) {
deletePayload["deleteSubtasks"] = "true"
content, _ := json.Marshal(deletePayload)
req, err := s.client.NewRequest("DELETE", apiEndpoint, content)
req, err := s.client.NewRequestWithContext(ctx, "DELETE", apiEndpoint, content)
if err != nil {
return nil, err
}
@ -1229,13 +1336,18 @@ func (s *IssueService) Delete(issueID string) (*Response, error) {
return resp, err
}
// GetWatchers wil return all the users watching/observing the given issue
// Delete wraps DeleteWithContext using the background context.
func (s *IssueService) Delete(issueID string) (*Response, error) {
return s.DeleteWithContext(context.Background(), issueID)
}
// GetWatchersWithContext wil return all the users watching/observing the given issue
//
// JIRA API docs: https://docs.atlassian.com/software/jira/docs/api/REST/latest/#api/2/issue-getIssueWatchers
func (s *IssueService) GetWatchers(issueID string) (*[]User, *Response, error) {
func (s *IssueService) GetWatchersWithContext(ctx context.Context, issueID string) (*[]User, *Response, error) {
watchesAPIEndpoint := fmt.Sprintf("rest/api/2/issue/%s/watchers", issueID)
req, err := s.client.NewRequest("GET", watchesAPIEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", watchesAPIEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -1267,13 +1379,18 @@ func (s *IssueService) GetWatchers(issueID string) (*[]User, *Response, error) {
return &result, resp, nil
}
// AddWatcher adds watcher to the given issue
// GetWatchers wraps GetWatchersWithContext using the background context.
func (s *IssueService) GetWatchers(issueID string) (*[]User, *Response, error) {
return s.GetWatchersWithContext(context.Background(), issueID)
}
// AddWatcherWithContext adds watcher to the given issue
//
// JIRA API docs: https://docs.atlassian.com/software/jira/docs/api/REST/latest/#api/2/issue-addWatcher
func (s *IssueService) AddWatcher(issueID string, userName string) (*Response, error) {
func (s *IssueService) AddWatcherWithContext(ctx context.Context, issueID string, userName string) (*Response, error) {
apiEndPoint := fmt.Sprintf("rest/api/2/issue/%s/watchers", issueID)
req, err := s.client.NewRequest("POST", apiEndPoint, userName)
req, err := s.client.NewRequestWithContext(ctx, "POST", apiEndPoint, userName)
if err != nil {
return nil, err
}
@ -1286,13 +1403,18 @@ func (s *IssueService) AddWatcher(issueID string, userName string) (*Response, e
return resp, err
}
// RemoveWatcher removes given user from given issue
// AddWatcher wraps AddWatcherWithContext using the background context.
func (s *IssueService) AddWatcher(issueID string, userName string) (*Response, error) {
return s.AddWatcherWithContext(context.Background(), issueID, userName)
}
// RemoveWatcherWithContext removes given user from given issue
//
// JIRA API docs: https://docs.atlassian.com/software/jira/docs/api/REST/latest/#api/2/issue-removeWatcher
func (s *IssueService) RemoveWatcher(issueID string, userName string) (*Response, error) {
func (s *IssueService) RemoveWatcherWithContext(ctx context.Context, issueID string, userName string) (*Response, error) {
apiEndPoint := fmt.Sprintf("rest/api/2/issue/%s/watchers", issueID)
req, err := s.client.NewRequest("DELETE", apiEndPoint, userName)
req, err := s.client.NewRequestWithContext(ctx, "DELETE", apiEndPoint, userName)
if err != nil {
return nil, err
}
@ -1305,13 +1427,18 @@ func (s *IssueService) RemoveWatcher(issueID string, userName string) (*Response
return resp, err
}
// UpdateAssignee updates the user assigned to work on the given issue
// RemoveWatcher wraps RemoveWatcherWithContext using the background context.
func (s *IssueService) RemoveWatcher(issueID string, userName string) (*Response, error) {
return s.RemoveWatcherWithContext(context.Background(), issueID, userName)
}
// UpdateAssigneeWithContext updates the user assigned to work on the given issue
//
// JIRA API docs: https://docs.atlassian.com/software/jira/docs/api/REST/7.10.2/#api/2/issue-assign
func (s *IssueService) UpdateAssignee(issueID string, assignee *User) (*Response, error) {
func (s *IssueService) UpdateAssigneeWithContext(ctx context.Context, issueID string, assignee *User) (*Response, error) {
apiEndPoint := fmt.Sprintf("rest/api/2/issue/%s/assignee", issueID)
req, err := s.client.NewRequest("PUT", apiEndPoint, assignee)
req, err := s.client.NewRequestWithContext(ctx, "PUT", apiEndPoint, assignee)
if err != nil {
return nil, err
}
@ -1324,6 +1451,11 @@ func (s *IssueService) UpdateAssignee(issueID string, assignee *User) (*Response
return resp, err
}
// UpdateAssignee wraps UpdateAssigneeWithContext using the background context.
func (s *IssueService) UpdateAssignee(issueID string, assignee *User) (*Response, error) {
return s.UpdateAssigneeWithContext(context.Background(), issueID, assignee)
}
func (c ChangelogHistory) CreatedTime() (time.Time, error) {
var t time.Time
// Ignore null
@ -1334,12 +1466,12 @@ func (c ChangelogHistory) CreatedTime() (time.Time, error) {
return t, err
}
// GetRemoteLinks gets remote issue links on the issue.
// GetRemoteLinksWithContext gets remote issue links on the issue.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/issue-getRemoteIssueLinks
func (s *IssueService) GetRemoteLinks(id string) (*[]RemoteLink, *Response, error) {
func (s *IssueService) GetRemoteLinksWithContext(ctx context.Context, id string) (*[]RemoteLink, *Response, error) {
apiEndpoint := fmt.Sprintf("rest/api/2/issue/%s/remotelink", id)
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -1352,12 +1484,17 @@ func (s *IssueService) GetRemoteLinks(id string) (*[]RemoteLink, *Response, erro
return result, resp, err
}
// AddRemoteLink adds a remote link to issueID.
// GetRemoteLinks wraps GetRemoteLinksWithContext using the background context.
func (s *IssueService) GetRemoteLinks(id string) (*[]RemoteLink, *Response, error) {
return s.GetRemoteLinksWithContext(context.Background(), id)
}
// AddRemoteLinkWithContext adds a remote link to issueID.
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/#api-rest-api-2-issue-issueIdOrKey-remotelink-post
func (s *IssueService) AddRemoteLink(issueID string, remotelink *RemoteLink) (*RemoteLink, *Response, error) {
func (s *IssueService) AddRemoteLinkWithContext(ctx context.Context, issueID string, remotelink *RemoteLink) (*RemoteLink, *Response, error) {
apiEndpoint := fmt.Sprintf("rest/api/2/issue/%s/remotelink", issueID)
req, err := s.client.NewRequest("POST", apiEndpoint, remotelink)
req, err := s.client.NewRequestWithContext(ctx, "POST", apiEndpoint, remotelink)
if err != nil {
return nil, nil, err
}
@ -1371,3 +1508,8 @@ func (s *IssueService) AddRemoteLink(issueID string, remotelink *RemoteLink) (*R
return responseRemotelink, resp, nil
}
// AddRemoteLink wraps AddRemoteLinkWithContext using the background context.
func (s *IssueService) AddRemoteLink(issueID string, remotelink *RemoteLink) (*RemoteLink, *Response, error) {
return s.AddRemoteLinkWithContext(context.Background(), issueID, remotelink)
}

View File

@ -1,6 +1,7 @@
package jira
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
@ -13,12 +14,12 @@ type IssueLinkTypeService struct {
client *Client
}
// GetList gets all of the issue link types from JIRA.
// GetListWithContext gets all of the issue link types from JIRA.
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/#api-rest-api-2-issueLinkType-get
func (s *IssueLinkTypeService) GetList() ([]IssueLinkType, *Response, error) {
func (s *IssueLinkTypeService) GetListWithContext(ctx context.Context) ([]IssueLinkType, *Response, error) {
apiEndpoint := "rest/api/2/issueLinkType"
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -31,12 +32,17 @@ func (s *IssueLinkTypeService) GetList() ([]IssueLinkType, *Response, error) {
return linkTypeList, resp, nil
}
// Get gets info of a specific issue link type from JIRA.
// GetList wraps GetListWithContext using the background context.
func (s *IssueLinkTypeService) GetList() ([]IssueLinkType, *Response, error) {
return s.GetListWithContext(context.Background())
}
// GetWithContext gets info of a specific issue link type from JIRA.
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/#api-rest-api-2-issueLinkType-issueLinkTypeId-get
func (s *IssueLinkTypeService) Get(ID string) (*IssueLinkType, *Response, error) {
func (s *IssueLinkTypeService) GetWithContext(ctx context.Context, ID string) (*IssueLinkType, *Response, error) {
apiEndPoint := fmt.Sprintf("rest/api/2/issueLinkType/%s", ID)
req, err := s.client.NewRequest("GET", apiEndPoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndPoint, nil)
if err != nil {
return nil, nil, err
}
@ -49,12 +55,17 @@ func (s *IssueLinkTypeService) Get(ID string) (*IssueLinkType, *Response, error)
return linkType, resp, nil
}
// Create creates an issue link type in JIRA.
// Get wraps GetWithContext using the background context.
func (s *IssueLinkTypeService) Get(ID string) (*IssueLinkType, *Response, error) {
return s.GetWithContext(context.Background(), ID)
}
// CreateWithContext creates an issue link type in JIRA.
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/#api-rest-api-2-issueLinkType-post
func (s *IssueLinkTypeService) Create(linkType *IssueLinkType) (*IssueLinkType, *Response, error) {
func (s *IssueLinkTypeService) CreateWithContext(ctx context.Context, linkType *IssueLinkType) (*IssueLinkType, *Response, error) {
apiEndpoint := "/rest/api/2/issueLinkType"
req, err := s.client.NewRequest("POST", apiEndpoint, linkType)
req, err := s.client.NewRequestWithContext(ctx, "POST", apiEndpoint, linkType)
if err != nil {
return nil, nil, err
}
@ -79,12 +90,17 @@ func (s *IssueLinkTypeService) Create(linkType *IssueLinkType) (*IssueLinkType,
return linkType, resp, nil
}
// Update updates an issue link type. The issue is found by key.
// Create wraps CreateWithContext using the background context.
func (s *IssueLinkTypeService) Create(linkType *IssueLinkType) (*IssueLinkType, *Response, error) {
return s.CreateWithContext(context.Background(), linkType)
}
// UpdateWithContext updates an issue link type. The issue is found by key.
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/#api-rest-api-2-issueLinkType-issueLinkTypeId-put
func (s *IssueLinkTypeService) Update(linkType *IssueLinkType) (*IssueLinkType, *Response, error) {
func (s *IssueLinkTypeService) UpdateWithContext(ctx context.Context, linkType *IssueLinkType) (*IssueLinkType, *Response, error) {
apiEndpoint := fmt.Sprintf("rest/api/2/issueLinkType/%s", linkType.ID)
req, err := s.client.NewRequest("PUT", apiEndpoint, linkType)
req, err := s.client.NewRequestWithContext(ctx, "PUT", apiEndpoint, linkType)
if err != nil {
return nil, nil, err
}
@ -96,12 +112,17 @@ func (s *IssueLinkTypeService) Update(linkType *IssueLinkType) (*IssueLinkType,
return &ret, resp, nil
}
// Delete deletes an issue link type based on provided ID.
// Update wraps UpdateWithContext using the background context.
func (s *IssueLinkTypeService) Update(linkType *IssueLinkType) (*IssueLinkType, *Response, error) {
return s.UpdateWithContext(context.Background(), linkType)
}
// DeleteWithContext deletes an issue link type based on provided ID.
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/#api-rest-api-2-issueLinkType-issueLinkTypeId-delete
func (s *IssueLinkTypeService) Delete(ID string) (*Response, error) {
func (s *IssueLinkTypeService) DeleteWithContext(ctx context.Context, ID string) (*Response, error) {
apiEndpoint := fmt.Sprintf("rest/api/2/issueLinkType/%s", ID)
req, err := s.client.NewRequest("DELETE", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "DELETE", apiEndpoint, nil)
if err != nil {
return nil, err
}
@ -109,3 +130,8 @@ func (s *IssueLinkTypeService) Delete(ID string) (*Response, error) {
resp, err := s.client.Do(req, nil)
return resp, err
}
// Delete wraps DeleteWithContext using the background context.
func (s *IssueLinkTypeService) Delete(ID string) (*Response, error) {
return s.DeleteWithContext(context.Background(), ID)
}

34
jira.go
View File

@ -2,6 +2,7 @@ package jira
import (
"bytes"
"context"
"crypto/sha256"
"encoding/hex"
"encoding/json"
@ -105,10 +106,10 @@ func NewClient(httpClient httpClient, baseURL string) (*Client, error) {
return c, nil
}
// NewRawRequest creates an API request.
// NewRawRequestWithContext creates an API request.
// A relative URL can be provided in urlStr, in which case it is resolved relative to the baseURL of the Client.
// Allows using an optional native io.Reader for sourcing the request body.
func (c *Client) NewRawRequest(method, urlStr string, body io.Reader) (*http.Request, error) {
func (c *Client) NewRawRequestWithContext(ctx context.Context, method, urlStr string, body io.Reader) (*http.Request, error) {
rel, err := url.Parse(urlStr)
if err != nil {
return nil, err
@ -118,7 +119,7 @@ func (c *Client) NewRawRequest(method, urlStr string, body io.Reader) (*http.Req
u := c.baseURL.ResolveReference(rel)
req, err := http.NewRequest(method, u.String(), body)
req, err := newRequestWithContext(ctx, method, u.String(), body)
if err != nil {
return nil, err
}
@ -143,10 +144,15 @@ func (c *Client) NewRawRequest(method, urlStr string, body io.Reader) (*http.Req
return req, nil
}
// NewRequest creates an API request.
// NewRawRequest wraps NewRawRequestWithContext using the background context.
func (c *Client) NewRawRequest(method, urlStr string, body io.Reader) (*http.Request, error) {
return c.NewRawRequestWithContext(context.Background(), method, urlStr, body)
}
// NewRequestWithContext creates an API request.
// A relative URL can be provided in urlStr, in which case it is resolved relative to the baseURL of the Client.
// If specified, the value pointed to by body is JSON encoded and included as the request body.
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) {
func (c *Client) NewRequestWithContext(ctx context.Context, method, urlStr string, body interface{}) (*http.Request, error) {
rel, err := url.Parse(urlStr)
if err != nil {
return nil, err
@ -165,7 +171,7 @@ func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Requ
}
}
req, err := http.NewRequest(method, u.String(), buf)
req, err := newRequestWithContext(ctx, method, u.String(), buf)
if err != nil {
return nil, err
}
@ -190,6 +196,11 @@ func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Requ
return req, nil
}
// NewRequest wraps NewRequestWithContext using the background context.
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) {
return c.NewRequestWithContext(context.Background(), method, urlStr, body)
}
// addOptions adds the parameters in opt as URL query parameters to s. opt
// must be a struct whose fields may contain "url" tags.
func addOptions(s string, opt interface{}) (string, error) {
@ -212,10 +223,10 @@ func addOptions(s string, opt interface{}) (string, error) {
return u.String(), nil
}
// NewMultiPartRequest creates an API request including a multi-part file.
// NewMultiPartRequestWithContext creates an API request including a multi-part file.
// A relative URL can be provided in urlStr, in which case it is resolved relative to the baseURL of the Client.
// If specified, the value pointed to by buf is a multipart form.
func (c *Client) NewMultiPartRequest(method, urlStr string, buf *bytes.Buffer) (*http.Request, error) {
func (c *Client) NewMultiPartRequestWithContext(ctx context.Context, method, urlStr string, buf *bytes.Buffer) (*http.Request, error) {
rel, err := url.Parse(urlStr)
if err != nil {
return nil, err
@ -225,7 +236,7 @@ func (c *Client) NewMultiPartRequest(method, urlStr string, buf *bytes.Buffer) (
u := c.baseURL.ResolveReference(rel)
req, err := http.NewRequest(method, u.String(), buf)
req, err := newRequestWithContext(ctx, method, u.String(), buf)
if err != nil {
return nil, err
}
@ -251,6 +262,11 @@ func (c *Client) NewMultiPartRequest(method, urlStr string, buf *bytes.Buffer) (
return req, nil
}
// NewMultiPartRequest wraps NewMultiPartRequestWithContext using the background context.
func (c *Client) NewMultiPartRequest(method, urlStr string, buf *bytes.Buffer) (*http.Request, error) {
return c.NewMultiPartRequestWithContext(context.Background(), method, urlStr, buf)
}
// Do sends an API request and returns the API response.
// The API response is JSON decoded and stored in the value pointed to by v, or returned as an error if an API error has occurred.
func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {

View File

@ -1,6 +1,7 @@
package jira
import (
"context"
"fmt"
"strings"
@ -47,16 +48,21 @@ type MetaIssueType struct {
Fields tcontainer.MarshalMap `json:"fields,omitempty"`
}
// GetCreateMeta makes the api call to get the meta information required to create a ticket
func (s *IssueService) GetCreateMeta(projectkeys string) (*CreateMetaInfo, *Response, error) {
return s.GetCreateMetaWithOptions(&GetQueryOptions{ProjectKeys: projectkeys, Expand: "projects.issuetypes.fields"})
// GetCreateMetaWithContext makes the api call to get the meta information required to create a ticket
func (s *IssueService) GetCreateMetaWithContext(ctx context.Context, projectkeys string) (*CreateMetaInfo, *Response, error) {
return s.GetCreateMetaWithOptionsWithContext(ctx, &GetQueryOptions{ProjectKeys: projectkeys, Expand: "projects.issuetypes.fields"})
}
// GetCreateMetaWithOptions makes the api call to get the meta information without requiring to have a projectKey
func (s *IssueService) GetCreateMetaWithOptions(options *GetQueryOptions) (*CreateMetaInfo, *Response, error) {
// GetCreateMeta wraps GetCreateMetaWithContext using the background context.
func (s *IssueService) GetCreateMeta(projectkeys string) (*CreateMetaInfo, *Response, error) {
return s.GetCreateMetaWithContext(context.Background(), projectkeys)
}
// GetCreateMetaWithOptionsWithContext makes the api call to get the meta information without requiring to have a projectKey
func (s *IssueService) GetCreateMetaWithOptionsWithContext(ctx context.Context, options *GetQueryOptions) (*CreateMetaInfo, *Response, error) {
apiEndpoint := "rest/api/2/issue/createmeta"
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -78,11 +84,16 @@ func (s *IssueService) GetCreateMetaWithOptions(options *GetQueryOptions) (*Crea
return meta, resp, nil
}
// GetEditMeta makes the api call to get the edit meta information for an issue
func (s *IssueService) GetEditMeta(issue *Issue) (*EditMetaInfo, *Response, error) {
// GetCreateMetaWithOptions wraps GetCreateMetaWithOptionsWithContext using the background context.
func (s *IssueService) GetCreateMetaWithOptions(options *GetQueryOptions) (*CreateMetaInfo, *Response, error) {
return s.GetCreateMetaWithOptionsWithContext(context.Background(), options)
}
// GetEditMetaWithContext makes the api call to get the edit meta information for an issue
func (s *IssueService) GetEditMetaWithContext(ctx context.Context, issue *Issue) (*EditMetaInfo, *Response, error) {
apiEndpoint := fmt.Sprintf("/rest/api/2/issue/%s/editmeta", issue.Key)
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -97,6 +108,11 @@ func (s *IssueService) GetEditMeta(issue *Issue) (*EditMetaInfo, *Response, erro
return meta, resp, nil
}
// GetEditMeta wraps GetEditMetaWithContext using the background context.
func (s *IssueService) GetEditMeta(issue *Issue) (*EditMetaInfo, *Response, error) {
return s.GetEditMetaWithContext(context.Background(), issue)
}
// GetProjectWithName returns a project with "name" from the meta information received. If not found, this returns nil.
// The comparison of the name is case insensitive.
func (m *CreateMetaInfo) GetProjectWithName(name string) *MetaProject {

View File

@ -1,6 +1,9 @@
package jira
import "fmt"
import (
"context"
"fmt"
)
// PermissionSchemeService handles permissionschemes for the JIRA instance / API.
//
@ -25,12 +28,12 @@ type Holder struct {
Expand string `json:"expand" structs:"expand"`
}
// GetList returns a list of all permission schemes
// GetListWithContext returns a list of all permission schemes
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v3/#api-api-3-permissionscheme-get
func (s *PermissionSchemeService) GetList() (*PermissionSchemes, *Response, error) {
func (s *PermissionSchemeService) GetListWithContext(ctx context.Context) (*PermissionSchemes, *Response, error) {
apiEndpoint := "/rest/api/3/permissionscheme"
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -45,12 +48,17 @@ func (s *PermissionSchemeService) GetList() (*PermissionSchemes, *Response, erro
return pss, resp, nil
}
// Get returns a full representation of the permission scheme for the schemeID
// GetList wraps GetListWithContext using the background context.
func (s *PermissionSchemeService) GetList() (*PermissionSchemes, *Response, error) {
return s.GetListWithContext(context.Background())
}
// GetWithContext returns a full representation of the permission scheme for the schemeID
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v3/#api-api-3-permissionscheme-schemeId-get
func (s *PermissionSchemeService) Get(schemeID int) (*PermissionScheme, *Response, error) {
func (s *PermissionSchemeService) GetWithContext(ctx context.Context, schemeID int) (*PermissionScheme, *Response, error) {
apiEndpoint := fmt.Sprintf("/rest/api/3/permissionscheme/%d", schemeID)
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -67,3 +75,8 @@ func (s *PermissionSchemeService) Get(schemeID int) (*PermissionScheme, *Respons
return ps, resp, nil
}
// Get wraps GetWithContext using the background context.
func (s *PermissionSchemeService) Get(schemeID int) (*PermissionScheme, *Response, error) {
return s.GetWithContext(context.Background(), schemeID)
}

View File

@ -1,5 +1,7 @@
package jira
import "context"
// PriorityService handles priorities for the JIRA instance / API.
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-Priority
@ -18,12 +20,12 @@ type Priority struct {
Description string `json:"description,omitempty" structs:"description,omitempty"`
}
// GetList gets all priorities from JIRA
// GetListWithContext gets all priorities from JIRA
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-api-2-priority-get
func (s *PriorityService) GetList() ([]Priority, *Response, error) {
func (s *PriorityService) GetListWithContext(ctx context.Context) ([]Priority, *Response, error) {
apiEndpoint := "rest/api/2/priority"
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -35,3 +37,8 @@ func (s *PriorityService) GetList() ([]Priority, *Response, error) {
}
return priorityList, resp, nil
}
// GetList wraps GetListWithContext using the background context.
func (s *PriorityService) GetList() ([]Priority, *Response, error) {
return s.GetListWithContext(context.Background())
}

View File

@ -1,6 +1,7 @@
package jira
import (
"context"
"fmt"
"github.com/google/go-querystring/query"
@ -80,20 +81,25 @@ type PermissionScheme struct {
Permissions []Permission `json:"permissions" structs:"permissions,omitempty"`
}
// GetList gets all projects form JIRA
// GetListWithContext gets all projects form JIRA
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/project-getAllProjects
func (s *ProjectService) GetList() (*ProjectList, *Response, error) {
return s.ListWithOptions(&GetQueryOptions{})
func (s *ProjectService) GetListWithContext(ctx context.Context) (*ProjectList, *Response, error) {
return s.ListWithOptionsWithContext(ctx, &GetQueryOptions{})
}
// ListWithOptions gets all projects form JIRA with optional query params, like &GetQueryOptions{Expand: "issueTypes"} to get
// GetList wraps GetListWithContext using the background context.
func (s *ProjectService) GetList() (*ProjectList, *Response, error) {
return s.GetListWithContext(context.Background())
}
// ListWithOptionsWithContext gets all projects form JIRA with optional query params, like &GetQueryOptions{Expand: "issueTypes"} to get
// a list of all projects and their supported issuetypes
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/project-getAllProjects
func (s *ProjectService) ListWithOptions(options *GetQueryOptions) (*ProjectList, *Response, error) {
func (s *ProjectService) ListWithOptionsWithContext(ctx context.Context, options *GetQueryOptions) (*ProjectList, *Response, error) {
apiEndpoint := "rest/api/2/project"
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -116,14 +122,19 @@ func (s *ProjectService) ListWithOptions(options *GetQueryOptions) (*ProjectList
return projectList, resp, nil
}
// Get returns a full representation of the project for the given issue key.
// ListWithOptions wraps ListWithOptionsWithContext using the background context.
func (s *ProjectService) ListWithOptions(options *GetQueryOptions) (*ProjectList, *Response, error) {
return s.ListWithOptionsWithContext(context.Background(), options)
}
// GetWithContext returns a full representation of the project for the given issue key.
// JIRA will attempt to identify the project by the projectIdOrKey path parameter.
// This can be an project id, or an project key.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/project-getProject
func (s *ProjectService) Get(projectID string) (*Project, *Response, error) {
func (s *ProjectService) GetWithContext(ctx context.Context, projectID string) (*Project, *Response, error) {
apiEndpoint := fmt.Sprintf("rest/api/2/project/%s", projectID)
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -138,14 +149,19 @@ func (s *ProjectService) Get(projectID string) (*Project, *Response, error) {
return project, resp, nil
}
// GetPermissionScheme returns a full representation of the permission scheme for the project
// Get wraps GetWithContext using the background context.
func (s *ProjectService) Get(projectID string) (*Project, *Response, error) {
return s.GetWithContext(context.Background(), projectID)
}
// GetPermissionSchemeWithContext returns a full representation of the permission scheme for the project
// JIRA will attempt to identify the project by the projectIdOrKey path parameter.
// This can be an project id, or an project key.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/project-getProject
func (s *ProjectService) GetPermissionScheme(projectID string) (*PermissionScheme, *Response, error) {
func (s *ProjectService) GetPermissionSchemeWithContext(ctx context.Context, projectID string) (*PermissionScheme, *Response, error) {
apiEndpoint := fmt.Sprintf("/rest/api/2/project/%s/permissionscheme", projectID)
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -159,3 +175,8 @@ func (s *ProjectService) GetPermissionScheme(projectID string) (*PermissionSchem
return ps, resp, nil
}
// GetPermissionScheme wraps GetPermissionSchemeWithContext using the background context.
func (s *ProjectService) GetPermissionScheme(projectID string) (*PermissionScheme, *Response, error) {
return s.GetPermissionSchemeWithContext(context.Background(), projectID)
}

23
request_context.go Normal file
View File

@ -0,0 +1,23 @@
// +build go1.13
// This file provides glue to use Context in `http.Request` with
// Go version 1.13 and higher.
// The function `http.NewRequestWithContext` has been added in Go 1.13.
// Before the release 1.13, to use Context we need creat `http.Request`
// then use the method `WithContext` to create a new `http.Request`
// with Context from the existing `http.Request`.
//
// Doc: https://golang.org/doc/go1.13#net/http
package jira
import (
"context"
"io"
"net/http"
)
func newRequestWithContext(ctx context.Context, method, url string, body io.Reader) (*http.Request, error) {
return http.NewRequestWithContext(ctx, method, url, body)
}

28
request_legacy.go Normal file
View File

@ -0,0 +1,28 @@
// +build !go1.13
// This file provides glue to use Context in `http.Request` with
// Go version before 1.13.
// The function `http.NewRequestWithContext` has been added in Go 1.13.
// Before the release 1.13, to use Context we need creat `http.Request`
// then use the method `WithContext` to create a new `http.Request`
// with Context from the existing `http.Request`.
//
// Doc: https://golang.org/doc/go1.13#net/http
package jira
import (
"context"
"io"
"net/http"
)
func newRequestWithContext(ctx context.Context, method, url string, body io.Reader) (*http.Request, error) {
r, err := http.NewRequest(method, url, body)
if err != nil {
return nil, err
}
return r.WithContext(ctx), nil
}

View File

@ -1,5 +1,7 @@
package jira
import "context"
// ResolutionService handles resolutions for the JIRA instance / API.
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-Resolution
@ -16,12 +18,12 @@ type Resolution struct {
Name string `json:"name" structs:"name"`
}
// GetList gets all resolutions from JIRA
// GetListWithContext gets all resolutions from JIRA
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-api-2-resolution-get
func (s *ResolutionService) GetList() ([]Resolution, *Response, error) {
func (s *ResolutionService) GetListWithContext(ctx context.Context) ([]Resolution, *Response, error) {
apiEndpoint := "rest/api/2/resolution"
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -33,3 +35,8 @@ func (s *ResolutionService) GetList() ([]Resolution, *Response, error) {
}
return resolutionList, resp, nil
}
// GetList wraps GetListWithContext using the background context.
func (s *ResolutionService) GetList() ([]Resolution, *Response, error) {
return s.GetListWithContext(context.Background())
}

23
role.go
View File

@ -1,6 +1,7 @@
package jira
import (
"context"
"fmt"
)
@ -35,12 +36,12 @@ type ActorUser struct {
AccountID string `json:"accountId" structs:"accountId"`
}
// GetList returns a list of all available project roles
// GetListWithContext returns a list of all available project roles
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v3/#api-api-3-role-get
func (s *RoleService) GetList() (*[]Role, *Response, error) {
func (s *RoleService) GetListWithContext(ctx context.Context) (*[]Role, *Response, error) {
apiEndpoint := "rest/api/3/role"
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -53,12 +54,17 @@ func (s *RoleService) GetList() (*[]Role, *Response, error) {
return roles, resp, err
}
// Get retreives a single Role from Jira
// GetList wraps GetListWithContext using the background context.
func (s *RoleService) GetList() (*[]Role, *Response, error) {
return s.GetListWithContext(context.Background())
}
// GetWithContext retreives a single Role from Jira
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v3/#api-api-3-role-id-get
func (s *RoleService) Get(roleID int) (*Role, *Response, error) {
func (s *RoleService) GetWithContext(ctx context.Context, roleID int) (*Role, *Response, error) {
apiEndpoint := fmt.Sprintf("rest/api/3/role/%d", roleID)
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -74,3 +80,8 @@ func (s *RoleService) Get(roleID int) (*Role, *Response, error) {
return role, resp, err
}
// Get wraps GetWithContext using the background context.
func (s *RoleService) Get(roleID int) (*Role, *Response, error) {
return s.GetWithContext(context.Background(), roleID)
}

View File

@ -1,6 +1,7 @@
package jira
import (
"context"
"fmt"
"github.com/google/go-querystring/query"
@ -22,17 +23,17 @@ type IssuesInSprintResult struct {
Issues []Issue `json:"issues"`
}
// MoveIssuesToSprint moves issues to a sprint, for a given sprint Id.
// MoveIssuesToSprintWithContext moves issues to a sprint, for a given sprint Id.
// Issues can only be moved to open or active sprints.
// The maximum number of issues that can be moved in one operation is 50.
//
// JIRA API docs: https://docs.atlassian.com/jira-software/REST/cloud/#agile/1.0/sprint-moveIssuesToSprint
func (s *SprintService) MoveIssuesToSprint(sprintID int, issueIDs []string) (*Response, error) {
func (s *SprintService) MoveIssuesToSprintWithContext(ctx context.Context, sprintID int, issueIDs []string) (*Response, error) {
apiEndpoint := fmt.Sprintf("rest/agile/1.0/sprint/%d/issue", sprintID)
payload := IssuesWrapper{Issues: issueIDs}
req, err := s.client.NewRequest("POST", apiEndpoint, payload)
req, err := s.client.NewRequestWithContext(ctx, "POST", apiEndpoint, payload)
if err != nil {
return nil, err
@ -45,15 +46,20 @@ func (s *SprintService) MoveIssuesToSprint(sprintID int, issueIDs []string) (*Re
return resp, err
}
// GetIssuesForSprint returns all issues in a sprint, for a given sprint Id.
// MoveIssuesToSprint wraps MoveIssuesToSprintWithContext using the background context.
func (s *SprintService) MoveIssuesToSprint(sprintID int, issueIDs []string) (*Response, error) {
return s.MoveIssuesToSprintWithContext(context.Background(), sprintID, issueIDs)
}
// GetIssuesForSprintWithContext 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.
//
// JIRA API Docs: https://docs.atlassian.com/jira-software/REST/cloud/#agile/1.0/sprint-getIssuesForSprint
func (s *SprintService) GetIssuesForSprint(sprintID int) ([]Issue, *Response, error) {
func (s *SprintService) GetIssuesForSprintWithContext(ctx context.Context, sprintID int) ([]Issue, *Response, error) {
apiEndpoint := fmt.Sprintf("rest/agile/1.0/sprint/%d/issue", sprintID)
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
@ -68,7 +74,12 @@ func (s *SprintService) GetIssuesForSprint(sprintID int) ([]Issue, *Response, er
return result.Issues, resp, err
}
// GetIssue returns a full representation of the issue for the given issue key.
// GetIssuesForSprint wraps GetIssuesForSprintWithContext using the background context.
func (s *SprintService) GetIssuesForSprint(sprintID int) ([]Issue, *Response, error) {
return s.GetIssuesForSprintWithContext(context.Background(), sprintID)
}
// GetIssueWithContext returns a full representation of the issue for the given issue key.
// JIRA will attempt to identify the issue by the issueIdOrKey path parameter.
// This can be an issue id, or an issue key.
// If the issue cannot be found via an exact match, JIRA will also look for the issue in a case-insensitive way, or by looking to see if the issue was moved.
@ -78,10 +89,10 @@ func (s *SprintService) GetIssuesForSprint(sprintID int) ([]Issue, *Response, er
// JIRA API docs: https://docs.atlassian.com/jira-software/REST/7.3.1/#agile/1.0/issue-getIssue
//
// TODO: create agile service for holding all agile apis' implementation
func (s *SprintService) GetIssue(issueID string, options *GetQueryOptions) (*Issue, *Response, error) {
func (s *SprintService) GetIssueWithContext(ctx context.Context, issueID string, options *GetQueryOptions) (*Issue, *Response, error) {
apiEndpoint := fmt.Sprintf("rest/agile/1.0/issue/%s", issueID)
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
@ -105,3 +116,8 @@ func (s *SprintService) GetIssue(issueID string, options *GetQueryOptions) (*Iss
return issue, resp, nil
}
// GetIssue wraps GetIssueWithContext using the background context.
func (s *SprintService) GetIssue(issueID string, options *GetQueryOptions) (*Issue, *Response, error) {
return s.GetIssueWithContext(context.Background(), issueID, options)
}

View File

@ -1,5 +1,7 @@
package jira
import "context"
// StatusService handles staties for the JIRA instance / API.
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/#api-group-Workflow-statuses
@ -19,12 +21,12 @@ type Status struct {
StatusCategory StatusCategory `json:"statusCategory" structs:"statusCategory"`
}
// GetAllStatuses returns a list of all statuses associated with workflows.
// GetAllStatusesWithContext returns a list of all statuses associated with workflows.
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/#api-rest-api-2-status-get
func (s *StatusService) GetAllStatuses() ([]Status, *Response, error) {
func (s *StatusService) GetAllStatusesWithContext(ctx context.Context) ([]Status, *Response, error) {
apiEndpoint := "rest/api/2/status"
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
@ -38,3 +40,8 @@ func (s *StatusService) GetAllStatuses() ([]Status, *Response, error) {
return statusList, resp, nil
}
// GetAllStatuses wraps GetAllStatusesWithContext using the background context.
func (s *StatusService) GetAllStatuses() ([]Status, *Response, error) {
return s.GetAllStatusesWithContext(context.Background())
}

View File

@ -1,5 +1,7 @@
package jira
import "context"
// StatusCategoryService handles status categories for the JIRA instance / API.
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-Statuscategory
@ -25,12 +27,12 @@ const (
StatusCategoryUndefined = "undefined"
)
// GetList gets all status categories from JIRA
// GetListWithContext gets all status categories from JIRA
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-api-2-statuscategory-get
func (s *StatusCategoryService) GetList() ([]StatusCategory, *Response, error) {
func (s *StatusCategoryService) GetListWithContext(ctx context.Context) ([]StatusCategory, *Response, error) {
apiEndpoint := "rest/api/2/statuscategory"
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx,"GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -42,3 +44,8 @@ func (s *StatusCategoryService) GetList() ([]StatusCategory, *Response, error) {
}
return statusCategoryList, resp, nil
}
// GetList wraps GetListWithContext using the background context.
func (s *StatusCategoryService) GetList() ([]StatusCategory, *Response, error) {
return s.GetListWithContext(context.Background())
}

78
user.go
View File

@ -1,6 +1,7 @@
package jira
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
@ -47,16 +48,16 @@ type userSearch []userSearchParam
type userSearchF func(userSearch) userSearch
// Get gets user info from JIRA
// GetWithContext gets user info from JIRA
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/cloud/#api/2/user-getUser
//
// /!\ Deprecation notice: https://developer.atlassian.com/cloud/jira/platform/deprecation-notice-user-privacy-api-migration-guide/
// By 29 April 2019, we will remove personal data from the API that is used to identify users,
// such as username and userKey, and instead use the Atlassian account ID (accountId).
func (s *UserService) Get(username string) (*User, *Response, error) {
func (s *UserService) GetWithContext(ctx context.Context, username string) (*User, *Response, error) {
apiEndpoint := fmt.Sprintf("/rest/api/2/user?username=%s", username)
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -69,12 +70,17 @@ func (s *UserService) Get(username string) (*User, *Response, error) {
return user, resp, nil
}
// Get gets user info from JIRA
// Get wraps GetWithContext using the background context.
func (s *UserService) Get(username string) (*User, *Response, error) {
return s.GetWithContext(context.Background(), username)
}
// GetByAccountIDWithContext gets user info from JIRA
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/cloud/#api/2/user-getUser
func (s *UserService) GetByAccountID(accountID string) (*User, *Response, error) {
func (s *UserService) GetByAccountIDWithContext(ctx context.Context, accountID string) (*User, *Response, error) {
apiEndpoint := fmt.Sprintf("/rest/api/2/user?accountId=%s", accountID)
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -87,12 +93,17 @@ func (s *UserService) GetByAccountID(accountID string) (*User, *Response, error)
return user, resp, nil
}
// Create creates an user in JIRA.
// GetByAccountID wraps GetByAccountIDWithContext using the background context.
func (s *UserService) GetByAccountID(accountID string) (*User, *Response, error) {
return s.GetByAccountIDWithContext(context.Background(), accountID)
}
// CreateWithContext creates an user in JIRA.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/cloud/#api/2/user-createUser
func (s *UserService) Create(user *User) (*User, *Response, error) {
func (s *UserService) CreateWithContext(ctx context.Context, user *User) (*User, *Response, error) {
apiEndpoint := "/rest/api/2/user"
req, err := s.client.NewRequest("POST", apiEndpoint, user)
req, err := s.client.NewRequestWithContext(ctx, "POST", apiEndpoint, user)
if err != nil {
return nil, nil, err
}
@ -117,13 +128,18 @@ func (s *UserService) Create(user *User) (*User, *Response, error) {
return responseUser, resp, nil
}
// Delete deletes an user from JIRA.
// Create wraps CreateWithContext using the background context.
func (s *UserService) Create(user *User) (*User, *Response, error) {
return s.CreateWithContext(context.Background(), user)
}
// DeleteWithContext deletes an user from JIRA.
// Returns http.StatusNoContent on success.
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-api-2-user-delete
func (s *UserService) Delete(username string) (*Response, error) {
func (s *UserService) DeleteWithContext(ctx context.Context, username string) (*Response, error) {
apiEndpoint := fmt.Sprintf("/rest/api/2/user?username=%s", username)
req, err := s.client.NewRequest("DELETE", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "DELETE", apiEndpoint, nil)
if err != nil {
return nil, err
}
@ -135,12 +151,17 @@ func (s *UserService) Delete(username string) (*Response, error) {
return resp, nil
}
// GetGroups returns the groups which the user belongs to
// Delete wraps DeleteWithContext using the background context.
func (s *UserService) Delete(username string) (*Response, error) {
return s.DeleteWithContext(context.Background(), username)
}
// GetGroupsWithContext returns the groups which the user belongs to
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/cloud/#api/2/user-getUserGroups
func (s *UserService) GetGroups(username string) (*[]UserGroup, *Response, error) {
func (s *UserService) GetGroupsWithContext(ctx context.Context, username string) (*[]UserGroup, *Response, error) {
apiEndpoint := fmt.Sprintf("/rest/api/2/user/groups?username=%s", username)
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -153,12 +174,17 @@ func (s *UserService) GetGroups(username string) (*[]UserGroup, *Response, error
return userGroups, resp, nil
}
// Get information about the current logged-in user
// GetGroups wraps GetGroupsWithContext using the background context.
func (s *UserService) GetGroups(username string) (*[]UserGroup, *Response, error) {
return s.GetGroupsWithContext(context.Background(), username)
}
// GetSelfWithContext information about the current logged-in user
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-api-2-myself-get
func (s *UserService) GetSelf() (*User, *Response, error) {
func (s *UserService) GetSelfWithContext(ctx context.Context) (*User, *Response, error) {
const apiEndpoint = "rest/api/2/myself"
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -170,6 +196,11 @@ func (s *UserService) GetSelf() (*User, *Response, error) {
return &user, resp, nil
}
// GetSelf wraps GetSelfWithContext using the background context.
func (s *UserService) GetSelf() (*User, *Response, error) {
return s.GetSelfWithContext(context.Background())
}
// WithMaxResults sets the max results to return
func WithMaxResults(maxResults int) userSearchF {
return func(s userSearch) userSearch {
@ -202,11 +233,11 @@ func WithInactive(inactive bool) userSearchF {
}
}
// Find searches for user info from JIRA:
// FindWithContext searches for user info from JIRA:
// It can find users by email, username or name
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/cloud/#api/2/user-findUsers
func (s *UserService) Find(property string, tweaks ...userSearchF) ([]User, *Response, error) {
func (s *UserService) FindWithContext(ctx context.Context, property string, tweaks ...userSearchF) ([]User, *Response, error) {
search := []userSearchParam{
{
name: "username",
@ -223,7 +254,7 @@ func (s *UserService) Find(property string, tweaks ...userSearchF) ([]User, *Res
}
apiEndpoint := fmt.Sprintf("/rest/api/2/user/search?%s", queryString[:len(queryString)-1])
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -235,3 +266,8 @@ func (s *UserService) Find(property string, tweaks ...userSearchF) ([]User, *Res
}
return users, resp, nil
}
// Find wraps FindWithContext using the background context.
func (s *UserService) Find(property string, tweaks ...userSearchF) ([]User, *Response, error) {
return s.FindWithContext(context.Background(), property, tweaks...)
}

View File

@ -1,6 +1,7 @@
package jira
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
@ -27,12 +28,12 @@ type Version struct {
StartDate string `json:"startDate,omitempty" structs:"startDate,omitempty"`
}
// Get gets version info from JIRA
// GetWithContext gets version info from JIRA
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-api-2-version-id-get
func (s *VersionService) Get(versionID int) (*Version, *Response, error) {
func (s *VersionService) GetWithContext(ctx context.Context, versionID int) (*Version, *Response, error) {
apiEndpoint := fmt.Sprintf("/rest/api/2/version/%v", versionID)
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
@ -45,12 +46,17 @@ func (s *VersionService) Get(versionID int) (*Version, *Response, error) {
return version, resp, nil
}
// Create creates a version in JIRA.
// Get wraps GetWithContext using the background context.
func (s *VersionService) Get(versionID int) (*Version, *Response, error) {
return s.GetWithContext(context.Background(), versionID)
}
// CreateWithContext creates a version in JIRA.
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-api-2-version-post
func (s *VersionService) Create(version *Version) (*Version, *Response, error) {
func (s *VersionService) CreateWithContext(ctx context.Context, version *Version) (*Version, *Response, error) {
apiEndpoint := "/rest/api/2/version"
req, err := s.client.NewRequest("POST", apiEndpoint, version)
req, err := s.client.NewRequestWithContext(ctx, "POST", apiEndpoint, version)
if err != nil {
return nil, nil, err
}
@ -75,12 +81,17 @@ func (s *VersionService) Create(version *Version) (*Version, *Response, error) {
return responseVersion, resp, nil
}
// Update updates a version from a JSON representation.
// Create wraps CreateWithContext using the background context.
func (s *VersionService) Create(version *Version) (*Version, *Response, error) {
return s.CreateWithContext(context.Background(), version)
}
// UpdateWithContext updates a version from a JSON representation.
//
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-api-2-version-id-put
func (s *VersionService) Update(version *Version) (*Version, *Response, error) {
func (s *VersionService) UpdateWithContext(ctx context.Context, version *Version) (*Version, *Response, error) {
apiEndpoint := fmt.Sprintf("rest/api/2/version/%v", version.ID)
req, err := s.client.NewRequest("PUT", apiEndpoint, version)
req, err := s.client.NewRequestWithContext(ctx, "PUT", apiEndpoint, version)
if err != nil {
return nil, nil, err
}
@ -95,3 +106,8 @@ func (s *VersionService) Update(version *Version) (*Version, *Response, error) {
ret := *version
return &ret, resp, nil
}
// Update wraps UpdateWithContext using the background context.
func (s *VersionService) Update(version *Version) (*Version, *Response, error) {
return s.UpdateWithContext(context.Background(), version)
}