Repository: ctreminiom/go-atlassian
Pull request #31 (2021-04-30 03:49:50)

Dev


Patch:
diff --git a/jira/examples/issue-fields-configurations/assign/assign.go b/jira/examples/issue-fields-configurations/assign/assign.go
new file mode 100644
index 0000000..c17ed46
--- /dev/null
+++ b/jira/examples/issue-fields-configurations/assign/assign.go
@@ -0,0 +1,35 @@
+package main
+
+import (
+	"context"
+	"github.com/ctreminiom/go-atlassian/jira"
+	"log"
+	"os"
+)
+
+func main() {
+
+	var (
+		host  = os.Getenv("HOST")
+		mail  = os.Getenv("MAIL")
+		token = os.Getenv("TOKEN")
+	)
+
+	atlassian, err := jira.New(nil, host)
+	if err != nil {
+		return
+	}
+
+	atlassian.Auth.SetBasicAuth(mail, token)
+
+	response, err := atlassian.Issue.Field.Configuration.Assign(context.Background(), "10001", "10001")
+	if err != nil {
+		if response != nil {
+			log.Println("Response HTTP Response", string(response.BodyAsBytes))
+		}
+		return
+	}
+
+	log.Println("Response HTTP Code", response.StatusCode)
+	log.Println("HTTP Endpoint Used", response.Endpoint)
+}
diff --git a/jira/examples/issue/edit/edit.go b/jira/examples/issue/edit/edit.go
index f97bffe..52f6589 100644
--- a/jira/examples/issue/edit/edit.go
+++ b/jira/examples/issue/edit/edit.go
@@ -24,7 +24,7 @@ func main() {
 
 	var payload = jira.IssueScheme{
 		Fields: &jira.IssueFieldsScheme{
-			Summary: "New summary test test",
+			//		Summary: "New summary test test",
 		},
 	}
 
diff --git a/jira/examples/issue/get/get.go b/jira/examples/issue/get/get.go
index e9bd467..684453e 100644
--- a/jira/examples/issue/get/get.go
+++ b/jira/examples/issue/get/get.go
@@ -22,7 +22,7 @@ func main() {
 
 	atlassian.Auth.SetBasicAuth(mail, token)
 
-	issue, response, err := atlassian.Issue.Get(context.Background(), "KP-12", nil, []string{"transitions"})
+	issue, response, err := atlassian.Issue.Get(context.Background(), "KP-2", nil, []string{"transitions"})
 	if err != nil {
 		if response != nil {
 			log.Println("Response HTTP Response", string(response.BodyAsBytes))
@@ -41,4 +41,12 @@ func main() {
 		log.Println(transition.Name, transition.ID, transition.To.ID, transition.HasScreen)
 	}
 
+	// Check if the issue contains sub-tasks
+	if issue.Fields.Subtasks != nil {
+
+		for _, subTask := range *issue.Fields.Subtasks {
+			log.Println("Sub-Task: ", subTask.Key, subTask.Fields.Summary)
+		}
+
+	}
 }
diff --git a/jira/examples/issue/move/main.go b/jira/examples/issue/move/main.go
index 4e6a7e1..632f1e9 100644
--- a/jira/examples/issue/move/main.go
+++ b/jira/examples/issue/move/main.go
@@ -22,7 +22,40 @@ func main() {
 
 	atlassian.Auth.SetBasicAuth(mail, token)
 
-	response, err := atlassian.Issue.Move(context.Background(), "KP-2", "11")
+	var payload = &jira.IssueScheme{
+		Fields: &jira.IssueFieldsScheme{
+			Summary: "New summary test test",
+		},
+	}
+
+	//CustomFields
+	var customFields = &jira.CustomFields{}
+	err = customFields.Groups("customfield_10052", []string{"jira-administrators", "jira-administrators-system"})
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	//Issue Update Operations
+	var operations = &jira.UpdateOperations{}
+
+	err = operations.AddArrayOperation("labels", map[string]string{
+		"triaged":   "add",
+		"triaged-2": "add",
+		"triaged-1": "add",
+		"blocker":   "add",
+	})
+
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	options := &jira.IssueMoveOptions{
+		Fields:       payload,
+		Operations:   operations,
+		CustomFields: customFields,
+	}
+
+	response, err := atlassian.Issue.Move(context.Background(), "KP-7", "41", options)
 	if err != nil {
 		if response != nil {
 			log.Println("Response HTTP Response", string(response.BodyAsBytes))
diff --git a/jira/filterShare.go b/jira/filterShare.go
index cbe1bcc..ef83cdd 100644
--- a/jira/filterShare.go
+++ b/jira/filterShare.go
@@ -68,6 +68,9 @@ func (f *FilterShareService) SetScope(ctx context.Context, scope string) (respon
 		return
 	}
 
+	request.Header.Set("Accept", "application/json")
+	request.Header.Set("Content-Type", "application/json")
+
 	response, err = f.client.Do(request)
 	if err != nil {
 		return
diff --git a/jira/issue.go b/jira/issue.go
index 24fe796..16a9362 100644
--- a/jira/issue.go
+++ b/jira/issue.go
@@ -46,11 +46,19 @@ type IssueFieldsScheme struct {
 	Components               *[]ProjectComponentScheme `json:"components,omitempty"`
 	Creator                  *UserScheme               `json:"creator,omitempty"`
 	Reporter                 *UserScheme               `json:"reporter,omitempty"`
-	Statuscategorychangedate string                    `json:"statuscategorychangedate,omitempty"`
+	Resolution               *IssueResolutionScheme    `json:"resolution,omitempty"`
+	Resolutiondate           string                    `json:"resolutiondate,omitempty"`
+	Workratio                int                       `json:"workratio,omitempty"`
+	StatuscategoryChangeDate string                    `json:"statuscategorychangedate,omitempty"`
 	LastViewed               string                    `json:"lastViewed,omitempty"`
 	Summary                  string                    `json:"summary,omitempty"`
 	Created                  string                    `json:"created,omitempty"`
+	Updated                  string                    `json:"updated,omitempty"`
 	Labels                   []string                  `json:"labels,omitempty"`
+	Status                   *StatusScheme             `json:"status,omitempty"`
+	Description              *CommentNodeScheme        `json:"description,omitempty"`
+	Comments                 []*IssueCommentPageScheme `json:"comments,omitempty"`
+	Subtasks                 *[]IssueScheme            `json:"subtasks,omitempty"`
 }
 
 func (i *IssueScheme) MergeCustomFields(fields *CustomFields) (result map[string]interface{}, err error) {
@@ -966,9 +974,15 @@ func (i *IssueService) Transitions(ctx context.Context, issueKeyOrID string) (re
 	return
 }
 
+type IssueMoveOptions struct {
+	Fields       *IssueScheme
+	CustomFields *CustomFields
+	Operations   *UpdateOperations
+}
+
 // Performs an issue transition and
 // Docs: https://docs.go-atlassian.io/jira-software-cloud/issues#transition-issue
-func (i *IssueService) Move(ctx context.Context, issueKeyOrID, transitionID string) (response *Response, err error) {
+func (i *IssueService) Move(ctx context.Context, issueKeyOrID, transitionID string, options *IssueMoveOptions) (response *Response, err error) {
 
 	if len(issueKeyOrID) == 0 {
 		return nil, fmt.Errorf("error, please provide a valid issueKeyOrID string value")
@@ -978,21 +992,76 @@ func (i *IssueService) Move(ctx context.Context, issueKeyOrID, transitionID stri
 		return nil, fmt.Errorf("error, please provide a valid transitionID string value")
 	}
 
-	payload := struct {
-		Transition struct {
-			ID string `json:"id"`
-		} `json:"transition"`
-	}{
-		Transition: struct {
-			ID string `json:"id"`
-		}{ID: transitionID},
-	}
+	payloadWithTransition := make(map[string]interface{})
+	payloadWithTransition["transition"] = map[string]interface{}{"id": transitionID}
 
-	var endpoint = fmt.Sprintf("rest/api/3/issue/%v/transitions", issueKeyOrID)
+	var (
+		endpoint = fmt.Sprintf("rest/api/3/issue/%v/transitions", issueKeyOrID)
+		request  *http.Request
+	)
 
-	request, err := i.client.newRequest(ctx, http.MethodPost, endpoint, &payload)
-	if err != nil {
-		return
+	if options != nil && options.Fields != nil {
+
+		// Executed when customfields and operation are provided
+		if options.CustomFields != nil && options.Operations != nil {
+
+			payloadWithCustomFields, err := options.Fields.MergeCustomFields(options.CustomFields)
+			if err != nil {
+				return nil, err
+			}
+
+			payloadWithOperations, err := options.Fields.MergeOperations(options.Operations)
+			if err != nil {
+				return nil, err
+			}
+
+			//Merge the map[string]interface{} into one
+			_ = mergo.Map(&payloadWithCustomFields, &payloadWithOperations, mergo.WithOverride)
+			_ = mergo.Map(&payloadWithCustomFields, &payloadWithTransition, mergo.WithOverride)
+
+			request, err = i.client.newRequest(ctx, http.MethodPost, endpoint, payloadWithCustomFields)
+			if err != nil {
+				return nil, err
+			}
+
+		}
+
+		// Executed when customfields are provided but not the operations
+		if options.CustomFields != nil && options.Operations == nil {
+
+			payloadWithCustomFields, err := options.Fields.MergeCustomFields(options.CustomFields)
+			if err != nil {
+				return nil, err
+			}
+
+			_ = mergo.Map(&payloadWithCustomFields, &payloadWithTransition, mergo.WithOverride)
+			request, err = i.client.newRequest(ctx, http.MethodPost, endpoint, payloadWithCustomFields)
+			if err != nil {
+				return nil, err
+			}
+
+		}
+
+		// Executed when operations are provided but not the customfields
+		if options.CustomFields == nil && options.Operations != nil {
+
+			payloadWithOperations, err := options.Fields.MergeOperations(options.Operations)
+			if err != nil {
+				return nil, err
+			}
+
+			_ = mergo.Map(&payloadWithOperations, &payloadWithTransition, mergo.WithOverride)
+			request, err = i.client.newRequest(ctx, http.MethodPost, endpoint, payloadWithOperations)
+			if err != nil {
+				return nil, err
+			}
+		}
+
+	} else {
+		request, err = i.client.newRequest(ctx, http.MethodPost, endpoint, &payloadWithTransition)
+		if err != nil {
+			return
+		}
 	}
 
 	request.Header.Set("Accept", "application/json")
diff --git a/jira/issueComment.go b/jira/issueComment.go
index bcf3218..e5b06de 100644
--- a/jira/issueComment.go
+++ b/jira/issueComment.go
@@ -19,32 +19,16 @@ type IssueCommentPageScheme struct {
 }
 
 type IssueCommentScheme struct {
-	Self         string      `json:"self,omitempty"`
-	ID           string      `json:"id,omitempty"`
-	Author       *UserScheme `json:"author,omitempty"`
-	RenderedBody string      `json:"renderedBody,omitempty"`
-	Body         struct {
-		Version int    `json:"version,omitempty"`
-		Type    string `json:"type,omitempty"`
-		Content []struct {
-			Type    string `json:"type,omitempty"`
-			Content []struct {
-				Type string `json:"type,omitempty"`
-				Text string `json:"text,omitempty"`
-			} `json:"content,omitempty"`
-		} `json:"content,omitempty"`
-	} `json:"body,omitempty"`
-	JSDPublic    bool        `json:"jsdPublic,omitempty"`
-	UpdateAuthor *UserScheme `json:"updateAuthor,omitempty"`
-	Created      string      `json:"created,omitempty"`
-	Updated      string      `json:"updated,omitempty"`
-	Visibility   struct {
-		Type  string `json:"type,omitempty"`
-		Value string `json:"value,omitempty"`
-	} `json:"visibility,omitempty"`
-	Properties []struct {
-		Key string `json:"key,omitempty"`
-	} `json:"properties,omitempty"`
+	Self         string                   `json:"self,omitempty"`
+	ID           string                   `json:"id,omitempty"`
+	Author       *UserScheme              `json:"author,omitempty"`
+	RenderedBody string                   `json:"renderedBody,omitempty"`
+	Body         *CommentNodeScheme       `json:"body,omitempty"`
+	JSDPublic    bool                     `json:"jsdPublic,omitempty"`
+	UpdateAuthor *UserScheme              `json:"updateAuthor,omitempty"`
+	Created      string                   `json:"created,omitempty"`
+	Updated      string                   `json:"updated,omitempty"`
+	Visibility   *CommentVisibilityScheme `json:"visibility,omitempty"`
 }
 
 // Returns all comments for an issue.
diff --git a/jira/issueFieldConfiguration.go b/jira/issueFieldConfiguration.go
index afeb3ef..0ce16fb 100644
--- a/jira/issueFieldConfiguration.go
+++ b/jira/issueFieldConfiguration.go
@@ -26,7 +26,7 @@ type FieldConfigScheme struct {
 	IsDefault   bool   `json:"isDefault,omitempty"`
 }
 
-// Returns a paginated list of all field configurations.
+// Gets Returns a paginated list of all field configurations.
 // Docs: https://docs.go-atlassian.io/jira-software-cloud/issues/fields/configuration#get-all-field-configurations
 func (f *FieldConfigurationService) Gets(ctx context.Context, IDs []int, isDefault bool, startAt, maxResults int) (result *FieldConfigSearchScheme, response *Response, err error) {
 
@@ -77,7 +77,7 @@ type FieldConfigurationItemScheme struct {
 	Description string `json:"description,omitempty"`
 }
 
-// Returns a paginated list of all fields for a configuration.
+// Items Returns a paginated list of all fields for a configuration.
 // Docs: https://docs.go-atlassian.io/jira-software-cloud/issues/fields/configuration#get-field-configuration-items
 func (f *FieldConfigurationService) Items(ctx context.Context, fieldConfigurationID, startAt, maxResults int) (result *FieldConfigurationItemPageScheme, response *Response, err error) {
 
@@ -120,7 +120,7 @@ type FieldConfigurationSchemeScheme struct {
 	Description string `json:"description,omitempty"`
 }
 
-// Returns a paginated list of field configuration schemes.
+// Schemes Returns a paginated list of field configuration schemes.
 // Docs: https://docs.go-atlassian.io/jira-software-cloud/issues/fields/configuration#get-all-field-configuration-schemes
 func (f *FieldConfigurationService) Schemes(ctx context.Context, IDs []int, startAt, maxResults int) (result *FieldConfigurationSchemePageScheme, response *Response, err error) {
 
@@ -167,7 +167,7 @@ type FieldConfigurationIssueTypeItemScheme struct {
 	FieldConfigurationID       string `json:"fieldConfigurationId,omitempty"`
 }
 
-// Returns a paginated list of field configuration issue type items.
+// IssueTypeItems Returns a paginated list of field configuration issue type items.
 // Docs: https://docs.go-atlassian.io/jira-software-cloud/issues/fields/configuration#get-field-configuration-issue-type-items
 func (f *FieldConfigurationService) IssueTypeItems(ctx context.Context, fieldConfigIDs []int, startAt, maxResults int) (result *FieldConfigurationIssueTypeItemPageScheme, response *Response, err error) {
 
@@ -212,7 +212,7 @@ type FieldConfigurationSchemeProjectScheme struct {
 	FieldConfigurationScheme *FieldConfigurationSchemeScheme `json:"fieldConfigurationScheme,omitempty"`
 }
 
-// Returns a paginated list of field configuration schemes and, for each scheme, a list of the projects that use it.
+// SchemesByProject Returns a paginated list of field configuration schemes and, for each scheme, a list of the projects that use it.
 // Docs: https://docs.go-atlassian.io/jira-software-cloud/issues/fields/configuration#get-field-configuration-schemes-for-projects
 func (f *FieldConfigurationService) SchemesByProject(ctx context.Context, projectIDs []int, startAt, maxResults int) (result *FieldConfigurationSchemeProjectPageScheme, response *Response, err error) {
 
@@ -243,3 +243,37 @@ func (f *FieldConfigurationService) SchemesByProject(ctx context.Context, projec
 
 	return
 }
+
+// Assign Assigns a field configuration scheme to a project.
+// If the field configuration scheme ID is null, the operation assigns the default field configuration scheme.
+// Docs: N/A
+func (f *FieldConfigurationService) Assign(ctx context.Context, fieldConfigurationSchemeID, projectID string) (response *Response, err error) {
+
+	if len(projectID) == 0 {
+		return nil, fmt.Errorf("error!, please provide a vaild projectID value")
+	}
+
+	payload := struct {
+		SchemeID  string `json:"fieldConfigurationSchemeId,omitempty"`
+		ProjectID string `json:"projectId,omitempty"`
+	}{
+		SchemeID:  fieldConfigurationSchemeID,
+		ProjectID: projectID,
+	}
+
+	var endpoint = "rest/api/3/fieldconfigurationscheme/project"
+	request, err := f.client.newRequest(ctx, http.MethodPut, endpoint, &payload)
+	if err != nil {
+		return
+	}
+
+	request.Header.Set("Accept", "application/json")
+	request.Header.Set("Content-Type", "application/json")
+
+	response, err = f.client.Do(request)
+	if err != nil {
+		return
+	}
+
+	return
+}
diff --git a/jira/issueSearch.go b/jira/issueSearch.go
index c96f7ff..5b7e4cb 100644
--- a/jira/issueSearch.go
+++ b/jira/issueSearch.go
@@ -27,18 +27,18 @@ type IssueTransitionsScheme struct {
 }
 
 type IssueTransitionScheme struct {
-	ID            string              `json:"id,omitempty"`
-	Name          string              `json:"name,omitempty"`
-	To            *TransitionToScheme `json:"to,omitempty"`
-	HasScreen     bool                `json:"hasScreen,omitempty"`
-	IsGlobal      bool                `json:"isGlobal,omitempty"`
-	IsInitial     bool                `json:"isInitial,omitempty"`
-	IsAvailable   bool                `json:"isAvailable,omitempty"`
-	IsConditional bool                `json:"isConditional,omitempty"`
-	IsLooped      bool                `json:"isLooped,omitempty"`
+	ID            string        `json:"id,omitempty"`
+	Name          string        `json:"name,omitempty"`
+	To            *StatusScheme `json:"to,omitempty"`
+	HasScreen     bool          `json:"hasScreen,omitempty"`
+	IsGlobal      bool          `json:"isGlobal,omitempty"`
+	IsInitial     bool          `json:"isInitial,omitempty"`
+	IsAvailable   bool          `json:"isAvailable,omitempty"`
+	IsConditional bool          `json:"isConditional,omitempty"`
+	IsLooped      bool          `json:"isLooped,omitempty"`
 }
 
-type TransitionToScheme struct {
+type StatusScheme struct {
 	Self           string                `json:"self,omitempty"`
 	Description    string                `json:"description,omitempty"`
 	IconURL        string                `json:"iconUrl,omitempty"`
diff --git a/jira/mocks/get-issue.json b/jira/mocks/get-issue.json
index 905265c..f30f42c 100644
--- a/jira/mocks/get-issue.json
+++ b/jira/mocks/get-issue.json
@@ -226,7 +226,6 @@
         "issueId": "10002"
       }
     ],
-    "updated": 1,
     "timetracking": {
       "originalEstimate": "10m",
       "remainingEstimate": "3m",
diff --git a/jira/mocks/search-issues.json b/jira/mocks/search-issues.json
index 241cd05..c7a87c8 100644
--- a/jira/mocks/search-issues.json
+++ b/jira/mocks/search-issues.json
@@ -233,7 +233,6 @@
             "issueId": "10002"
           }
         ],
-        "updated": 1,
         "timetracking": {
           "originalEstimate": "10m",
           "remainingEstimate": "3m",


Test patch:
diff --git a/jira/issueFieldConfiguration_test.go b/jira/issueFieldConfiguration_test.go
index abec89b..84c630c 100644
--- a/jira/issueFieldConfiguration_test.go
+++ b/jira/issueFieldConfiguration_test.go
@@ -1005,3 +1005,140 @@ func TestFieldConfigurationService_SchemesByProject(t *testing.T) {
 	}
 
 }
+
+func TestFieldConfigurationService_Assign(t *testing.T) {
+
+	testCases := []struct {
+		name                       string
+		fieldConfigurationSchemeID string
+		projectID                  string
+		mockFile                   string
+		wantHTTPMethod             string
+		endpoint                   string
+		context                    context.Context
+		wantHTTPCodeReturn         int
+		wantErr                    bool
+	}{
+		{
+			name:                       "AssignFieldConfigurationToProjectWhenTheParametersAreCorrect",
+			fieldConfigurationSchemeID: "1000",
+			projectID:                  "1001",
+			wantHTTPMethod:             http.MethodPut,
+			endpoint:                   "/rest/api/3/fieldconfigurationscheme/project",
+			context:                    context.Background(),
+			wantHTTPCodeReturn:         http.StatusNoContent,
+			wantErr:                    false,
+		},
+
+		{
+			name:                       "AssignFieldConfigurationToProjectWhenTheProjectIDIsNotProvided",
+			fieldConfigurationSchemeID: "1000",
+			projectID:                  "",
+			wantHTTPMethod:             http.MethodPut,
+			endpoint:                   "/rest/api/3/fieldconfigurationscheme/project",
+			context:                    context.Background(),
+			wantHTTPCodeReturn:         http.StatusNoContent,
+			wantErr:                    true,
+		},
+
+		{
+			name:                       "AssignFieldConfigurationToProjectWhenTheRequestMethodIsIncorrect",
+			fieldConfigurationSchemeID: "1000",
+			projectID:                  "1001",
+			wantHTTPMethod:             http.MethodHead,
+			endpoint:                   "/rest/api/3/fieldconfigurationscheme/project",
+			context:                    context.Background(),
+			wantHTTPCodeReturn:         http.StatusNoContent,
+			wantErr:                    true,
+		},
+
+		{
+			name:                       "AssignFieldConfigurationToProjectWhenTheStatusCodeIsIncorrect",
+			fieldConfigurationSchemeID: "1000",
+			projectID:                  "1001",
+			wantHTTPMethod:             http.MethodPut,
+			endpoint:                   "/rest/api/3/fieldconfigurationscheme/project",
+			context:                    context.Background(),
+			wantHTTPCodeReturn:         http.StatusBadRequest,
+			wantErr:                    true,
+		},
+
+		{
+			name:                       "AssignFieldConfigurationToProjectWhenTheContextIsNil",
+			fieldConfigurationSchemeID: "1000",
+			projectID:                  "1001",
+			wantHTTPMethod:             http.MethodPut,
+			endpoint:                   "/rest/api/3/fieldconfigurationscheme/project",
+			context:                    nil,
+			wantHTTPCodeReturn:         http.StatusNoContent,
+			wantErr:                    true,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			//Init a new HTTP mock server
+			mockOptions := mockServerOptions{
+				Endpoint:           testCase.endpoint,
+				MockFilePath:       testCase.mockFile,
+				MethodAccepted:     testCase.wantHTTPMethod,
+				ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+			}
+
+			mockServer, err := startMockServer(&mockOptions)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			defer mockServer.Close()
+
+			//Init the library instance
+			mockClient, err := startMockClient(mockServer.URL)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			service := &FieldConfigurationService{client: mockClient}
+			gotResponse, err := service.Assign(testCase.context, testCase.fieldConfigurationSchemeID, testCase.projectID)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.Error(t, err)
+
+				if gotResponse != nil {
+					t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.StatusCode)
+				}
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+
+				apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+				if err != nil {
+					t.Fatal(err)
+				}
+
+				var endpointToAssert string
+
+				if apiEndpoint.Query().Encode() != "" {
+					endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+				} else {
+					endpointToAssert = apiEndpoint.Path
+				}
+
+				t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+				assert.Equal(t, testCase.endpoint, endpointToAssert)
+
+				t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.StatusCode)
+				assert.Equal(t, gotResponse.StatusCode, testCase.wantHTTPCodeReturn)
+			}
+
+		})
+	}
+
+}
diff --git a/jira/issue_test.go b/jira/issue_test.go
index 167637b..276e303 100644
--- a/jira/issue_test.go
+++ b/jira/issue_test.go
@@ -2006,10 +2006,47 @@ func TestIssueService_Get(t *testing.T) {
 
 func TestIssueService_Move(t *testing.T) {
 
+	var payload = &IssueScheme{
+		Fields: &IssueFieldsScheme{
+			Summary: "New summary test test",
+		},
+	}
+
+	var customFieldMockedWithFields = CustomFields{}
+
+	// Add a new custom field
+	err := customFieldMockedWithFields.Groups("customfield_10052", []string{"jira-administrators", "jira-administrators-system"})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = customFieldMockedWithFields.Number("customfield_10043", 1000.3232)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var customFieldMockedWithOutFields = CustomFields{}
+
+	var operationMockedWithFields = UpdateOperations{}
+
+	err = operationMockedWithFields.AddArrayOperation("labels", map[string]string{
+		"triaged":   "remove",
+		"triaged-2": "remove",
+		"triaged-1": "remove",
+		"blocker":   "remove",
+	})
+
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	operationMockedWithOutFields := UpdateOperations{}
+
 	testCases := []struct {
 		name               string
 		issueKeyOrID       string
 		transitionID       string
+		options            *IssueMoveOptions
 		mockFile           string
 		wantHTTPMethod     string
 		endpoint           string
@@ -2018,16 +2055,165 @@ func TestIssueService_Move(t *testing.T) {
 		wantErr            bool
 	}{
 		{
-			name:               "MoveIssueStatusWhenTheIssueKeyOrIDIsSet",
-			issueKeyOrID:       "DUMMY-3",
-			transitionID:       "10001",
-			wantHTTPMethod:     http.MethodPost,
+			name:           "MoveIssueStatusWhenTheTheCustomFieldsIsProvidedButNotOperations",
+			issueKeyOrID:   "DUMMY-3",
+			transitionID:   "10001",
+			wantHTTPMethod: http.MethodPost,
+			options: &IssueMoveOptions{
+				Fields:       payload,
+				CustomFields: &customFieldMockedWithFields,
+				Operations:   nil,
+			},
+			endpoint:           "/rest/api/3/issue/DUMMY-3/transitions",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            false,
+		},
+
+		{
+			name:           "MoveIssueStatusWhenTheTheOperationsIsProvidedButNotCustomFields",
+			issueKeyOrID:   "DUMMY-3",
+			transitionID:   "10001",
+			wantHTTPMethod: http.MethodPost,
+			options: &IssueMoveOptions{
+				Fields:       payload,
+				CustomFields: nil,
+				Operations:   &operationMockedWithFields,
+			},
+			endpoint:           "/rest/api/3/issue/DUMMY-3/transitions",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            false,
+		},
+
+		{
+			name:           "MoveIssueStatusWhenTheTheOperationsIsProvidedButNotCustomFieldsAndContext",
+			issueKeyOrID:   "DUMMY-3",
+			transitionID:   "10001",
+			wantHTTPMethod: http.MethodPost,
+			options: &IssueMoveOptions{
+				Fields:       payload,
+				CustomFields: nil,
+				Operations:   &operationMockedWithFields,
+			},
+			endpoint:           "/rest/api/3/issue/DUMMY-3/transitions",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+		},
+
+		{
+			name:           "MoveIssueStatusWhenTheTheOperationsIsProvidedButNotCustomFieldsAndNotFieldsOperations",
+			issueKeyOrID:   "DUMMY-3",
+			transitionID:   "10001",
+			wantHTTPMethod: http.MethodPost,
+			options: &IssueMoveOptions{
+				Fields:       payload,
+				CustomFields: nil,
+				Operations:   &operationMockedWithOutFields,
+			},
+			endpoint:           "/rest/api/3/issue/DUMMY-3/transitions",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+		},
+
+		{
+			name:           "MoveIssueStatusWhenTheTheCustomFieldsIsProvidedButNotOperationsAndContext",
+			issueKeyOrID:   "DUMMY-3",
+			transitionID:   "10001",
+			wantHTTPMethod: http.MethodPost,
+			options: &IssueMoveOptions{
+				Fields:       payload,
+				CustomFields: &customFieldMockedWithFields,
+				Operations:   nil,
+			},
+			endpoint:           "/rest/api/3/issue/DUMMY-3/transitions",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+		},
+
+		{
+			name:           "MoveIssueStatusWhenTheTheCustomFieldsIsProvidedButWithNotFields",
+			issueKeyOrID:   "DUMMY-3",
+			transitionID:   "10001",
+			wantHTTPMethod: http.MethodPost,
+			options: &IssueMoveOptions{
+				Fields:       payload,
+				CustomFields: &customFieldMockedWithOutFields,
+				Operations:   nil,
+			},
+			endpoint:           "/rest/api/3/issue/DUMMY-3/transitions",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+		},
+
+		{
+			name:           "MoveIssueStatusWhenTheTheCustomFieldsAndOperationAreProvided",
+			issueKeyOrID:   "DUMMY-3",
+			transitionID:   "10001",
+			wantHTTPMethod: http.MethodPost,
+			options: &IssueMoveOptions{
+				Fields:       payload,
+				CustomFields: &customFieldMockedWithFields,
+				Operations:   &operationMockedWithFields,
+			},
 			endpoint:           "/rest/api/3/issue/DUMMY-3/transitions",
 			context:            context.Background(),
 			wantHTTPCodeReturn: http.StatusNoContent,
 			wantErr:            false,
 		},
 
+		{
+			name:           "MoveIssueStatusWhenTheTheCustomFieldsAndOperationAreProvidedButNotContext",
+			issueKeyOrID:   "DUMMY-3",
+			transitionID:   "10001",
+			wantHTTPMethod: http.MethodPost,
+			options: &IssueMoveOptions{
+				Fields:       payload,
+				CustomFields: &customFieldMockedWithFields,
+				Operations:   &operationMockedWithFields,
+			},
+			endpoint:           "/rest/api/3/issue/DUMMY-3/transitions",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+		},
+
+		{
+			name:           "MoveIssueStatusWhenTheTheOperationAreProvidedButNotTheCustomFields",
+			issueKeyOrID:   "DUMMY-3",
+			transitionID:   "10001",
+			wantHTTPMethod: http.MethodPost,
+			options: &IssueMoveOptions{
+				Fields:       payload,
+				CustomFields: &customFieldMockedWithOutFields,
+				Operations:   &operationMockedWithFields,
+			},
+			endpoint:           "/rest/api/3/issue/DUMMY-3/transitions",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+		},
+
+		{
+			name:           "MoveIssueStatusWhenTheTheCustomFieldsAreProvidedButNotTheOperations",
+			issueKeyOrID:   "DUMMY-3",
+			transitionID:   "10001",
+			wantHTTPMethod: http.MethodPost,
+			options: &IssueMoveOptions{
+				Fields:       payload,
+				CustomFields: &customFieldMockedWithFields,
+				Operations:   &operationMockedWithOutFields,
+			},
+			endpoint:           "/rest/api/3/issue/DUMMY-3/transitions",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+		},
+
 		{
 			name:               "MoveIssueStatusWhenTheIssueKeyOrIDIsNotSet",
 			issueKeyOrID:       "",
@@ -2122,7 +2308,7 @@ func TestIssueService_Move(t *testing.T) {
 
 			i := &IssueService{client: mockClient}
 
-			gotResponse, err := i.Move(testCase.context, testCase.issueKeyOrID, testCase.transitionID)
+			gotResponse, err := i.Move(testCase.context, testCase.issueKeyOrID, testCase.transitionID, testCase.options)
 
 			if testCase.wantErr {